日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

《Programming WPF》翻译 第8章 2.Timeline

發布時間:2024/9/5 66 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《Programming WPF》翻译 第8章 2.Timeline 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
《Programming WPF》翻譯 第8章 2.Timeline 原文:《Programming WPF》翻譯 第8章 2.Timeline

Timeline代表了時間的延伸。它通常還描述了一個或多個在這段時間所發生的事情。例如,在前面章節描述的動畫類型,都是Timeline。可哦率這樣的DoubleAnimation

<DoubleAnimation?From=”10”?To=”300”?Duration=”0:0:5”?/>

正如Duration屬性指出的,這代表了一個5秒的時間長度。所有類型的Timeline總是有一個開始時間和一個持續時間。如果沒有詳細指定開始時間,它默認為0:0:0,但是它可以使用BeginTime屬性設置。開始時間可以是相對于各種引用幀的,如當一個頁面被解析的時候;或者是相對于另一個Timeline,依賴于Timeline在哪里定義的。

你還可以設置BeginTimenull。(在xaml中,這是通過{x:Null}標記來實現的。)這就指出了Timeline并沒有一個固定的開始時間,但是可以被某個事件觸發。后面我們將會看到任何觸發一個Timeline

不僅表示一個特定的時間延伸,特定的timeline還表示一段時間內某個值的改變。在timeline的開始,值為10,在結束,值為300DoubleAnimation是很多內建動畫類型的一個。

8.2.1 動畫時間線類型

WPF提供了一組動畫類——符合相同的基本樣式。因此當你必須選擇一個動畫類型——這個類型匹配被設置了動畫的屬性類型,,動畫類型的行為是相當一致的。

例如,Double類型的屬性可以被設置動畫——通過使用DoubleAnimation,而為了一個Color屬性,你可以使用ColorAnimation。這些類型都允許遵循相同的TypeAnimation命名轉換,正如你從表8-1中看到的。

Table 8-1. Animation types

BooleanAnimation

Int64Animation

SingleAnimation

ByteAnimation

MatrixAnimation

Size3DAnimation

CharAnimation

Point3DAnimation

SizeAnimation

ColorAnimation

PointAnimation

StringAnimation

DecimalAnimation

Rect3DAnimation

ThicknessAnimation

DoubleAnimation

RectAnimation

Vector3DAnimation

Int16Animation

Rotation3DAnimation

VectorAnimation

Int32Animation

? ?
所有的內建類提供了ToFrom屬性來設置開始值和結束值。可選擇的,很多還提供了By屬性,這將允許你修改屬性而不用知道它當前的值。如果示例8-4被應用到一個對象的Width,這將使得它增加100px的合理寬度,不管初始的Width值為多少。

示例8-4

<DoubleAnimation?By="100"?Duration="0:0:5"?/>

你可以設計動畫為交疊的——通過開始一個在另一個結束之前。你甚至可以這么做,通過動畫為同樣的屬性設置目標。如果動畫使用了ToFrom,最后一個動畫會覆蓋其它的。但是如果動畫使用了By,它們的效果是累積的。凈結果是獨立的動畫效果的總和。

Tofrom屬性在是示例8-1中所有的動畫類型上都是有效的。(By屬性不能夠不是在所有的類型上都有效,因為有一些,如Color,這將沒有任何意義。)當然,這些屬性的類型匹配了ColorAnimation目標類型,這些屬性將將會是Color類型的——當在DoubleAnimation上它們是Double類型的。在所有情形中,本質行為是一樣的。動畫簡單地在其持續時間內添加了新值,從一個值到另一個值。

默認的,這種添加新值是線性的。這個值以常速在整個動畫的持續時間內改變,然而,你可以通過AccelerationRationDecelerationRation屬性來改變這個值。這些屬性允許你向動畫提供一個“軟”的開始和結束。如果你設置了AccelerationRation0.2,這個動畫的改變速度將要從0開始,它會逐漸地加速到全速,在timeline的第一個五分之一的持續時間里。如果你設置DecelerationRation0.1,動畫將減速直到停止,在timeline的最后一個十分之一的持續時間里。

這是相當不尋常的——想只孤立地使用一個動畫。你將經常想對多個相關的動畫——一起工作以產生所需要的可視化效果——進行分類。為了支持這一點,timeline可以被分組和嵌套。

