计时事件概述
本主题描述如何使用 Timeline 和 Clock 对象中可用的 5 个计时事件。
先决条件
若要了解本主题,您应当了解如何创建和使用动画。 若要了解动画的基本知识,请参见动画概述。
可以使用多种方法在 WPF 中对属性进行动画处理。
使用 Storyboard 对象(标记和代码):您可以使用 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.
AddHandler myStoryboard.CurrentStateInvalidated, AddressOf myStoryboard_CurrentStateInvalidated
// Register for the CurrentStateInvalidated timing event.
myStoryboard.CurrentStateInvalidated += new EventHandler(myStoryboard_CurrentStateInvalidated);
有关更完整的示例,请参见 如何:在时钟状态发生变化时接收通知。
公共事件
Timeline 和 Clock 类都提供 5 个计时事件。 下表列出了这些事件和触发这些事件的条件。
Event |
触发交互操作 |
其他触发器 |
---|---|---|
完成 |
跳过以填充 |
时钟完成。 |
CurrentGlobalSpeedInvalidated |
暂停、继续、查找、设置速率、跳过以填充、停止 |
时钟反向、加速、开始或停止。 |
CurrentStateInvalidated |
开始、跳过以填充、停止 |
时钟开始、停止或填充。 |
CurrentTimeInvalidated |
开始、查找、跳过以填充、停止 |
时钟前进。 |
RemoveRequested |
移除 |
滴答和事件合并
当您在 WPF 中对对象进行动画处理时,是计时引擎在管理您的动画。 计时引擎跟踪时间的进度,并计算每个动画的状态。 它在一秒内会进行很多这样的计算过程。 这些计算过程称为“滴答”。
尽管滴答频率很高,但是在两次滴答之间还是有可能会发生许多事情。 例如,时间线可能会停止、启动和再次停止,在这种情况下,它的当前状态将更改三次。 理论上,事件可以在一个滴答过程中引发多次;但是,计时引擎会对事件进行合并,因此,在每个滴答过程中,每个事件最多只能引发一次。
注册事件
有两种方法可以注册计时事件:您可以向时间线注册,也可以向从时间线创建的时钟注册。 直接向时钟注册事件比较简单,但是它只能在代码中进行。 您可以从标记或代码中向时间线注册事件。 下一节描述如何向时间线注册时钟事件。
向时间线注册时钟事件
虽然时间线的 Completed、CurrentGlobalSpeedInvalidated、CurrentStateInvalidated、CurrentTimeInvalidated 和 RemoveRequested 事件似乎与时间线关联,但是注册这些事件实际上将事件处理程序与为该时间线创建的 Clock 关联。
例如,当您在时间线上注册 Completed 事件时,您实际上通知系统注册为时间线创建的每个时钟的 Completed 事件。 在代码中,您必须在为此时间线创建 Clock 之前注册此事件,否则您不会收到通知。 这在 XAML 中自动发生,分析器自动在创建 Clock 之前注册事件。