WPF 動畫系統

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>

在這裏插入圖片描述

轉載自:https://www.cnblogs.com/xiezunxu/articles/8965848.html:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章