8.2.2 層次

Timeline經常排列在一個層次。我們已經看到SetterTimeline——作為DoubleAnimation的父一級,但這是普通的使更深層的嵌套,來管理更復雜的動畫。我們使用ParallelTimeline來實現,這是一個timeline類型,作為分組其他timeline使用。

子一級Timeline的開始時間是相對于它們的父一級的。因此BeginTime0:1:0并不一定意味著1分鐘。作為子一級Timeline,它意味著1分鐘,在它的父一級開始之后。

示例8-5使用ParallelTimeline對一些動畫進行分組。

示例8-5

<Window?Text="TimelineHierarchy"?Width="320"?Height="100"
????xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
????xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005">

????
<Window.Storyboards>

????????
<ParallelTimeline?RepeatBehavior="Forever">

????????????
<SetterTimeline?BeginTime="0:0:0"?TargetName="button1"
????????????????????????????Path
="(Button.Height)">
????????????????
<DoubleAnimation?Duration="0:0:0.2"
?????????????????????????????????By
="30"?AutoReverse="True"?/>
????????????
</SetterTimeline>

????????????
<SetterTimeline?BeginTime="0:0:1"?TargetName="button2"
????????????????????????????Path
="(Button.Height)">
????????????????
<DoubleAnimation?Duration="0:0:0.2"
?????????????????????????????????By
="30"?AutoReverse="True"?/>
????????????
</SetterTimeline>


????????????
<ParallelTimeline?BeginTime="0:0:2">
????????????????
<SetterTimeline?BeginTime="0:0:0"?TargetName="button3"
????????????????????????????????Path
="(Button.Height)">
????????????????????
<DoubleAnimation?Duration="0:0:0.2"
?????????????????????????????????????By
="30"?AutoReverse="True"?/>
????????????????
</SetterTimeline>
????????????????
<SetterTimeline?BeginTime="0:0:1"?TargetName="button4"
????????????????????????????????Path
="(Button.Height)">
????????????????????
<DoubleAnimation?Duration="0:0:0.2"
?????????????????????????????????????By
="30"?AutoReverse="True"?/>
????????????????
</SetterTimeline>
????????????
</ParallelTimeline>

????????
</ParallelTimeline>

????
</Window.Storyboards>

????
<StackPanel?Orientation="Horizontal"?VerticalAlignment="Center">
????????
<Button?x:Name="button1"?Height="25">One</Button>
????????
<Button?x:Name="button2"?Height="25">Two</Button>
????????
<Button?x:Name="button3"?Height="25">Three</Button>
????????
<Button?x:Name="button4"?Height="25">Four</Button>
????
</StackPanel>
</Window>

這個動畫按順序修改了每個按鈕的高度,放大了按鈕,然后收縮到它的元素大小。圖

8-2顯示了這個動畫的中途的一個情形。

8-2


Storyboard的結構并不是像這個簡單的序列所建議的那樣直接。它有一點人為的結構,為了在層次上顯示timeline的效果。每一個按鈕都有一個SetterTimelineDoubleAnimation來為它的高度設置動畫。前兩個按鈕是足夠簡單的,它們都是ParallelTimeline的子級,而且SetterTimeline.BeginTime屬性被各自設置為0:0:00:0:1。這意味這第二個按鈕伸展和縮短比第一個按鈕晚1秒。然而,后兩個按鈕有點令人驚訝的。它們的BeginTime屬性也都分別設置為0:0:00:0:1。雖然這樣,它們并沒有和頭兩個按鈕同時伸展和縮短。圖8-2顯示了第四個按鈕,和第二個按鈕具有同樣的大小。

這些按鈕的動畫從左到右一個接著一個執行。即使后兩個按鈕和前兩個按鈕有相同的BeginTime值,這仍然是可以工作的,原因是它們嵌入到了另一個ParallelTimeline中,這將輪流嵌入到頂級的ParallelTimeline中。后兩個動畫的BeginTime屬性是關聯到這個內嵌的ParallelTimeline,而不是頂級的ParallelTimeline。這種內嵌了ParallelTimeline的動畫有一個值為0:0:2BeginTime,意味著它直到頂級timeline2秒后才開始運行,在前兩個按鈕被設置動畫之后。這依次意味著這些內嵌按鈕的動畫直到這是才開始運行。

