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

时间:2013-02-04 16:25:05

标签: wpf wpf-controls

我有一个故事板,我重复使用它来动画一些图片,我想在每个动画后执行一些操作,包括一些计算,然后运行另一个动画,所以我相信我应该使用StoryBoard的已完成事件{{1} }

我很好奇的是,我应该在当前的StoryBoard MyStoryboard.Completed += storyboard_Com​pleted;中开始下一个动画吗?而且,如果我使用Application.Current.Dispatcher对象在单独的线程中启动第一个动画,是否有任何影响?

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

Storyboard_Completed Event

这是对的吗?或者是否有更好的方法来检查故事板是否已经结束并开始下一组计算&故事板动画就在那之后?

我曾想过使用一个后台工作程序按顺序处理所有动画和计算,但我也想知道如何在开始下一组计算和动画之前“等待”动画完成。 BackGroundWorker在等待动画完成时有private void Story_Completed(object sender, EventArgs e) { Application.Current.Dispatcher.Invoke((Action)delegate() { SomeNewStoryBoardAnimation.Begin(); } } 这是正常的吗?

2 个答案:

答案 0 :(得分:7)

您可以将故事板包装在Task对象中并await完成。

这是一段很好的示例代码,说明了如何做到这一点,取自Morten Nielsen的blog post

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;
    }
}

基本上,您正在创建一个扩展方法,该方法返回一个Task对象,表示Storyboard已完成。通过这种方式,您可以得到一些不错的流畅语法:

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

//Do my other stuff here, after the storyboard completes...

答案 1 :(得分:1)

使用Storyboard.Completed事件应该适用于您的目的。 Storyboard.Completed事件处理程序应在UI线程上触发,因此您不需要调用Application.Current.Dispatcher.Invoke来触发第二个Storyboard。

如果使用Application.Current.Dispatcher.Invoke调用原始Storyboard.Begin,则不会产生任何影响。这不会在新线程上启动故事板动画。它将在主UI线程上异步调用动画。无论您是自己在UI线程上调用Begin还是使用Application.Current.Dispatcher.Invoke来执行此操作,最终结果都应该相同。故事板完成后,您已完成的事件处理程序将触发,您可以执行计算并触发下一个故事板。

有关故事板在过去被用作计时器的一些讨论,请参阅以下问题,因为它在UI线程上运行:

What is the point of using Storyboard as timer?

此外,对于您描述的特定情况,这可能有点过分,但如果您需要编排一系列顺序异步操作,则可以使用Reactive Extensions:

http://msdn.microsoft.com/en-us/data/gg577609.aspx

以下文章包含一个连续的故事板示例(尽管该文章已经足够大,语法可能已更改):

http://www.wintellect.com/cs/blogs/jlikness/archive/2010/08/22/coroutines-for-asynchronous-sequential-workflows-using-reactive-extensions-rx.aspx