Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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

Ask Question

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;

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?

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?

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.sleep while waiting for animation to complete?

I think you don't have to call SomeNewStoryBoardAnimation.Begin(); with the Dispatcher since Story_Completed is called by the UI Thread. – Cédric Bignon Feb 4, 2013 at 16:33

You could wrap the Storyboard in a Task object and await its completion.

Here is an excellent bit of sample code illustrating how to do just that, taken from a blog post by 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());
            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:

//Start the storyboard and asynchronously await completion...
await myStoryboard.BeginAsync();
//Do my other stuff here, after the storyboard completes...
                It's a nice solution, however it may be more appropriate to use the CurrentStateInvalidated event, because Completed is not raised if the Storyboard will be stopped. You would compare current clock state with ClockState.Stopped and ClockState.Filling, then.
– JeffRSon
                Nov 28, 2014 at 11:17

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.

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.

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:

What is the point of using Storyboard as timer?

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:

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

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.