8-3說明了示例8-5Storyboard的結構。每一個timeline(包括SetterTimelineDoubleAnimation)都表示為一個水平線,在開始和結束的位置都有一個圓點。它的水平位置指出了,當timeline按照上面顯示的刻度運行時,這個timeline向右顯示的越遠,,它運行的越晚。(這個刻度相對于應用程序開始的時間)

這種有層次的結構使得改變很容易——當一個動畫序列開始時,而不用必須遍及這個序列的任意細節。因為每個BeginTime屬性指向到它的父一級,我們可以通過調整這個單獨的BeginTime來移動序列。例如,我們可以改變——當后兩個按鈕通過只改變它們父一級的BeginTime的方式設置動畫。一種繪制的方式是想象在圖8-3中通過一個被標記為BeginTime的垂直箭頭獲取這個結構。如果你移動一條線從一邊到另一邊,任何在這條線下的事物都會跟著移動。

圖8-3

在這個示例中,唯一的
BeginTime——相對于流逝的時間,是頂級的不具備父一級的ParallelTimeline。默認的,頂級的ParallelTimeline會使用“全局應用程序時鐘”作為它的參考。這個“全局應用程序時鐘”開始運行于應用程序首次解析標記或加載xaml,因此任何這樣timelineBeginTime是相對于應用程序首次加載UI的時間。

“全局應用程序時鐘”并沒有等第一個窗體的打開。當UI初始化的時候,它才開始運行。這意味著你的動畫在顯示這個窗體之前開始計時是可能的。極端的例子是,動畫可以在窗體出現之前結束。如果你想動畫只在窗體出現之前開始,你可以給它們一個空的BeginTime,以及使用在本章后面討論的代碼后置技術。我們希望這個樣式的版本可以更容易地設置動畫的開始時間——相對于UI的外觀。

注意到在圖8-3中,圖表的右手邊,所有的四個激活的timeline都到達了一個終點在一個嚴格相同的瞬間。這不僅僅是坐標。這甚至不是小心編碼的結果,如果你看一下示例8-5,你可以看到,只有帶著明確的延續時間的timeline才是DoubleAnimation元素。所有其它的timeline自動獲取它們的延續時間。

8.2.3 延續時間

如果你沒有提供一個Duration屬性,timeline會嘗試計算出它的延續時間。這會基于它的子級別的延續時間,設置它自己的延續時間,使之足夠長以容納任何最后一個結束的timeline

考慮一下示例8-6

示例8-6

<ParallelTimeline>

????
<SetterTimeline?BeginTime="0:0:0"?TargetName="button1"
????????????????????????????Path
="(Button.Height)">
????????
<DoubleAnimation?Duration="0:0:0.2"?By="30"?/>
????
</SetterTimeline>

????
<SetterTimeline?BeginTime="0:0:1"?TargetName="button2"
????????????????????????????Path
="(Button.Height)">
????????
<DoubleAnimation?Duration="0:0:0.2"?By="30"?/>
????
</SetterTimeline>

</ParallelTimeline>

每個

DoubleAnimation都有一個顯示的Duration,但是兩個SetterTimeline元素沒有。它們都有一個隱式的延續時間——由它們的子級DoubleAnimation結束的時間決定。在這個例子中,這意味著這兩個SetterTimeline元素都有0.2秒的延續時間。

父一級ParallelTimeline是有趣的,因為它包括兩個SetterTimeline元素,它們都有一個隱式的0.2秒延續時間。然而,這個timeline的有效延續時間并不是0.2秒;而是1.2秒。還記得一個隱式的延續時間并不簡單的是最長的子級timeline的長度,而是由最后一個timeline結束的時間決定。第二個SetterTimeline對象的BeginTime值為0:0:1,也就是在它的父一級ParallelTimeline開始后1秒。由于這個子級的延續時間是0.2秒,它就直到它的父一級開始1.2后才會結束——意味著它的父一級有一個隱式的1.2秒延續時間。

