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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14690960/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 07:22:28  来源:igfitidea点击:

WPF: What is the correct way to wait for a storyboard animation to complete before performing an operation

wpfwpf-controls

提问by black eyed pea

I have a storyboard which I reuse to animate some pictures, I wanna perform some operation after each animation, which includes some calculations, and then running another animation, so I believe I should be using the StoryBoard's Completed Event MyStoryboard.Completed += storyboard_Com?pleted;

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

What I'm curious about is, should I start the next animation in the current StoryBoard's Storyboard_Completed Event? And, are there any implications if I started the first animation in a separate thread using the Application.Current.Dispatcher Object?

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

If I called a StoryBoard.Begin() in a separate thread using the Application.Current.Dispatcher, does the Storyboard_Completed Event also get invoked in the UI thread? In this case, do I still need to wrap the Next Animation within another Dispatcher Invoke?

如果我使用 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();
    }
}

Is this correct? Or is there a better way to check if a storyboard has ended and start the next set of calculations & storyboard animation right after that?

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

I've thought of using a single background worker to handler all animations and calculations in sequence, but I'm also wondering how to "wait" for the animation to complete before starting on the next set of calculations and animations. Is it normal for a BackGroundWorker to have Thread.sleepwhile waiting for animation to complete?

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

采纳答案by BTownTKD

You could wrap the Storyboard in a Taskobject and awaitits completion.

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

Here is an excellent bit of sample code illustrating how to do just that, taken from a blog postby Morten Nielsen:

这是一段很好的示例代码,说明了如何做到这一点,摘自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;
    }
}

Essentially you're creating an extension method, which returns a Task object signalling the completion of the Storyboard. In this way, you get some nice fluid syntax like this:

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

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

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

回答by dandubious

Using the Storyboard.Completed event should work for your purposes. The Storyboard.Completed event handler should fire on the UI thread, so you should not need to call Application.Current.Dispatcher.Invoke to fire off the second Storyboard.

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

There should be no implications if you call the original Storyboard.Begin using Application.Current.Dispatcher.Invoke. This won't launch the storyboard animation on a new thread. It will asynchronously invoke the animation on the main UI thread. Whether you call Begin on the UI thread yourself or whether you use Application.Current.Dispatcher.Invoke to do it, the final result should be the same. Your completed event handler will fire when the storyboard finishes, and you can perform your calculations and fire off the next storyboard.

如果您使用 Application.Current.Dispatcher.Invoke 调用原始 Storyboard.Begin,则应该没有任何影响。这不会在新线程上启动故事板动画。它将异步调用主 UI 线程上的动画。不管是自己在UI线程上调用Begin,还是使用Application.Current.Dispatcher.Invoke来做,最终的结果应该是一样的。您的完成事件处理程序将在故事板完成时触发,您可以执行计算并触发下一个故事板。

See the following question for some discussion of storyboard having being used in the past as a timer because of the fact that it runs on the UI thread:

请参阅以下问题,了解过去由于故事板在 UI 线程上运行而被用作计时器的一些讨论:

What is the point of using Storyboard as timer?

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

Also, this is probably overkill for the specific case you are describing, but if you need to orchestrate a bunch of sequential, asynchronous operations, you could use Reactive Extensions:

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

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

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

The following article includes a sequential storyboard example (though the article is old enough that the syntax has probably changed):

下面的文章包括一个连续的故事板示例(尽管这篇文章已经足够老了,语法可能已经改变了):

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

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