動畫和計時系統概觀
本主題說明計時系統如何使用動畫、Timeline 和 Clock 類別來以動畫顯示屬性。
必要條件
若要了解本主題,您可以如動畫概觀中所述,使用 WPF 動畫來以動畫顯示屬性。 這也有助於熟悉相依性屬性。如需詳細資訊,請參閱相依性屬性概觀。
時間軸和時鐘
動畫概觀說明 Timeline 如何代表一段時間,以及動畫是一種會產生輸出值的 Timeline 類型。 單獨使用 Timeline 只會描述一段時間,不會執行任何其他動作。 執行實際工作的是時間軸的 Clock 物件。 同樣地,動畫不會實際以動畫顯示屬性 (動畫類別說明應如何計算輸出值),而是針對動畫所建立的 Clock 才會產生動畫輸出,並將其套用至屬性。
Clock 是一種特殊類型的物件,旨在維護 Timeline 的計時相關執行階段狀態。 它提供對於動畫和計時系統而言必要的三個資訊位元:CurrentTime、CurrentProgress 和 CurrentState。 Clock 會使用其 Timeline 所描述的計時行為 (Duration、RepeatBehavior、AutoReverse 等) 來判斷其目前時間、進度和狀態。
在大部分情況下,系統會自動為您的時間軸建立 Clock。 當您使用 Storyboard 或 BeginAnimation 方法以動畫顯示時,系統會自動為您的時間軸和動畫建立時鐘,並套用至其目標屬性。 您也可以使用 Timeline 的 CreateClock 方法來明確建立 Clock。 MediaTimeline.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 的時間。 如果 Clock 為 AnimationClock,則會使用建立它的 AnimationTimeline 的 GetCurrentValue 方法計算其目前的輸出值。 AnimationClock 會提供 AnimationTimeline 目前的當地時間 (一個輸入值,通常是屬性的基底值),以及預設目的地值。 當您使用 GetValue 方法或屬性的 CLR 存取子擷取動畫屬性的值時,您會得到其 AnimationClock 的輸出。
時鐘群組
上一節說明不同類型的時間軸有不同類型的 Clock 物件。 下圖顯示時間管理員、ClockGroup、AnimationClock 和動畫相依性屬性之間的關聯性。 將其他時間軸分組的時間軸會建立 ClockGroup,例如 Storyboard 類別會將動畫與其他時間軸分組。
ClockGroup
組合
您可以將多個時鐘與單一屬性進行關聯,此時每個時鐘都使用上述時鐘的輸出值做為其基底值。 下圖顯示三個套用至相同屬性的 AnimationClock 物件。 Clock1 使用動畫屬性的基底值做為輸入,並使用它來產生輸出。 Clock2 會採用從 Clock1 的輸出做為輸入,並使用它來產生輸出。 Clock3 會採用從 Clock2 的輸出做為輸入,並使用它來產生輸出。 當多個時鐘同時影響同一個屬性時,就可以說是形成一個組合鏈結。
組合鏈結
請注意,雖然在組合鏈結中 AnimationClock 物件的輸入和輸出之間已建立關聯性,但其計時行為不會受到影響。Clock 物件 (包括 AnimationClock 物件) 以階層方式相依於其父 Clock 物件。
若要將多個時鐘套用至相同的屬性,請在套用 Storyboard、動畫或 AnimationClock 時使用 Compose HandoffBehavior。
滴答和事件彙總
除了計算輸出值,時間管理員也會在每次滴答時執行其他工作︰它會判斷每個時鐘的狀態並引發適當的事件。
雖然滴答經常發生,但有很多事可能會在滴答之間發生。 例如,Clock 可能會停止、啟動又再次停止,在此情況下,其 CurrentState 值已變更三次。 理論上,CurrentStateInvalidated 可以在單一滴答中引發很多次;不過,由於計時引擎會彙總事件,因此 CurrentStateInvalidated 事件在每次滴答中最多只能引發一次。 這適用於所有的計時事件:對於指定的 Clock 物件,每個類型最多只會引發一次事件。
當 Clock 切換狀態並回到其滴答之間的原始狀態時 (例如從 Active 變更為 Stopped,再回到 Active),相關聯的事件還是會發生。
如需計時事件的詳細資訊,請參閱計時事件概觀。
屬性的目前值和基底值
可動畫的屬性可以有兩個值︰基底值和目前值。 當您使用屬性的 CLR 存取子或 SetValue 方法設定屬性時,就是在設定屬性的基底值。 當屬性未以動畫顯示時,其基底值和目前值都相同。
當您以動畫顯示屬性時,AnimationClock 會設定屬性的「目前」值。 當 AnimationClock 是 Active 或 Filling 時,透過屬性的 CLR 存取子或 GetValue 方法擷取屬性的值會傳回 AnimationClock 的輸出。 您可以使用 GetAnimationBaseValue 方法擷取屬性的基底值。