所有的timeline都提供一個AutoReverse屬性。如果被設為truetimeline將會反過來運行——在它到達終點時。這就加倍了它的延續時間。這會產生輕微地困惑,當與一個顯示Duration協力工作時。一個帶有顯示0:0:0.2Duration以及AutoReverse設置為true,有一個有效的0.4秒延續時間。這就是為什么圖8-3中的timeline都比你所希望的長一些。

一般而言,顯示延續時間機制工作良好,可以為你節省一些努力。然而,有一些情形會引起驚訝。確實,它會引起一個輕微的小故障在一個早期的示例中。如果你測試了示例8-5,你會注意到這里有一個僅多于0.5秒的間隙在每個按鈕伸展和收縮之間,除重復序列以外。在第四個按鈕結束收縮和第一個按鈕開始伸展之間沒有間隙。這個小故障在圖8-3中是可見的。?

你可以看到每個DoubleAnimation以一個整秒數在序列之間。第一個按鈕馬上就有了動畫效果,第二個在1秒之后,第三個在2秒之后,第四個在3秒之后。但是因為這個動畫會在3.4秒后重復,這引起了一個簡單的不平衡的感覺。如果在4秒后重復,這將會更好。

有很多種方法來修復這個問題。我們可以僅設置頂級ParallelTimeline的延遲時間為4秒。更巧妙地,我們可以設置第四個SetterTimeline的延遲時間為1秒。這將隱式地擴展它的父一級ParallelTimeline2秒長——使得頂級ParallelTimeline4秒。盡管這個方法看上去不太直接,它避免了硬編碼頂級timeline的延遲時間,意味著如果你后來添加了更多的子級動畫,你不會需要返回來調整頂級的延遲時間。

8.2.4 循環

默認的,一個timeline開始于由它的BeginTime詳細指定的偏移,并停止于當它到達延遲時間時。盡管如此,所有的timeline都有一個RepeatBehavior屬性,支持它們重復一次或更多次在到達它們的終止點之后。

我們已經在示例8-5中看到這一點,在頂級ParallelTimelineRepeatBehavior設置為Forever之處。這有一個對頂級元素充分直接的意義:它們會在UI運行的時候重復。對于內嵌的timeline,這并不是非常簡單的。當一個內嵌的帶有RepeatBehavior設置為Forevertimeline到達延遲時間的終點時,它會回到起始點以及繼續重復直到時間的終點,但是只為“the end of time”的小值。

記住任何嵌入timelineBeginTime都是相對于它的父一級。實際山,它的全部時間視圖都由它的父一級決定。因此對于一個內嵌的timeline,“the end of time”意味著它的父一級的延遲時間。示例8-7顯示了一個值為ForeverRepeatBehavior可以在一小段時間后被切分。

示例8-7

<Window?Text="The?End?Of?The?World?As?We?Know?It"?Width="330"?Height="100"
????xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005"
????xmlns
="http://schemas.microsoft.com/winfx/avalon/2005">

????
<Window.Storyboards>
????????
<ParallelTimeline?Duration="0:0:5">
????????????
<SetterTimeline?BeginTime="0:0:2"?TargetName="button1"
????????????????????????????Path
="(Button.Background).(SolidColorBrush.Color)">
????????????????
<ColorAnimation?From="Red"?To="Yellow"?Duration="0:0:1"
????????????????????????????????AutoReverse
="True"
????????????????????????????????RepeatBehavior
="Forever"?/>
????????????
</SetterTimeline>
????????
</ParallelTimeline>
????
</Window.Storyboards>

????
<Button?x:Name="button1"?Background="Red"?VerticalAlignment="Center"
????????????HorizontalAlignment
="Center">
????????I?feel?fine
????
</Button>
</Window>

在這個示例中,按鈕的背景被設置了動畫效果:在紅色和黃色之間漸變。它使用了一個

ColorAnimation,帶有一個值為ForeverRepeatBehavior。運行這段代碼,在2秒內顯示了一個紅色的按鈕,漸變到黃色,并返回來一次,再一次漸變到黃色,然后突然回到紅色,并永遠保持這樣的方式。這2秒的延遲由SetterTimeline.BeginTime0:0:2導致。這個動畫在一個半循環(3秒)后被切割,因為頂級的ParallelTimeline有一個顯示的0:0:5延遲時間。一旦達到了這一點,timeline和所有它的子一級都會結束,動畫也不再有效了,以及按鈕反轉到它的原始顏色。

