【问题标题】:Storyboard animation happening AFTER all the code is read. Need it to happen BEFORE故事板动画在读取所有代码后发生。需要它发生之前
【发布时间】:2014-11-22 19:02:38
【问题描述】:

我愿意学习 WPF 和 C#,并且我认为学习编程语言的最佳方式是想一个对我有意义的小项目,然后根据需要学习语言特性。

现在,我在设置屏幕上有一个按钮,它正在调用辅助类 HarpaEngine 中的一些方法,执行一些 IO 密集型工作,所以为了给用户一些反馈,我放了一个 <Path> 对象在我单击按钮时应该开始旋转的屏幕上,当 IO 工作完成后,它应该消失。这是我单击按钮时执行的代码:

private void btnSaveSettings_Click(object sender, RoutedEventArgs e)
{

    // I created the Storyboard programmatically, don't think that's relevant               
    // It works though

    DoubleAnimation refreshAnimation = new DoubleAnimation();
    refreshAnimation.Duration = TimeSpan.FromSeconds(3);
    refreshAnimation.From = 0.0;
    refreshAnimation.To = 360.0;
    refreshAnimation.RepeatBehavior = RepeatBehavior.Forever;

    Storyboard storyboard = new Storyboard ();
    storyboard.Children.Add(refreshAnimation);
    Storyboard.SetTargetName(refreshAnimation, "RefreshAngle");
    Storyboard.SetTargetProperty(refreshAnimation, new PropertyPath(RotateTransform.AngleProperty));

    //(...) Some work gets done here (...)

    RefreshIcon.Visibility = System.Windows.Visibility.Visible;
    storyboard.Begin(this);

    //HarpaEngine is my helper class
    HarpaEngine.MP3Files.Clear();

    Task deassign = Task.Run(() => HarpaEngine.DeassignMP3toHymns());
    deassign.Wait();

    Task populateMP3 = Task.Run(() => HarpaEngine.PopulateMP3Files());
    populateMP3.Wait();

    Task assign = Task.Run(() => HarpaEngine.AssignMP3toHymns());
    assign.Wait();

    Task serialize = Task.Run(() => HarpaEngine.SerializeMP3());
    serialize.Wait();

    storyboard.Stop();
    RefreshIcon.Visibility = System.Windows.Visibility.Hidden;

使用此代码,对象永远不可见。我认为物体变得可见然后不可见,速度如此之快,以至于肉眼看不到。当我删除最后 2 行以使对象永远不可见时,它会开始动画处理 AFTER 所有行。通过使用断点,我发现整个过程大约需要 10 秒才能完成,因此如果对象在处理 Task.Run 行之前变得可见,它将完美地工作。我尝试使用asyncawait 而不是Task.Run,但这不是这里的解决方案,或者我错误地实现了它。我在 MSDN 上阅读了一些关于 Background Workers 的文章,但他们建议 Task.Run 性能更高。

关于我的程序的一些背景背景:

它有一个嵌入的 .txt 资源文件,它可以读取我们在教堂里唱的大约 640 首歌曲的所有歌词,然后在MainWindow 的列表中显示歌曲列表。它还读取一个属性设置,该设置指定存储与这些歌曲相关的所有 MP3 文件的文件夹。 “设置”窗口允许用户更改该文件夹的路径,并且此代码中的按钮调用扫描新文件夹以查找 .mp3 文件的方法,然后填充 List<MP3file>,以便在显示歌词列表时,它也为文件夹中对应的 .mp3 文件的每首歌曲显示一个小播放按钮。

有人能指出我正确的方向吗?我猜<Path> 仅在读完整个代码后才会显示,因为 UIThread 被阻塞了。这是一种普通的必需品,但我看到的大多数关于 Threads 和 async 的示例都处理更复杂的场景,这些场景对我的问题来说太过分了,并且建议的实现涉及我不知道如何使用的高级 C# 功能.

非常感谢所有帮助!

PS:请不要以为我知道如何实施您的建议。

【问题讨论】:

    标签: c# wpf task


    【解决方案1】:

    它似乎直到工作完成后才开始的原因是因为您正在对您的任务调用 Wait()。这会导致线程阻塞,直到它们完成 - 不幸的是,该线程是您的 UI 线程,它也负责旋转轮子。这意味着您正在启动动画,立即阻塞 UI 线程(导致您的 UI 挂起),然后在您完成所有工作后立即释放它。

    假设您只有 1 个长期运行的任务可以满足,而不是 3 个。一种解决方案是将长时间运行的方法转换为返回任务的方法,然后附加一个 ContinueWith 回调

    public Task DoSomethingAsync()
    {
        return Task.Factory.StartNew(
            () => HarpaEngine.DeassignMP3toHymns()
        );
    }
    
    public void StopAnimation()
    {
        //stop storyboard
    }
    

    然后,在您的按钮单击中

    Task doingWork = DoSomethingAsync();
    doingWork.ContineWith(OnWorkCompleted);
    

    【讨论】:

    • 太棒了@Andrew!不知道这个 ContinueWith 方法!非常感谢!!!
    猜你喜欢
    • 1970-01-01
    • 2020-08-20
    • 2011-10-16
    • 2011-09-03
    • 2014-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-29
    相关资源
    最近更新 更多