本主题介绍如何使用对 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 类均提供五个计时事件。 下表列出了这些事件以及触发这些事件的条件。
事件 | 触发交互式操作 | 其他触发器 |
---|---|---|
Completed | 跳过以填充 | 时钟完成。 |
CurrentGlobalSpeedInvalidated | 暂停、恢复、查找、设置速度比、跳过以填充、停止 | 时钟反转、加速、启动或停止。 |
CurrentStateInvalidated | 开始、跳过以填充、停止 | 时钟开始、停止或填充。 |
CurrentTimeInvalidated | 开始、查找、跳过以填充、停止 | 时钟前进。 |
RemoveRequested | 删除 |
时钟周期和事件合并
在 WPF 中对对象进行动画处理时,计时引擎负责管理您的动画。 计时引擎跟踪时间进度并计算每个动画的状态。 它一秒内进行多次计算。 这些计算过程称为“时钟周期”。
尽管时钟周期频繁发生,但是不同时钟周期之间可能会很多操作。 例如,时间线可能会再次停止、启动和停止,在这种情况下,其当前状态将更改三次。 从理论上讲,事件在单个时间刻度中可以多次触发;但是,计时引擎会合并事件,因此在每个时间刻度中每个事件最多只能触发一次。
报名活动
可以通过两种方法注册计时事件:使用时间线或使用从时间线创建的时钟进行注册。 直接使用时钟注册事件相当简单,不过该方法只能在代码中执行。 可以通过标记或代码注册具有时间线的事件。 下一部分介绍如何使用时间线注册时钟事件。
使用时间线注册时钟事件
尽管时间线的 Completed、CurrentGlobalSpeedInvalidated、CurrentStateInvalidated、CurrentTimeInvalidated和 RemoveRequested 事件似乎与时间线相关联,但注册这些事件实际上会将事件处理程序与为时间线创建的 Clock 相关联。
例如,按时间线注册 Completed 事件时,实际上是在告诉系统针对为时间线创建的每个时钟注册 Completed 事件。 在代码中,为该时间线创建 Clock 之前,必须先注册此事件;否则,你将不会收到通知。 这在 XAML 中自动发生;在创建 Clock 之前,分析器会自动注册事件。