8-4顯示了示例8-7中的timeline結構。正如你看到的,SetterTimeline2秒后開始,因為它的BeginTime0:0:2ColorAnimation.Duration屬性被設置為0:0:1,但是這并不是一個有效的延遲時間。首先,AutoReverse屬性被設置為true,加倍了有效的長度。此外,因為它的RepeatBehavior值為Forever,它將會執行在它被允許的時候,因此它的有效的延遲時間只是被它的上下文約束。

SetterTimeline容器并沒有一個顯示的延遲時間,因此它獲取不確定的有效的ColorAnimation延遲時間。但是這些都被它的父一級ParallelTimeline切割,帶有它的顯示5秒延遲時間。

如果你使用設置為ForeverRepeatBehavior,并沒有在父一級進行切割——帶有顯示的延遲時間,隱式的父一級元素的延遲時間將是不確定的。從示例8-7中的ParallelTimeline移除Duration屬性,允許顏色動畫不確定地運行。

RepeatBehavior屬性還支持有效的重復。你可以指示一個timeline來重復一個特定長度的時間或一個固定數量的迭代。示例8-8顯示了這兩個技術的例子。

8-4


示例
8-8

<ColorAnimation?From="Red"?To="Yellow"?Duration="0:0:1"
????????????????RepeatBehavior
="3x"?/>

<DoubleAnimation?By="20"??Duration="0:0:0.25"
?????????????????RepeatBehavior
="0:0:2"?/>

示例

8-8中的ColorAnimationRepeatBehaior值為3x。這指出了動畫應該重復3次然后停止。有效的動畫結束延遲時間為3秒,三倍時間比沒有使用重復的情況。DoubleAnimationRepeatBehavior值為0:0:2。這意味著這個動畫將會重復直到2秒過后。

8.2.5 填充

很多動畫有有限的延遲時間。這引發了一個問題:當動畫完成后,被設置了動畫的屬性將會發生什么?到目前為止出現的示例都有點鬼鬼祟祟的——我們看到的所有動畫或者是永遠重復或者是設置屬性回到它的原始值在它們結束之前。示例8-9沒有使用這些詭計。

示例8-9

<Window?x:Class="Holding.Window1"?Text="Holding"
????xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
????xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005"
????Width
="320"?Height="150">

????
<Window.Storyboards>
????????
<SetterTimeline?BeginTime="0:0:2"?TargetName="myEllipse"
????????????????????????Path
="(Ellipse.Width)">
????????????
<DoubleAnimation?From="10"?To="300"?Duration="0:0:5"?/>
????????
</SetterTimeline>
????
</Window.Storyboards>

????
<StackPanel?Orientation="Horizontal">
????????
<Ellipse?x:Name="myEllipse"?Height="100"?Fill="Red"?/>
????
</StackPanel>

</Window>

示例

8-9非常類似于示例8-1。這兩個示例都設置了動畫,使橢圓的大小在5秒內從10增加到300。這里有5個不同點。示例8-9只運行了動畫一次。它忽略了示例8-1中的RepeatBehavior。它還在開始之前等待2秒。

當你運行這個程序時,這個橢圓會初始化為不可見的。2秒后,它會出現,然后逐漸擴展——像之前那樣。在5秒動畫的終點,這個橢圓保持著它的原始大小。我們可以添加一些代碼來更詳細地看一下,正如示例8-10所示。

示例8-10

using?System;
using?System.Windows;
using?System.Windows.Threading;
using?System.Diagnostics;

namespace?Holding
{
????
public?partial?class?Window1?:?Window
????
{
????????
public?Window1(?)
????????
{
????????????InitializeComponent(?);

????????????t?
=?new?DispatcherTimer(?);
????????????t.Tick?
+=?new?EventHandler(OnTimerTick);
????????????t.Interval?
=?TimeSpan.FromSeconds(0.5);
????????????t.Start(?);
????????????start?
=?DateTime.Now;
????????}

????????
private?DispatcherTimer?t;
????????
private?DateTime?start;

????????
void?OnTimerTick(object?sender,?EventArgs?e)
????????
{
????????????TimeSpan?elapsedTime?
=?DateTime.Now?-?start;
????????????Debug.WriteLine(elapsedTime.ToString(?)?
+?":?"?+
????????????????myEllipse.Width);
????????}

????}

}

