计时事件概述
本主题介绍如何使用 Timeline 和 Clock 对象上提供的五个计时事件。
先决条件
若要了解本主题,应了解如何创建和使用动画。 若要开始使用动画,请参阅动画概述。
在 WPF 中,对属性进行动画处理的方法有很多:
使用情节提要对象(标记和代码):可以使用 Storyboard 对象来排列动画并将其分发到一个或多个对象。 有关示例,请参阅使用情节提要对属性进行动画处理。
使用本地动画(仅代码):可以直接将 AnimationTimeline 对象应用到进行动画处理的属性。 有关示例,请参阅 在不使用演示图板的情况下对属性进行动画处理。
使用时钟(仅代码):可以显式管理时钟创建并自行分发动画时钟。 有关示例,请参阅使用 AnimationClock 对属性进行动画处理。
因为可以在标记和代码中使用它们,所以此概述中的示例使用 Storyboard 对象。 但是,所介绍的概念适用于其他对属性进行动画处理的方法。
是什么时钟?
除了描述时间段外,时间线本身并无其他任何作用。 实际工作由时间线的 Clock 对象执行:维护时间线计时相关的运行时状态。 在大多数情况下,比如使用情节提要时,会自动为时间线创建时钟。 还可以使用 CreateClock 方法显式地创建一个 Clock。 有关 Clock 对象的详细信息,请参阅动画和计时系统概述。
为什么使用事件?
除了一个例外(对齐到上一时钟周期的查找操作),所有交互式计时操作均为异步操作。 无法准确知道它们何时执行。 当存在其他代码依赖于计时操作时,可能会产生问题。 假设你希望停止对矩形进行动画处理的时间线。 在时间线停止后,更改矩形的颜色。
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
在上一示例中,第二行代码可能会在情节提要停止前执行。 这是因为停止操作是异步操作。 告知时间线或时钟停止将创建各种“停止请求”,但它仅在计时引擎的下一时钟周期才会处理。
若要在时间线完成后执行命令,请使用计时事件。 在下面的示例中,事件处理程序用于在情节提要停止播放后更改矩形的颜色。
// 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
有关更完整的示例,请参阅在时钟状态发生变化时接收通知。
公共活动
Timeline 和 Clock 类均提供五个计时事件。 下表列出了这些事件及其触发条件。
事件 | 触发交互式操作 | 其他触发器 |
---|---|---|
已完成 | 跳过以填充 | 时钟完成。 |
CurrentGlobalSpeedInvalidated | 暂停、恢复、查找、设置速度比、跳过以填充、停止 | 时钟反转、加速、启动或停止。 |
CurrentStateInvalidated | 开始、跳过以填充、停止 | 时钟开始、停止或填充。 |
CurrentTimeInvalidated | 开始、查找、跳过以填充、停止 | 时钟前进。 |
RemoveRequested | 删除 |
时钟周期和事件合并
在 WPF 中对对象进行动画处理时,计时引擎将管理动画。 计时引擎跟踪时间进度,并计算每个动画的状态。 它一秒内进行多次计算。 这些计算过程称为“时钟周期”。
尽管滴答频率很高,但是在两次滴答之间还是有可能会发生许多事情。 例如,时间线可能会停止、启动、再次停止,在这种情况下其当前状态将更改三次。 从理论上讲,在一个时钟周期内,可以多次引发事件;但是,计时引擎会合并事件,因此每个事件在每个时钟周期内只能引发一次。
注册事件
可以通过两种方法注册计时事件:使用时间线或使用从时间线创建的时钟进行注册。 直接使用时钟注册事件相当简单,不过该方法只能在代码中执行。 可以在标记或代码中使用时间线注册事件。 下一节介绍如何使用时间线注册时钟事件。
使用时间线注册时钟事件
尽管时间线的 Completed、CurrentGlobalSpeedInvalidated、CurrentStateInvalidated、CurrentTimeInvalidated 和 RemoveRequested 事件似乎与时间线相关联,但注册这些事件实际上会将事件处理程序与为时间线创建的 Clock 相关联。
例如,按时间线注册 Completed 事件时,实际上是在告诉系统针对为时间线创建的每个时钟注册 Completed 事件。 在代码中,为该时间线创建 Clock 之前,必须先注册此事件;否则,你将不会收到通知。 这在 XAML 中会自动发生;在 Clock 创建前,分析器自动注册事件。