动画和计时系统概述

更新:2007 年 11 月

本主题描述计时系统如何使用动画、TimelineClock 类来对属性进行动画处理。

先决条件

为了了解本主题,您应当能够使用 WPF 动画来对属性进行动画处理,如动画概述所述。本主题还有助于您熟悉依赖项属性;有关更多信息,请参见依赖项属性概述

时间线和时钟

动画概述描述了 Timeline 如何表示一个时间段,还描述了动画是生成输出值的某种类型的 TimelineTimeline 本身除了仅仅描述一个时间段外,不执行任何其他操作。实际工作是由时间线的 Clock 对象执行的。同样,动画实际上不对属性进行动画处理:动画类描述应如何计算输出值,但它是为某个动画创建的 Clock,该动画会促进动画输出并将其应用于属性。

Clock 是一种特殊类型的对象,它维护 Timeline 的与计时相关的运行时状态。它提供动画和计时系统所必需的三则信息:CurrentTimeCurrentProgressCurrentStateClock 使用由它的 Timeline 所描述的计时行为(DurationRepeatBehaviorAutoReverse 等)来确定它的当前时间、进度和状态。

在多数情况下,会自动为您的时间线创建一个 Clock。当您使用 StoryboardBeginAnimation 方法来进行动画处理时,系统会自动为您的时间线和动画创建时钟,并将这些时钟应用于其目标属性。您还可以使用 TimelineCreateClock 方法显式创建 ClockMediaTimeline.CreateClock 方法为调用它的 Timeline 创建适当类型的时钟。如果 Timeline 包含子时间线,则还会为这些子时间线创建 Clock 对象。所得到的 Clock 对象将以树的形式排列,这些树与这些对象创建时所在的 Timeline 对象树相匹配。

不同类型的时间线具有不同类型的时钟。下表显示的是与一些不同 Timeline 类型相对应的 Clock 类型。

时间线类型

时钟类型

时钟用途

动画(继承自 AnimationTimeline

AnimationClock

为依赖项属性生成输出值。

MediaTimeline

MediaClock

处理媒体文件。

ParallelTimeline

ClockGroup

对它的子 Clock 对象进行分组和控制

Storyboard

ClockGroup

对它的子 Clock 对象进行分组和控制

可以使用 ApplyAnimationClock 方法,将您创建的任何 AnimationClock 对象应用于兼容的依赖项属性。

在严重依赖性能的方案(如对大量类似的对象进行动画处理)中,管理您自己对 Clock 的使用可能会提高性能。

时钟和时间管理器

当您对 WPF 中的对象进行动画处理时,时间管理器会管理系统为您的时间线创建的 Clock 对象。时间管理器是 Clock 对象树的根,并控制该树中的时间流。 时间管理器是为每个 WPF 应用程序自动创建的,它对于应用程序开发人员不可见。时间管理器每秒钟“滴答”多次;实际滴答次数取决于可用的系统资源。在每个滴答过程中,时间管理器都会计算计时树中所有 Active Clock 对象的状态。

下图演示时间管理器、AnimationClock 和带有动画的依赖项属性之间的关系。

对属性进行动画处理

计时系统组件

当时间管理器滴答时,它会更新应用程序中每个 Active Clock 的时间。如果 ClockAnimationClock,它会使用从中创建它的 AnimationTimelineGetCurrentValue 方法来计算其当前的输出值。AnimationClockAnimationTimeline 提供当前的本地时间、一个输入值(通常是属性的基值)和一个默认目标值。当您使用 GetValue 方法或动画依据属性的 CLR 访问器检索该属性的值时,会获得该属性的 AnimationClock 的输出。

时钟组

上一节描述了不同类型的时间线具有不同类型的 Clock 对象。下图演示时间管理器、ClockGroupAnimationClock 和带有动画的依赖项属性之间的关系。ClockGroup 是为用来对其他时间线进行分组的时间线创建的,如 Storyboard 类,该类对动画和其他时间线进行分组。

ClockGroup

计时系统组件

结构

可以将多个时钟与一个属性相关联,在这种情况下,每个时钟都将上一个时钟的输出值用作其基值。下图演示的是应用于同一个属性的三个 AnimationClock 对象。时钟1 将动画属性的基值用作其输入,并使用该值来生成输出。时钟2 将时钟1 的输出用作其输入,并使用该值来生成输出。时钟3 将时钟2 的输出用作其输入,并使用该值来生成输出。如果多个时钟同时影响同一个属性,则认为这些时钟位于一个结构链中。

结构链

计时系统组件

请注意,尽管在结构链中 AnimationClock 对象的输入和输出之间创建了关系,但是这些对象的计时行为不会受到影响;Clock 对象(包括 AnimationClock 对象)对于它们的父级 Clock 对象具有分层依赖性。

若要对同一个属性应用多个时钟,在应用 Storyboard、动画或 AnimationClock 时,请使用 Compose HandoffBehavior

滴答和事件合并

除了计算输出值以外,时间管理器还会在它每走过一个刻度时执行其他工作:它会确定每个时钟的状态并在适当时引发事件。

尽管滴答频率很高,但是在两次滴答之间还是有可能会发生许多事情。例如,Clock 可能会停止、启动和再次停止,在这种情况下,它的 CurrentState 值将更改三次。理论上,CurrentStateInvalidated 事件可以在一个滴答过程中引发多次;但是,计时引擎会对事件进行合并,因此,在每个滴答过程中,最多只能引发 CurrentStateInvalidated 事件一次。这同样适用于所有的计时事件:对于给定的 Clock 对象,针对每种类型最多引发一个事件。

Clock 在两次滴答之间切换状态并恢复到最初的状态(如从 Active 更改为 Stopped,然后再恢复为 Active)时,仍将发生相关的事件。

有关计时事件的更多信息,请参见计时事件概述

属性的当前值和基值

可进行动画处理的属性可以具有两个值:基值和当前值。当您使用属性的 CLR 访问器或 SetValue 方法设置属性时,可以设置属性的基值。对于尚未动画处理的属性,基值和当前值是相等的。

当您对属性进行动画处理时,AnimationClock 会设置属性的当前 值。当 AnimationClockActiveFilling 时,通过属性的 CLR 访问器或 GetValue 方法检索属性值会返回 AnimationClock 的输出。可以使用 GetAnimationBaseValue 方法来检索属性的基值。

请参见

概念

动画概述

计时事件概述

计时行为概述