1、基本動畫。
WPF提供了一個更高級的模型,通過該模型可以只關注動畫的定義,而不考慮它們的渲染方式,這個模型基於依賴項屬性基礎架構,本質上,WPF動畫只不過是在一段時間間隔內修改依賴項屬性值的一種方式。不過還有另外一個限制,爲了實現屬性的動態化,需要有支持相應數據類型的動畫類,例如Button.Width屬性使用雙精度數據類型,爲實現屬性的動態化,需要使用DoubleAnimation類,但Button.Padding屬性使用的是Thickness結構,所以需要使用ThicknessAnimation類。爲了爲屬性應用動畫,可以針對相應的數據類型創建自己的動畫類,你將發現,System.Windows.Media.Animation名稱空間已經爲希望使用的大多數數據類型提供了動畫類。
2、Animation類。
實際上有兩種類型的動畫,一種是在開始值和結束值之間以逐步增加的方式改變屬性的動畫(線性插值過程),另一種是從一個值突然變成另一值得動畫(關鍵幀動畫)。所有關鍵幀動畫都使用 "類型名 + AnimationUsingKeyFrames " 的形式進行命名,比如StringAnimationUsingKeyFrames和ObjectAnimationUsingKeyFrames。某些數據類型有關鍵幀動畫類,但沒有插值動畫類。例如,可使用關鍵幀爲字符串應用動畫,不能使用插值爲字符串應用動畫。然而,所有數據類型都支持關鍵幀動畫,除非他們根本不支持動畫。所有具有(使用插值)常規動畫類的數據類型,也都有相應的關鍵幀動畫的動畫類型,如線性插值的DoubleAnimation對應DoubleAnimationUsingKyyFrames。另外還有一種基於路徑的動畫。因此,WPF動畫使用三種方法:線性插值、關鍵幀和路徑。在System.Windows.Media.Animation名稱空間中將發現以下內容:
7個 “類型名+Animation類” 這些類使用插值動畫。
22個 “類型名+AnimationUsingKeyFrames” 這些類使用關鍵幀動畫。
3個 "類型名+AnimationUsingPath"類這類使用基於路徑的動畫。
3、使用代碼創建動畫。
wpf中,最常用的動畫技術是線性插值動畫,標準的幀速率是60秒/幀,使用動畫的最簡單方式是實例化在前面列出的其中一個動畫類,然後使用修改元素的BeginAnimation()方法,所有wpf元素,從UIElement基類開始,都繼承了BeginAnimation()方法,該方法是IAnimatable接口的一部分。
xaml代碼:
<Button Width="150" Height="60" Grid.Row="0" Click="Button_Click">點擊開始動畫</Button>
<Button Grid.Row="1" Name="btn1" Width="150" Height="60" Content="動畫按鈕"></Button>
後臺代碼:
private void Button_Click(object sender, RoutedEventArgs e)
{
//實例化一個DoubleAnimation類。
DoubleAnimation doubleAnimation = new DoubleAnimation();
//設置From屬性。
doubleAnimation.From = btn1.Width;
//設置To屬性。
doubleAnimation.To = 250;
//設置Duration屬性。
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
//爲元素設置BeginAnimation方法。
btn1.BeginAnimation(Button.WidthProperty, doubleAnimation);
}
其中, From屬性是元素的開始值,To屬性是元素屬性的結束值,Duration是整個動畫執行的時間。即使不使用To屬性,也可以使用By屬性,By值被簡單地增加到From值上,使其達到To值。不過,對於非數值數據類型來說,By屬性是沒有意義的。
4、同時發生的動畫。
就是創建多個Animation動畫,然後爲元素設置屬性。
private void Button_Click(object sender, RoutedEventArgs e)
{
//實例化一個DoubleAnimation類。
DoubleAnimation doubleAnimation = new DoubleAnimation();
//設置From屬性。
doubleAnimation.From = btn1.Width;
//設置To屬性。
doubleAnimation.To = 250;
//設置Duration屬性。
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
//爲元素設置BeginAnimation方法。
btn1.BeginAnimation(Button.WidthProperty, doubleAnimation);
//實例化一個DoubleAnimation動畫,用於設置元素的高。
DoubleAnimation doubleAnimationHeight = new DoubleAnimation();
//設置Form屬性。
doubleAnimationHeight.From = btn1.Height;
//設置To屬性的值。
doubleAnimationHeight.By = 70;
//設置時間。
doubleAnimationHeight.Duration = new Duration(TimeSpan.FromSeconds(3));
//開始動畫。
btn1.BeginAnimation(Button.HeightProperty, doubleAnimationHeight);
}
5、動畫的生命週期。
從技術的角度看,WPF動畫只是暫時的,這意味着它們不能真正改變基本屬性的值,當動畫處於活動狀態時,只是覆蓋了屬性的值。
單向動畫,在動畫運行結束後會保持處於活動狀態,這是因爲動畫需要將按鈕的寬度保持爲新值,這回導致如下常見問題,如果嘗試使用代碼在動畫完成後修改屬性值,代碼將不會起作用,因爲代碼只是爲屬性指定了一個新的本地值,但仍會先試用動畫之後的屬性值。
爲了解決動畫完成後能修改屬性的值,有以下方法可解決。
a)、設置AutoReverse屬性,如果將該屬性設置爲true,將會反向運動,返回原始的值(不適合動畫完成後,再爲屬性設置最後的值,只是還原爲動畫之前的值)。
b)、改變FillBehavior屬性。通常,FillBehavior屬性設置爲HoldEnd,這意味着噹噹動畫結束時,會繼續爲目標元素應用最後的值。如果將FillBehavior屬性改爲Stop,只要動畫結束,屬性就會恢復爲原來的值(適用於動畫結束後,再次爲其設置新值,一般不與AutoReverse配合着使用,這兩個用其中一個就行了)。
6、動畫的Completed事件。
使用Completed事件時,要將事件設置BeginAnimation()方法之前,否則不起作用。在Completed中,可通過調用BeginAnimation()方法來渲染不活動的動畫,爲此,只需要指定屬性,併爲動畫對象傳遞null引用。
void doubleAnimationHeight_Completed(object sender, EventArgs e)
{
MessageBox.Show("動畫的高執行完畢了!!!");
//設置空引用。
btn1.BeginAnimation(Button.HeightProperty, null);
}
7、TimeLine類。
7.1)、AccelerationRatio和DeceleRation屬性。
可以通過AcclerationRation和DecelerationRation屬性壓縮部分時間軸,使動畫運行的更快,並將拉伸其他時間進行補償,使總時間保持不變。這兩個屬性都表示百分比值,例如,將AcceleRation屬性設置爲0.3,表示希望使用動畫持續時間中前30%的時間進行加速。例如在1個10秒的動畫中,前3秒會加速運行,而剩餘的7秒會以恆定不變的速度運行,如果將DeceleRation屬性設置爲0.3,那麼最後3秒回減速運行。
private void Button_Click(object sender, RoutedEventArgs e)
{
//實例化一個DoubleAnimation類。
DoubleAnimation doubleAnimation = new DoubleAnimation();
//設置From屬性。
doubleAnimation.From = btn1.Width;
//前5秒加速度運行。
doubleAnimation.AccelerationRatio = 0.5;
//後2秒減速運行
doubleAnimation.DecelerationRatio = 0.2;
//設置To屬性。
doubleAnimation.To = 1000;
//設置Duration屬性。
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(10));
//爲元素設置BeginAnimation方法。
btn1.BeginAnimation(Button.WidthProperty, doubleAnimation);
}
7.2)、RepeatBehavior屬性。
使用RepeataBehavior屬性可以控制如何重複運行動畫,如果希望重複固定次數,應爲RepeatBehavior構造函數傳遞合適的次數。
還可設置RepeatBehavior爲永久重複。 //設置重複次數爲3次。 doubleAnimation.RepeatBehavior = new RepeatBehavior(3); //設置永久重複動畫。 doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
8、故事版。
WPF動畫通過一組動畫類表示,使用少數幾個屬性設置相關信息,如開始值、結束值以及持續時間。這顯然使他們非常適合於XAMl,不是很清晰的是,如何爲特定的事件和屬性關聯動畫,以及如何在正確的時間觸發動畫。
故事板:故事板是BeginAnimation()方法的XAML等價物,通過故事板將動畫指定到合適的元素和屬性。
事件觸發器:事件觸發器響應屬性變化或事件(如按鈕的Click事件),並控制故事板。
故事板:
故事板是增強的時間線,可用來分組多個動畫,而且具有控制動畫播放的能力—暫停、停止以及播放位置。然而Storyboard類提供的最基本功能是,能夠使用TargetProperty和TargetName屬性指向某個特定屬性和特定元素,換句話說,故事板在動畫和希望應用動畫的屬性之間架起了一座橋樑。其中TargetProperty屬性和TargetName屬性都是附加屬性。
<!--創建一個故事板-->
<Storyboard Storyboard.TargetProperty="Width">
<!--創建一個DoubleAnimation類。-->
<DoubleAnimation To="350" RepeatBehavior="Forever" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
<!--由於Storyboard.TargetProperty屬性是附加屬性,因此還可以寫出-->
<Storyboard >
<!--創建一個DoubleAnimation類。-->
<DoubleAnimation Storyboard.TargetProperty = "Width" To="350" RepeatBehavior="Forever" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
事件觸發器:
可以在以下4個位置定義事件觸發器。
a)、在樣式中(Style.Triggers集合)。
b)、在數據模板中(DataTemplate.Triggers集合)。
c)、在控件模板中(ControlTemplate.Triggers集合)。
d)、直接在元素中定義事件觸發器(FrameworkElement.Triggers集合)。
當創建事件觸發器時,需要指定開始觸發器的路由事件和觸發器執行的一個或多個動作。對於動畫,最常用的動作是BeginStoryboard,該動作相當於調用BeginAnimation()方法。所有事件觸發器都可以啓動動作,所有動作都由繼承自System.Windows.TriggerAction的類表示。
xaml代碼:
<Button Width="200" Height="80" Content="事件觸發器" FontSize="20">
<!--元素觸發器-->
<Button.Triggers>
<!--定義事件觸發器-->
<EventTrigger RoutedEvent="Button.Click">
<!--執行一個動作-->
<EventTrigger.Actions>
<!--開始故事板-->
<BeginStoryboard>
<!--創建一個故事板-->
<Storyboard >
<!--創建一個DoubleAnimation類。-->
<DoubleAnimation Storyboard.TargetProperty = "Width" To="350" RepeatBehavior="Forever" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
9、使用樣式關聯觸發器。
有三種基本類型的WPF觸發器:屬性觸發器、數據觸發器以及事件觸發器。使用觸發器是關聯動畫的最常用方式,但並不是唯一的選擇。
xaml代碼:
<Window.Resources>
<Style TargetType="Button">
<Setter Property="FontSize" Value="20"></Setter>
<Style.Triggers>
<!--使用屬性觸發器-->
<Trigger Property="IsPressed" Value="True">
<!--在這裏使用的是EnterActions-->
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Width">
<DoubleAnimation To="300" RepeatBehavior="Forever" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style>
</Window.Resources>
<Grid>
<Button Width="200" Height="80" Content="使用樣式關聯觸發器"></Button>
</Grid>
10、同步的動畫。
StoryBoard類間接地繼承自TimeLineGroup類,所以StoryBoard類能包含多個動畫,這些動畫可以作爲一組進行管理,這意味着它們可以在同一時間開始。
<Window.Resources>
<Style TargetType="Button">
<Setter Property="FontSize" Value="20"></Setter>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="300" Duration="0:0:3"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="Height" To="100" Duration="0:0:3"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Button Width="150" Height="70" Content="同步動畫"></Button>
</Grid>
11、控制播放。
到目前爲止,已經在事件觸發器中使用了一個動作,加載動畫的BeginStoryboard動作,然而,一旦創建故事版,就可以使用其他動作控制故事板,這些動作類都繼承自ControllableStoryboardAction類,控制故事版的主要類如下:
爲成功地執行這些動作,必須在同一個Triggers集合中定義所有的觸發器,如果將BeginStoryboard動作的觸發器和PauseStoryboard動作的觸發器放置到不同的集合中,PauseStoryboard動作就無法工作。
xaml代碼:
<Window x:Class="控制播放.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Triggers>
<!--開始事件-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_start">
<BeginStoryboard Name="beginstoryboard1">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="img" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:6"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<!--停止動畫-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_pause">
<PauseStoryboard BeginStoryboardName="beginstoryboard1"></PauseStoryboard>
</EventTrigger>
<!--恢復動畫-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_resume">
<ResumeStoryboard BeginStoryboardName="beginstoryboard1"></ResumeStoryboard>
</EventTrigger>
<!--停止動畫-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_stop">
<StopStoryboard BeginStoryboardName="beginstoryboard1"></StopStoryboard>
</EventTrigger>
<!--移除動畫-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_remove">
<RemoveStoryboard BeginStoryboardName="beginstoryboard1"></RemoveStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="3*"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Image Name="img" Source="1.jpg"></Image>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Name="btn_start" Content="開始" Margin="10" FontSize="20" Grid.Column="0"></Button>
<Button Name="btn_pause" Content="暫停" Margin="10" FontSize="20" Grid.Column="1"></Button>
<Button Name="btn_resume" Content="恢復" Margin="10" FontSize="20" Grid.Column="2"></Button>
<Button Name="btn_stop" Content="停止" Margin="10" FontSize="20" Grid.Column="3"></Button>
<Button Name="btn_remove" Content="移除" Margin="10" FontSize="20" Grid.Column="4"></Button>
</Grid>
</Grid>
</Window>
分析:在包含元素的Triggers集合中(在這裏是Window.Triggers集合),使用EventTrigger.SourceName屬性關聯這些事件觸發器,只要SourceName屬性和爲按鈕設置的Name屬性相匹配,觸發器就會用到恰當的按鈕上。還必須要問BeginStoryboard動作指定名稱,這樣其他觸發器BeginStoryboardName屬性指定這個名稱,連接到相同的故事板,然後進行控制。
12、故事板事件。
故事板事件
Completed 動畫已經到達終點
CurrentGlobalSpeedInvalidated 速度發生了變化,或者動畫被暫停、重新開始、停止或移到某個新的位置。
CurrentStateInvalidated 動畫已經開始或結束。
CurrentTimeInvalidated 動畫時鐘已經向前移動了一個步長,正在更改動畫。當動畫開始、停止或結束時也會引發該事件。
RemoveRequested 動畫正在被移除。
監視動畫進度:
如果要監視動畫,要用到Storyboard的一些事件。在這裏使用的是CurrentTimeInvalidated事件,每次向前移動動畫時鐘都會引發該事件。當引發CurrentTimeInvalidated事件時,發送者是Clock對象(Color類位於System.Windows.Media.Animation名稱空間中),可通過Clock對象檢索當前時間。當前時間使用TimeSpan對象表示,並且可檢索當前進度,當前進度使用0~1之間的數值表示。
後臺代碼:
就是在上面的例子中爲故事板加一個CurrentTimeInvalidated事件,然後再界面中放一個label控件(用於顯示時間)和ProgressBar(用於顯示進度,最大值爲1,最小值爲0)控件。
private void Storyboard_CurrentTimeInvalidated(object sender, EventArgs e)
{
Clock storyboardClock = (Clock)sender;
if (storyboardClock.CurrentProgress == null)
{
lblTime.Content = "";
progressBar1.Value = 0;
}
else
{
lblTime.Content = storyboardClock.CurrentTime.ToString();
progressBar1.Value = (double)storyboardClock.CurrentProgress;
}
}
13、動畫緩動。
線性動畫有一個缺點,通常讓人覺得機械和不夠自然。改進動畫並創建更趨自然的動畫的祕訣是改變變化速率。不是創建以固定不變的速率改變屬性的動畫,而是需要設計根據某種方式加速或減速的動畫,實現更趨自然的動畫的最簡單方法是使用預置的緩動函數(EasingFunction)。EasyingFunction屬性只能接受單個緩動函數對象,所以不能爲同一個動畫結合不同的緩動函數。
xaml代碼
<Window.Resources>
<Style TargetType="Button">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Width">
<DoubleAnimation To="300" Duration="0:0:5">
<!--使用緩動函數-->
<DoubleAnimation.EasingFunction>
<!--設置緩動模式和振盪次數-->
<ElasticEase EasingMode="EaseOut" Oscillations="5"></ElasticEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Button Width="150" Height="50" Content="緩動動畫" FontSize="20"></Button>
</Grid>
14、緩動函數類。
在繼續分析不同的緩動類之前,理解緩動函數的應用時機是很重要的。所有的緩動函數類都繼承自EasingFunctionBase類,並且繼承了EasingMode屬性,EasingMode有三種值,分別是:EasyIn(在動畫開始時應用緩動效果)、EasyOut(動畫結束時應用緩動效果)和EasyInOut(在開始和結束時應用緩動動畫)。當應用緩動函數時不會改變動畫的持續時間。
15、自定義緩動函數。
創建自定義緩動函數一般需要以下幾個步驟:
a)、新建一個類,讓其繼承自EasingFunctionBase類。
b)、重寫EaseInCore()方法和CreateInstanceCore()方法。
c)、定義依賴屬性。
d)、引用。
後臺代碼(自定義類):
public class RandomJitterEase : EasingFunctionBase
{
//聲明一個Random類,用於聲明隨機數。
Random rand = new Random();
/// <summary>
/// 重寫EaseCore方法。
/// </summary>
/// <param name="normalizedTime"></param>
/// <returns></returns>
protected override double EaseInCore(double normalizedTime)
{
//幾乎所有邏輯代碼都在EaseInCore方法中運行。該方法接受一個規範化的時間值,本質上是表示動畫進度從
//0到1之間的值,當動畫開始時,規範化的時間值是0,它從該點開始增加,直到在動畫結束點達到1.
//在動畫運行期間,每次更新動畫的值時,WPF都會調用EaseInCore方法,確切的調用頻率取決於動畫的幀率。
if (normalizedTime == 1)
{
return 1;
}
else
{
return Math.Abs(normalizedTime - (double)rand.Next(0, 10) / (2010 - Jitter));
}
}
protected override System.Windows.Freezable CreateInstanceCore()
{
return new RandomJitterEase();
}
//定義一個依賴屬性。
public static readonly DependencyProperty JitterProperty;
//在靜態方法中註冊依賴屬性。
static RandomJitterEase()
{
JitterProperty = DependencyProperty.Register("Jitter", typeof(int), typeof(RandomJitterEase), new UIPropertyMetadata(1000), new ValidateValueCallback(ValidateJitter));
}
public int Jitter
{
get { return (int)GetValue(JitterProperty); }
set { SetValue(JitterProperty, value); }
}
//此方法用於判斷值。
private static bool ValidateJitter(object value)
{
int jitterValue = (int)value;
if (jitterValue <= 2000 && jitterValue >= 0)
{
return true;
}
else
{
return false;
}
}
}
xaml代碼:
<Window x:Class="自定義緩動函數.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:自定義緩動函數"
Title="MainWindow" Height="350" Width="525">
<Window.Triggers>
<!--事件觸發器,窗體加載的Loaded事件。-->
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Canvas.Left)" From="0" To="480" Duration="0:0:5"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="ellipse2" Storyboard.TargetProperty="(Canvas.Left)" From="0" To="480" Duration="0:0:5">
<DoubleAnimation.EasingFunction>
<!--調用自定義緩動函數類-->
<local:RandomJitterEase EasingMode="EaseIn" Jitter="1500"></local:RandomJitterEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Canvas ClipToBounds="True">
<Ellipse Name="ellipse1" Width="25" Height="25" Fill="Red"></Ellipse>
<Ellipse Margin="0,70,0,0" Name="ellipse2" Width="25" Height="25" Fill="Green"></Ellipse>
</Canvas>
</Window>
16、WPF動畫性能和幀率。
通常,爲用戶界面應用動畫,只不過是創建並配置正確的動畫和故事版對象。但在其他情況下,特別是同時發生多個動畫時,可能更加需要關注性能。WPF試圖保持以60幀/秒的速度進行動畫,可以確保從開始到結束得到平滑流暢的動畫。幀速率越低,會發生抖動現象。幀速率越高,佔用的CPU也就越高。通過TimeLine.DesiredFrameRate屬性進行調整。
xaml代碼:
<Window x:Class="動畫性能之幀率.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:動畫性能之幀率"
Title="MainWindow" Height="500" Width="525">
<Window.Triggers>
<!--定義一個事件觸發器,通過SourceName屬性關聯button-->
<EventTrigger RoutedEvent="Button.Click" SourceName="btn_start">
<EventTrigger.Actions>
<BeginStoryboard>
<!--通過Timeline.DesiredFrameRate屬性設置幀速率-->
<Storyboard Storyboard.TargetName="ellipse" Timeline.DesiredFrameRate="{Binding ElementName=txtBox1, Path=Text}">
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" From="0" To="300" Duration="0:0:10"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" From="0" To="250" Duration="0:0:10"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid ShowGridLines="False">
<Grid.RowDefinitions>
<RowDefinition Height="5*"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions >
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Canvas ClipToBounds="True" Grid.Row="0" Grid.ColumnSpan="2" Height="320" Background="Beige">
<Ellipse Name="ellipse" Fill="Red" Width="10" Height="10"></Ellipse>
</Canvas>
<Label Grid.Row="1" Content="幀速率:" FontSize="20" HorizontalAlignment="Right" VerticalAlignment="Center"></Label>
<TextBox Name="txtBox1" Text="1" Width="60" Height="30" FontSize="20" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBox>
<Button Name="btn_start" Grid.Row="2" Grid.ColumnSpan="2" Width="200" Height="60" Content="點擊動畫" FontSize="20"></Button>
</Grid>
</Window>