示例

8-10創建了一個timer,每秒2次調用我們的OnTimerTrick函數。(DispatcherTimer是一個特殊的WPF的計時器,保證了在能使UI安全工作的上下文中調用我們的計時器。這意味著我們不需要擔心是否在安全的線程上。參見附錄C獲取更多WPF中線程的信息。)在每個計時器的tick中,橢圓的寬度將使用Debug類打印出來。運行這個程序在vs2008中,我們可以在“輸出”面板中看到這些消息,如下:

??? 00:00:00.5007200: NaN
??? 00:00:01.1917136: NaN
??? 00:00:01.6924336: 19.4539942
??? 00:00:02.1931536: 48.57
??? 00:00:02.6938736: 77.512
??? 00:00:03.1945936: 106.628
??? 00:00:03.6953136: 135.57
??? 00:00:04.1960336: 164.628
??? 00:00:04.6967536: 193.686
??? 00:00:05.1974736: 222.686
??? 00:00:05.6981936: 251.744
??? 00:00:06.1989136: 280.802
??? 00:00:06.6996336: 300
??? 00:00:07.2003536: 300

這就說明了2點。首先,不要依賴DispatcherTimer特別精確于它什么時候回調的,尤其是如果你運行在調試器中。其次,在動畫運行前,橢圓報到的準確寬度為NaN。這是Not a Number的簡寫,同時說明了屬性的寬度并沒有一個值。

NaN是由Double浮點類型支持的一個特殊值。對于WPF這不是稀奇的。IEEE標準中的浮點類型為積極的和消極的無限值定義了特殊值,以及這個“not a number”值。NaN經常出現于可疑的操作,如嘗試00,或者從無限值中減去有限值。

雖然NaN是一個標準值,WPF在這里使用它有一點不尋常。它擔當著一種標記值,指出了一個屬性沒有被設置。

我們不應驚訝于橢圓初始沒有寬度,由于我們沒有直接在標記中設置橢圓的寬度屬性。我們使用動畫間接地設置,因此Width屬性只有一個意味深長的值,一旦動畫開始。我們修復這個問題,通過設置橢圓的寬度。

<Ellipse?x:Name=”myEllipse”?Height=”100”?Fill=”Red”?Width=”42”?/>

做了這樣的改動,這個橢圓在動畫開始時是可見的。它初始化為

42px寬度。(如以前,一旦動畫結束,它是300px寬度。)調試器反映了這一點,在動畫的開始顯示了寬度為42的值,取代以NaN 00:00:00.5007300: 42 00:00:01.0415184: 42 00:00:01.5422484: 42 00:00:02.0429784: 21.4259942 00:00:02.5537230: 50.948 00:00:03.0544530: 79.948 00:00:03.5551830: 109.006 00:00:04.0659276: 138.644 00:00:04.5666576: 167.7019942 00:00:05.0673876: 196.76 00:00:05.5781322: 226.34 00:00:06.0788622: 255.398 00:00:06.5795922: 284.398 00:00:07.0803222: 300 00:00:07.5810522: 300

這是動畫的默認行為——當它們到達終點時,它們最后的值持續請求——只要它們的父一級timeline持續為活動的。在一些環境中,這可能并不總是你需要的行為,你可能想確保這個屬性返回它的原始值。即使當它是你需要的行為的時候,這看起來并不是直接了當的。

當一個動畫到達它的延遲時間的終點時,這個動畫并沒有完全結束。我們看到動畫的最后值——應用到上面的示例中,原因是這個動畫仍然是活動的,即使它已經到達延遲時間的終點。這個模糊的地帶——在動畫延遲時間的終點和它最后的鈍化之間,被稱為“填充周期”。

所有的timeline都有一個FillBehavior屬性,詳細指出了在timeline到達它的有效延遲時間之后發生了什么。默認值為HoldEnd,意味著這個動畫將會繼續應用它的最后值直到UI關閉,除非一些事引起它為無效的。可選擇的FillBehavior,顯示在示例8-11中,為Deactivate。這使得這個動畫無效——一旦它到達了延遲時間的終點,意味著相應的屬性將會反轉它的值在動畫開始之前。

