9

我有一个故事板,我重复使用它来制作一些图片的动画,我想在每个动画之后执行一些操作,其中包括一些计算,然后运行另一个动画,所以我相信我应该使用 StoryBoard 的 Completed EventMyStoryboard.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();
    }
}

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

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

4

2 回答 2

9

您可以将 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;
    }
}

本质上,您正在创建一个扩展方法,该方法返回一个表示故事板完成的 Task 对象。通过这种方式,您可以获得一些不错的流畅语法,如下所示:

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

//Do my other stuff here, after the storyboard completes...
于 2013-02-04T20:55:29.960 回答
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 线程上运行:

使用 Storyboard 作为计时器有什么意义?

此外,对于您所描述的特定情况,这可能是矫枉过正,但如果您需要编排一堆顺序的异步操作,您可以使用 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

于 2013-02-05T06:23:11.983 回答