WPF:在执行操作之前等待故事板动画完成的正确方法是什么

bla*_*pea 8 wpf wpf-controls

我有一个故事板,我重复使用动画一些图片,我想在每个动画后执行一些操作,包括一些计算,然后运行另一个动画,所以我相信我应该使用StoryBoard的完成事件 MyStoryboard.Completed += storyboard_Com?pleted;

我很好奇的是,我应该在当前的StoryBoard中开始下一个动画Storyboard_Completed Event吗?并且,如果我使用Application.Current.Dispatcher对象在单独的线程中启动第一个动画,是否有任何影响?

如果我使用Application.Current.Dispatcher在一个单独的线程中调用了StoryBoard.Begin(),那么在UI线程中是否也会调用Storyboard_Completed事件?在这种情况下,我是否仍需要将Next Animation包装在另一个Dispatcher Invoke中?

private void Story_Completed(object sender, EventArgs e)
{
    Application.Current.Dispatcher.Invoke((Action)delegate()
    {
       SomeNewStoryBoardAnimation.Begin();
    }
}
Run Code Online (Sandbox Code Playgroud)

它是否正确?或者是否有更好的方法来检查故事板是否已经结束并在此之后开始下一组计算和故事板动画?

我曾想过使用一个后台工作程序按顺序处理所有动画和计算,但我也想知道如何在开始下一组计算和动画之前"等待"动画完成.Thread.sleep在等待动画完成时BackGroundWorker是否正常?

BTo*_*TKD 7

您可以将Storyboard包装在Task对象中并等待其完成.

以下是Morten Nielsen 博客文章中的一些示例代码,说明了如何做到这一点:

public static class StoryboardExtensions
{
    public static Task BeginAsync(this Storyboard storyboard)
    {
        System.Threading.Tasks.TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
        if (storyboard == null)
            tcs.SetException(new ArgumentNullException());
        else
        {
            EventHandler<object> onComplete = null;
            onComplete = (s, e) => {
                storyboard.Completed -= onComplete; 
                tcs.SetResult(true); 
            };
            storyboard.Completed += onComplete;
            storyboard.Begin();
        }
        return tcs.Task;
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上你正在创建一个扩展方法,它返回一个Task对象,表示Storyboard的完成.通过这种方式,你得到一些不错的流畅语法,如下所示:

//Start the storyboard and asynchronously await completion...
await myStoryboard.BeginAsync();

//Do my other stuff here, after the storyboard completes...
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的解决方案,但是使用`CurrentStateInvalidated`事件可能更合适,因为如果`Storyboard`将被停止,则不会引发`Completed`.您可以将当前时钟状态与`ClockState.Stopped`和`ClockState.Filling`进行比较. (3认同)