示例8-11

<Ellipse?x:Name="myEllipse"?Height="100"?Fill="Red"?FillBehavior="Deactivate"?/>

注意到,不同于

RepeatBehaviorFillBehavior屬性對timeline的有效延遲時間沒有影響。FillBehavior.HoldEnd只會做一些事——如果父一級timeline運行時間比正被討論的timeline的延遲時間長。示例8-12顯示了這樣一個場景。父一級SetterTimeline10秒的延遲時間,當它的子一級有5秒的延遲時間,剩下一個5秒的“填充周期”。子一級FillBehavior并沒有被設置,因此它默認為HoldEnd

示例8-12

<SetterTimeline?TargetName="myEllipse"?Path="(Ellipse.Width)"
????????????????Duration
="0:0:10"?HoldEnd="Deactivate">
????
<DoubleAnimation?From="10"?To="300"?Duration="0:0:5"?/>
</SetterTimeline>


8-5說明了這樣一對timeline。由于父一級timelineFillBehaviorDeactivate,它在其自然的延遲時間終止點會失效。當父一級失效時,所有的子一級都會失效,因此這會引起子一級的“填充周期”到達終點,意味著相應的屬性將全都回復到在動畫開始之前的值。

8-5


如果頂級
timeline有一個默認為HoldEndFillBehavior,它的“填充周期”將是不確定的。這就一次意味著它的子一級“填充周期”也會是不確定的。示例8-13顯示了這樣一個有層次的Timeline。(這和示例8-9具有相同的一組Timeline

示例8-13

<Window.Storyboards>
????
<SetterTimeline?BeginTime="0:0:2"?TargetName="myEllipse"
????????????????????Path
="(Ellipse.Width)">
????????
<DoubleAnimation?From="10"?To="300"?Duration="0:0:5"?/>
????
</SetterTimeline>
</Window.Storyboards>

這里,

DoubleAnimationSetterTimeline都有一個顯示的FillBehavior,因此它們默認為HoldEnd。由于SetterTimeline是頂級的timeline(沒有父一級),這意味著它的“填充周期”是有效不確定的。這就依次表明DoubleAnimation也有一個不確定的“填充周期”,正如圖8-6中的雙向箭頭指出的。示例8-13中帶有Storyboard的結果是,橢圓的寬度從10增長到300,并保持在300

8-6


默認的填充行為意味著動畫典型地結束于一個不確定的“填充周期”。這通常導致了渴望的行為:一旦動畫的延遲時間結束一個動畫的最后值就是在那個適當的的位置保持的值。然而,它有一個令人吃驚的結果——如果你一個接著一個應用多個動畫到同樣的屬性,而且這些屬性使用
By屬性。例如,你可能有一個動畫:在幾秒內向右移動一個對象,接著另一個動畫將會在它的“填充周期”內。這意味著兩個動畫是同時激活的。如果第二個動畫使用了FromTo,這將復寫第一個屬性。但是如果它使用了By屬性,這個動畫將會累積。動畫系統會把第二個動畫的效果添加到第一個動畫。

幸運的是,在這種情形中,這個行為的終結結果可以是你想要的——當使用By屬性時,第二個動畫的起始點是第一個動畫的最后值。

8.2.6 速度

有時你可能發現你想改變動畫運行的某部分的速度。對于一個簡單的包含單獨元素的動畫,你可以只改變延遲時間。對于一個更復雜的動畫,有很多timeline組成,這將變得冗長的

——來手動調整每個延遲時間。一個簡單的解決方案是包裝時間,有效地在任何timeline上使用SpeedRatio屬性。

SpeedRatio允許你在動畫向后播放處改變速率。它的默認值為1,意味著所有的timeline提前一秒——為實時流逝的每一秒。然而,如果你修改了若干timeline中一個SpeedRatio2,這個timeline以及它的子一級都會提前2秒——為實時流逝的每一秒。

SpeedRatio是相對于父一級timeline前進的速率,而不是絕對的流逝時間。這變得很重要——如果你在多個地方詳細指出速率。示例8-14顯示了一個示例8-5動畫的修改后的版本,帶有一個SpeedRatio屬性,添加到某些timeline中。

示例8-14

<ParallelTimeline?RepeatBehavior="Forever">

????
<SetterTimeline?BeginTime="0:0:0"?TargetName="button1"
????????????????????Path
="(Button.Height)">
????????
<DoubleAnimation?Duration="0:0:0.2"?By="30"?AutoReverse="True"?/>
????
</SetterTimeline>

????
<SetterTimeline?SpeedRatio="2"?BeginTime="0:0:1"?TargetName="button2"
????????????????????Path
="(Button.Height)">
????????
<DoubleAnimation?Duration="0:0:0.2"?By="30"?AutoReverse="True"?/>
????
</SetterTimeline>


????
<ParallelTimeline?BeginTime="0:0:2"?SpeedRatio="4">
????????
<SetterTimeline?SpeedRatio="0.25"?BeginTime="0:0:0"?TargetName="button3"
????????????????????????Path
="(Button.Height)">
????????????
<DoubleAnimation?Duration="0:0:0.2"
?????????????????????????????By
="30"?AutoReverse="True"?/>
????????
</SetterTimeline>
????????
<SetterTimeline?SpeedRatio="0.5"?BeginTime="0:0:1"?TargetName="button4"
????????????????????????Path
="(Button.Height)">
????????????
<DoubleAnimation?SpeedRatio="0.125"??Duration="0:0:0.2"
?????????????????????????????By
="30"?AutoReverse="True"?/>
????????
</SetterTimeline>
????
</ParallelTimeline>
</ParallelTimeline>

8-7顯示了這些改動的效果。頂級timeline的速度沒有詳細指出,因此它默認為1,并按正常的速率前進。它的第一個SetterTimeline子一級也是這樣的。第二個SetterTimelineSpeedRatio2。這沒有影響這個timeline開始的時間。它的BeginTimeline是相對于它的父一級的,因此依賴于它的父一級速度。但是這個timeline的內容,DoubleAnimation,將會運行以正常速度的兩倍,因此它就像是這個動畫的延遲時間設置為0.1而不是0.2。結果是第二個按鈕擴展和收縮在第一個按鈕擴展和收縮的一半時間內。

頂級timeline的后兩個子一級是一個ParalletTimeline元素,帶有SpeedRatio4的屬性。這將是4倍于它工作中的子一級timeline。可是,它的子一級是帶有SpeedRatio0.25屬性的SetterTimeline。因此,這個timeline——設置在第三個按鈕的動畫,將會以正常的速度運行。下一個內嵌的SetterTimeline——控制著第四個按鈕,它的BeginTime設置為0:0:1,但是因為它的父一級SpeedRatio4,它將會開始于這個timeline中的1/4秒,引起它輕微交疊于前一個動畫,如圖8-7所示。它的速度為0.5,但這是相對于它的父一級速度為4,意味著這個timeline以雙倍速度運行。可是,它的子一級是速度為0.125DoubleAnimation。這里有3SpeedRatio值在運行中。這里,內嵌的ParalletTimelineSetterTimelineDoubleAnimation的速度分別為40.50.125。聯合這些,我們得到了0.25。因此最后的結果是第四個按鈕的動畫效果為四分之一的正常速度,因此是延遲時間的4倍。

8-7


到目前為止,本章所有的示例,你可能想知道為什么這些動畫都在
storyboard中。這是可論證地,對于ColorAnimation更加簡單,以間接地嵌入到示例8-2中的SolidColorBrush,取代以被隔離到Window.Storyboard屬性中,這里需要一個SetterTimeline元素來指出它應用到哪個元素。對于非常簡單的動畫,使用storyboard可能有一點麻煩,但是一旦你想要同時為多個屬性設置動畫,就會保持這些動畫異步激活的挑戰。Storyboard存在以解決這個問題。

posted on 2015-11-14 09:02 NET未來之路 閱讀(...) 評論(...) 編輯 收藏

轉載于:https://www.cnblogs.com/lonelyxmas/p/4963868.html

總結

以上是生活随笔為你收集整理的《Programming WPF》翻译 第8章 2.Timeline的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。