Timing Events Overview
This topic describes how to use the five timing events available on Timeline and Clock objects.
Prerequisites
To understand this topic, you should understand how to create and use animations. To get started with animation, see the Animation Overview.
There are multiple ways to animate properties in WPF:
Using storyboard objects (markup and code): You can use Storyboard objects to arrange and distribute animations to one or more objects. For an example, see Animate a Property by Using a Storyboard.
Using local animations (code only): You can apply AnimationTimeline objects directly to the properties they animate. For an example, see Animate a Property Without Using a Storyboard.
Using clocks (code only): You can explicitly manage clock creation and distribute the animation clocks yourself. For an example, see Animate a Property by Using an AnimationClock.
Because you can use them in markup and code, the examples in this overview use Storyboard objects. However, the concepts described can be applied to the other methods of animating properties.
What is a clock?
A timeline, by itself, doesn't actually do anything other than describe a segment of time. It's the timeline's Clock object that does the real work: it maintains timing-related run-time state for the timeline. In most cases, such as when using storyboards, a clock is created automatically for your timeline. You can also create a Clock explicitly by using the CreateClock method. For more information about Clock objects, see the Animation and Timing System Overview.
Why Use Events?
With the exception of one (seek aligned to last tick), all interactive timing operations are asynchronous. There is no way for you to know exactly when they will execute. That can be a problem when you have other code that's dependent upon your timing operation. Suppose that you wanted to stop a timeline that animated a rectangle. After the timeline stops, you change the color of the rectangle.
myStoryboard.Stop(myRectangle);
// This statement might execute
// before the storyboard has stopped.
myRectangle.Fill = Brushes.Blue;
myStoryboard.Stop(myRectangle)
' This statement might execute
' before the storyboard has stopped.
myRectangle.Fill = Brushes.Blue
In the previous example, the second line of code might execute before the storyboard stops. That's because stopping is an asynchronous operation. Telling a timeline or clock to stop creates a "stop request" of sorts that isn't processed until the timing engine's next tick.
To execute commands after a timeline completes, use timing events. In the following example, an event handler is used to change the color of a rectangle after the storyboard stops playing.
// Register for the CurrentStateInvalidated timing event.
myStoryboard.CurrentStateInvalidated += new EventHandler(myStoryboard_CurrentStateInvalidated);
' Register for the CurrentStateInvalidated timing event.
AddHandler myStoryboard.CurrentStateInvalidated, AddressOf myStoryboard_CurrentStateInvalidated
// Change the rectangle's color after the storyboard stops.
void myStoryboard_CurrentStateInvalidated(object sender, EventArgs e)
{
Clock myStoryboardClock = (Clock)sender;
if (myStoryboardClock.CurrentState == ClockState.Stopped)
{
myRectangle.Fill = Brushes.Blue;
}
}
' Change the rectangle's color after the storyboard stops.
Private Sub myStoryboard_CurrentStateInvalidated(ByVal sender As Object, ByVal e As EventArgs)
Dim myStoryboardClock As Clock = CType(sender, Clock)
If myStoryboardClock.CurrentState = ClockState.Stopped Then
myRectangle.Fill = Brushes.Blue
End If
End Sub
For a more complete example, see Receive Notification When a Clock's State Changes.
Public Events
The Timeline and Clock classes both provide five timing events. The following table lists these events and the conditions that trigger them.
Event | Triggering interactive operation | Other triggers |
---|---|---|
Completed | Skip to fill | The clock completes. |
CurrentGlobalSpeedInvalidated | Pause, resume, seek, set speed ratio, skip to fill, stop | The clock reverses, accelerates, starts, or stops. |
CurrentStateInvalidated | Begin, skip to fill, stop | The clock starts, stops, or fills. |
CurrentTimeInvalidated | Begin, seek, skip to fill, stop | The clock progresses. |
RemoveRequested | Remove |
Ticking and Event Consolidation
When you animate objects in WPF, it’s the timing engine that manages your animations. The timing engine tracks the progression of time and computes the state of each animation. It makes many such evaluation passes in a second. These evaluation passes are known as "ticks."
While ticks occur frequently, it's possible for a lot of things to happen between ticks. For example, a timeline might be stopped, started, and stopped again, in which case its current state will have changed three times. In theory, the event could be raised multiple times in a single tick; however, the timing engine consolidates events, so that each event can be raised at most once per tick.
Registering for Events
There are two ways to register for timing events: you can register with the timeline or with the clock created from the timeline. Registering for an event directly with a clock is fairly straightforward, although it can only be done from code. You can register for events with a timeline from markup or code. The next section describes how to register for clock events with a timeline.
Registering for Clock Events with a Timeline
Although a timeline's Completed, CurrentGlobalSpeedInvalidated, CurrentStateInvalidated, CurrentTimeInvalidated, and RemoveRequested events appear to be associated with the timeline, registering for these events actually associates an event handler with the Clock created for the timeline.
When you register for the Completed event on a timeline, for example, you're actually telling the system to register for the Completed event of each clock that is created for the timeline. In code, you must register for this event before the Clock is created for this timeline; otherwise, you won't receive notification. This happens automatically in XAML; the parser automatically registers for the event before the Clock is created.
See also
.NET Desktop feedback