腳本概觀

更新:2007 年 11 月

本主題顯示如何使用 Storyboard 物件組織和套用動畫。內容說明如何以互動方式管理 Storyboard 物件,並且說明間接屬性目標語法。

必要條件

若要了解本主題,您應該熟悉不同的動畫類型及其基本功能。如需動畫功能的簡介,請參閱動畫概觀。您也應該知悉如何使用附加屬性。如需附加屬性的詳細資訊,請參閱附加屬性概觀

什麼是腳本

動畫不是唯一有用的時刻表類型,還有其他時刻表類別可以協助您組織時刻表集合,以及將時刻表套用至屬性。容器 (Container) 時刻表衍生自 TimelineGroup 類別,並且包含 ParallelTimelineStoryboard

Storyboard 是一種容器時刻表,可提供所含時刻表的目標資訊。腳本 (Storyboard) 可以包含任何類型的 Timeline,包括其他容器時刻表和動畫。Storyboard 物件可以讓您將影響各項物件和屬性的時刻表合併成單一時刻表樹狀目錄,以更輕鬆地組織和控制複雜的時間行為。例如,假設您想要某個按鈕執行下列三項動作。

  • 在使用者選取按鈕時放大及變更色彩。

  • 在按一下時縮小再放大回原始大小。

  • 在按鈕停用時縮小並呈現 50 % 不透明度。

在這個案例中,您有多組動畫套用至同一個物件,並且想要視按鈕的狀態在不同時間加以播放。Storyboard 物件可以讓您組織動畫,並且將動畫以群組套用至一個或多個物件。

何處可以使用腳本

Storyboard 可以利用可展示動畫的類別的相依性屬性建立動畫 (如需可展示動畫的類別有何特色的詳細資訊,請參閱動畫概觀)。但是,因為腳本是架構層級的功能,所以物件必須屬於 FrameworkElementFrameworkContentElementNameScope

例如,您可以使用 Storyboard 達到下列目的:

但是,您無法在 Storyboard 中使用符合下列兩種情況的 SolidColorBrush 來建立動畫:未向 FrameworkElementFrameworkContentElement 註冊其名稱,或未用以設定 FrameworkElementFrameworkContentElement 的屬性。

如何以腳本套用動畫

若要使用 Storyboard 組織和套用動畫,請將動畫加入為 Storyboard 的子時刻表。Storyboard 類別提供 Storyboard.TargetNameStoryboard.TargetProperty 附加屬性。設定動畫的這些屬性以指定動畫的目標物件和屬性。

若要將動畫套用至其目標,請使用觸發程序動作或方法來開始 Storyboard。在 XAML 中,可以使用 BeginStoryboard 物件並搭配 EventTriggerTriggerDataTrigger。在程式碼中,則還可以使用 Begin 方法。

下表顯示每種 Storyboard 開始方法適用的不同位置:個別執行個體 (Per-instance)、樣式、控制項樣板及資料範本。「個別執行個體」是指將動畫或腳本直接套用至物件執行個體而非套用至樣式、控制項樣板或資料範本的方法。

開始使用腳本的方法…

個別執行個體

樣式

控制項樣板

資料範本

範例

BeginStoryboardEventTrigger

可以

可以

可以

可以

HOW TO:使用腳本建立屬性的動畫

BeginStoryboard 和屬性 Trigger

不可以

可以

可以

可以

HOW TO:當屬性值變更時觸發動畫

BeginStoryboardDataTrigger

不可以

可以

可以

可以

HOW TO:資料變更時觸發動畫

Begin 方法

可以

不可以

不可以

不可以

HOW TO:使用腳本建立屬性的動畫

下列範例會使用 StoryboardRectangle 項目的 Width,以及用於繪製該 RectangleSolidColorBrushColor 來建立動畫。

<!-- This example shows how to animate with a storyboard.-->
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.Samples.Animation.StoryboardsExample" 
  WindowTitle="Storyboards Example">
  <StackPanel Margin="20">

    <Rectangle Name="MyRectangle"
      Width="100"
      Height="100">
      <Rectangle.Fill>
        <SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
      </Rectangle.Fill>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseEnter">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation 
                Storyboard.TargetName="MyRectangle"
                Storyboard.TargetProperty="Width"
                From="100" To="200" Duration="0:0:1" />

              <ColorAnimation 
                Storyboard.TargetName="MySolidColorBrush"
                Storyboard.TargetProperty="Color"
                From="Blue" To="Red" Duration="0:0:1" />  
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle> 
  </StackPanel>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Data;
using System.Windows.Shapes;
using System.Windows.Input;


namespace Microsoft.Samples.Animation
{
    public class StoryboardsExample : Page
    {      
        public StoryboardsExample()
        {
            this.WindowTitle = "Storyboards Example";
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(20);

            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "MyRectangle";

            // Create a name scope for the page.
            NameScope.SetNameScope(this, new NameScope());            

            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Blue);
            this.RegisterName("MySolidColorBrush", mySolidColorBrush);
            myRectangle.Fill = mySolidColorBrush;

            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 100;
            myDoubleAnimation.To = 200;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation, 
                new PropertyPath(Rectangle.WidthProperty));

            ColorAnimation myColorAnimation = new ColorAnimation();
            myColorAnimation.From = Colors.Blue;
            myColorAnimation.To = Colors.Red;
            myColorAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTargetName(myColorAnimation, "MySolidColorBrush");
            Storyboard.SetTargetProperty(myColorAnimation, 
                new PropertyPath(SolidColorBrush.ColorProperty)); 
            Storyboard myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            myStoryboard.Children.Add(myColorAnimation);

            myRectangle.MouseEnter += delegate(object sender, MouseEventArgs e)
            {
                myStoryboard.Begin(this);
            };

            myStackPanel.Children.Add(myRectangle);
            this.Content = myStackPanel;
        } 
    }
}

下列章節會詳細說明 TargetNameTargetProperty 附加屬性。

以架構項目、架構內容項目和 Freezable 為目標

前面一節曾提到,動畫要找到目標,就必須知悉目標的名稱和要建立動畫的屬性。指定要建立動畫的屬性相當簡單,只要以要建立動畫的屬性名稱設定 Storyboard.TargetProperty 即可。至於要建立動畫的屬性所屬的物件名稱,則是透過設定動畫的 Storyboard.TargetName 屬性來指定。

若要成功使用 TargetName 屬性,目標物件必須有名稱。指派名稱給 XAML 中的 FrameworkElementFrameworkContentElement,與指派名稱給 Freezable 物件是不同的。

架構項目是繼承自 FrameworkElement 類別的類別。架構項目的範例包括 WindowDockPanelButtonRectangle。基本上所有視窗、面板和控制項都是項目。架構內容項目是繼承自 FrameworkContentElement 類別的類別。架構內容項目的範例包括 FlowDocumentParagraph。如果您不確定某個型別是否為架構項目或架構內容項目,請檢查其是否有 Name 屬性。如果有,可能是架構項目或架構內容項目。若要進一步確定,請檢查其型別頁面的「<legacyBold>繼承階層架構</legacyBold>」一節。

若要能夠在 XAML 中以架構項目或架構內容項目為目標,請設定該項目的 Name 屬性。在程式碼中,您也必須使用 RegisterName 方法,將項目名稱註冊至您已建立 NameScope 的項目。

下列取自上一個範例的範例會指派名稱 MyRectangle 給 Rectangle,這是一種 FrameworkElement

<Rectangle Name="MyRectangle"
  Width="100"
  Height="100">
Rectangle myRectangle = new Rectangle();
myRectangle.Name = "MyRectangle";

// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope());            

this.RegisterName(myRectangle.Name, myRectangle);

指派名稱給項目之後,就可以用該項目的屬性建立動畫。

<DoubleAnimation 
  Storyboard.TargetName="MyRectangle"
  Storyboard.TargetProperty="Width"
  From="100" To="200" Duration="0:0:1" />
Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
Storyboard.SetTargetProperty(myDoubleAnimation, 
    new PropertyPath(Rectangle.WidthProperty));

Freezable 型別是繼承自 Freezable 類別的類別。Freezable 的範例包括 SolidColorBrushRotateTransformGradientStop

若要在 XAML 中使 Freezable 能夠做為動畫的目標,請使用 x:Name 屬性指派名稱。在程式碼中,則是使用 RegisterName 方法,將名稱註冊至您已建立 NameScope 的項目。

下列範例會指派名稱給 Freezable 物件。

<SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Blue);
this.RegisterName("MySolidColorBrush", mySolidColorBrush);

然後物件可以就做為動畫的目標。

<ColorAnimation 
  Storyboard.TargetName="MySolidColorBrush"
  Storyboard.TargetProperty="Color"
  From="Blue" To="Red" Duration="0:0:1" />  
Storyboard.SetTargetName(myColorAnimation, "MySolidColorBrush");
Storyboard.SetTargetProperty(myColorAnimation, 
    new PropertyPath(SolidColorBrush.ColorProperty)); 

Storyboard 物件會使用名稱範圍來解析 TargetName 屬性。如需 WPF 名稱範圍的詳細資訊,請參閱 WPF 命名範圍。如果省略 TargetName 屬性,則動畫會以定義了該動畫的項目為目標,如果動畫定義在樣式中,則以套用該樣式的項目為目標。

有時候無法指派名稱給 Freezable 物件。例如,如果 Freezable 被宣告為資源或是被用於設定樣式中的屬性值,就不能有名稱。沒有名稱就不能直接做為目標,但是可以間接做為目標。下列章節說明如何使用間接目標。

間接目標

有時候 Freezable 無法讓動畫直接做為目標,例如當 Freezable 被宣告為資源或是被用於設定樣式中的屬性值的時候。在這些情況中,即使無法直接做為目標,仍然可以以 Freezable 物件建立動畫,方法是指定 Freezable 所屬項目的名稱,而不是以 Freezable 的名稱設定 TargetName 屬性。例如,有個 SolidColorBrush 用於設定矩形項目的 Fill 並且屬於該矩形。若要建立這個筆刷的動畫,可以用屬性鏈結設定動畫的 TargetProperty,這個屬性鏈結以 Freezable 所設定之架構項目或架構內容項目的屬性開始,以要建立動畫的 Freezable 屬性結尾。

<ColorAnimation 
  Storyboard.TargetName="Rectangle01"
  Storyboard.TargetProperty="Fill.Color"
  From="Blue" To="AliceBlue" Duration="0:0:1" />
DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath);

請注意,如果 Freezable 凍結,則會建立複製品 (Clone),並以該複製品建立動畫。發生這種情況時,原始物件的 HasAnimatedProperties 屬性會繼續傳回 false,因為實際並未以原始物件建立動畫。如需複製 (Clone) 的詳細資訊,請參閱 Freezable 物件概觀

同時請注意,使用間接屬性目標時可以以不存在的物件為目標。例如,您可能會假設特定按鈕的 Background 是以 SolidColorBrush 設定,而嘗試以這個筆刷的色彩 (Color) 建立動畫,但實際上 LinearGradientBrush 是用於設定按鈕的背景 (Background)。在這些情況中,不會擲回例外狀況,而動畫不會產生視覺效果,因為 LinearGradientBrush 不會回應 Color 屬性的變更。

下列章節會詳細說明間接屬性目標語法。

在 XAML 中間接以 Freezable 的屬性為目標

若要在 XAML 中以 Freezable 的屬性為目標,請使用下列語法。

ElementPropertyName.FreezablePropertyName

項目

下列程式碼顯示如何以用於設定下列項目之 SolidColorBrushColor 來建立動畫:

矩形項目的 Fill

<Rectangle
  Name="Rectangle01"
  Height="100"
  Width="100"
  Fill="{StaticResource MySolidColorBrushResource}">
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <ColorAnimation 
            Storyboard.TargetName="Rectangle01"
            Storyboard.TargetProperty="Fill.Color"
            From="Blue" To="AliceBlue" Duration="0:0:1" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

有時候您需要以包含在集合或陣列中的 Freezable 為目標。

若要以包含在集合中的 Freezable 為目標,請使用下列路徑語法。

ElementPropertyName.Children[CollectionIndex].FreezablePropertyName

其中 CollectionIndex 是物件在其陣列或集合中的索引。

例如,假設矩形的 RenderTransform 屬性套用了 TransformGroup 資源,而您想要以該資源包含的其中一個轉換建立動畫。

<TransformGroup x:Key="MyTransformGroupResource"
  x:Shared="False">
  <ScaleTransform />
  <RotateTransform />
</TransformGroup>

下列程式碼顯示如何以上一個範例中 RotateTransformAngle 屬性建立動畫。

<Rectangle
  Name="Rectangle02"
  Height="100"
  Width="100"
  Fill="Blue"
  RenderTransform="{StaticResource MyTransformGroupResource}">
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation 
            Storyboard.TargetName="Rectangle02"
            Storyboard.TargetProperty="RenderTransform.Children[1].Angle"
            From="0" To="360" Duration="0:0:1" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>  

在程式碼中間接以 Freezable 的屬性為目標

在程式碼中,請建立 PropertyPath 物件。當您建立 PropertyPath 時,會指定 PathPathParameters

若要建立 PathParameters,請建立 DependencyProperty 型別的陣列,其中要包含相依性屬性識別項欄位的清單。第一個識別項欄位代表用以設定 FreezableFrameworkElementFrameworkContentElement 的屬性。下一個識別項欄位代表要做為目標之 Freezable 的屬性。請將它想像為連接 FreezableFrameworkElement 物件的屬性鏈結。

以下是以 SolidColorBrush (這個筆刷用以設定矩形項目的 Fill) 的 Color為目標的相依性屬性鏈結範例。

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};

您也需要指定 PathPathString,負責告知 Path 如何解譯其 PathParameters。它會使用下列語法。

(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

項目

下列範例顯示伴隨上一個範例中定義之 PathParametersPath

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";

下列範例結合前述範例的程式碼,會以 SolidColorBrush (這個筆刷用以設定矩形項目的 Fill) 的 Color 建立動畫。

// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope()); 

Rectangle rectangle01 = new Rectangle();
rectangle01.Name = "Rectangle01";   
this.RegisterName(rectangle01.Name, rectangle01);
rectangle01.Width = 100;
rectangle01.Height = 100;
rectangle01.Fill = 
    (SolidColorBrush)this.Resources["MySolidColorBrushResource"];

ColorAnimation myColorAnimation = new ColorAnimation();
myColorAnimation.From = Colors.Blue;
myColorAnimation.To = Colors.AliceBlue;
myColorAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTargetName(myColorAnimation, rectangle01.Name);

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath);

Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myColorAnimation);
BeginStoryboard myBeginStoryboard = new BeginStoryboard();
myBeginStoryboard.Storyboard = myStoryboard;
EventTrigger myMouseEnterTrigger = new EventTrigger();
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent;
myMouseEnterTrigger.Actions.Add(myBeginStoryboard);
rectangle01.Triggers.Add(myMouseEnterTrigger);

有時候您需要以包含在集合或陣列中的 Freezable 為目標。例如,假設矩形的 RenderTransform 屬性套用了 TransformGroup 資源,而您想要以該資源包含的其中一個轉換建立動畫。

<TransformGroup x:Key="MyTransformGroupResource"
  x:Shared="False">
  <ScaleTransform />
  <RotateTransform />
</TransformGroup>  

若要以包含在集合中的 Freezable 為目標,請使用下列路徑語法。

(OwnerPropertyArrayIndex).(CollectionChildrenPropertyArrayIndex)[CollectionIndex].(FreezablePropertyArrayIndex)

其中 CollectionIndex 是物件在其陣列或集合中的索引。

若要以 RotateTransform (TransformGroup 中的第二個轉換) 的 Angle 屬性為目標,請使用下列 PathPathParameters

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {
            Rectangle.RenderTransformProperty, 
            TransformGroup.ChildrenProperty,
            RotateTransform.AngleProperty
        };
string thePath = "(0).(1)[1].(2)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath);

下列範例顯示以 TransformGroup 中之 RotateTransformAngle 建立動畫時的完整程式碼。

Rectangle rectangle02 = new Rectangle();
rectangle02.Name = "Rectangle02";
this.RegisterName(rectangle02.Name, rectangle02);
rectangle02.Width = 100;
rectangle02.Height = 100;
rectangle02.Fill = Brushes.Blue;
rectangle02.RenderTransform = 
    (TransformGroup)this.Resources["MyTransformGroupResource"];

DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 0;
myDoubleAnimation.To = 360;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTargetName(myDoubleAnimation, rectangle02.Name);

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {
            Rectangle.RenderTransformProperty, 
            TransformGroup.ChildrenProperty,
            RotateTransform.AngleProperty
        };
string thePath = "(0).(1)[1].(2)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath);

Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myDoubleAnimation);
BeginStoryboard myBeginStoryboard = new BeginStoryboard();
myBeginStoryboard.Storyboard = myStoryboard;
EventTrigger myMouseEnterTrigger = new EventTrigger();
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent;
myMouseEnterTrigger.Actions.Add(myBeginStoryboard);
rectangle02.Triggers.Add(myMouseEnterTrigger);

以 Freezable 做為開始點的間接目標

前面幾節說明了一種間接以 Freezable 為目標的方式,也就是以 FrameworkElementFrameworkContentElement 為開頭,然後建立屬性鏈結連到 Freezable 子屬性。您也可以使用 Freezable 做為開始點,然後間接以其中一個 Freezable 子屬性做為間接目標。使用 Freezable 做為間接目標的開始點時還有一個額外的限制:做為開始點的 Freezable,以及在它與要間接做為目標子屬性之間的每個 Freezable 都不能凍結。

在 XAML 中以互動方式控制腳本

若要在可延伸標記語言 (XAML) 中開始腳本,請使用 BeginStoryboard 觸發程序動作。BeginStoryboard 會將動畫分派給物件和目標屬性,然後啟動腳本 (如需這個程序的詳細資訊,請參閱動畫和計時系統概觀)。如果您藉由指定 BeginStoryboardName 屬性來指派名稱,它就會成為可控制的腳本。在腳本啟動後,您就可以用互動方式控制腳本。以下是可控制的腳本動作的清單,您可以將這些動作與事件觸發搭配使用以控制腳本。

下列範例中會使用可控制的腳本動作以互動方式控制腳本。

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.SDK.Animation.ControllableStoryboardExample"
  WindowTitle="Fading Rectangle Example">
  <StackPanel Margin="10">

    <Rectangle
      Name="MyRectangle"
      Width="100" 
      Height="100"
      Fill="Blue">
    </Rectangle>

    <Button Name="BeginButton">Begin</Button>
    <Button Name="PauseButton">Pause</Button>
    <Button Name="ResumeButton">Resume</Button>
    <Button Name="SkipToFillButton">Skip To Fill</Button>
    <Button Name="StopButton">Stop</Button>

    <StackPanel.Triggers>
      <EventTrigger RoutedEvent="Button.Click" SourceName="BeginButton">
        <BeginStoryboard Name="MyBeginStoryboard">
          <Storyboard>
            <DoubleAnimation
              Storyboard.TargetName="MyRectangle" 
              Storyboard.TargetProperty="(Rectangle.Opacity)"
              From="1.0" To="0.0" Duration="0:0:5" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="PauseButton">
        <PauseStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="ResumeButton">
        <ResumeStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="SkipToFillButton">
        <SkipStoryboardToFill BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="StopButton">
        <StopStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
    </StackPanel.Triggers>
  </StackPanel>
</Page>

使用程式碼以互動方式控制腳本

前述範例顯示如何使用觸發程序動作進行動畫顯示。在程式碼中,您也可以使用 Storyboard 類別的互動方法來控制腳本。對於要在程式碼中以互動方式控制的 Storyboard,必須使用腳本之 Begin方法的適當多載,並指定 true 使該腳本變成可控制的。如需詳細資訊,請參閱 Begin(FrameworkElement, Boolean) 頁面。

下列清單顯示的方法,可用於管理已啟動的 Storyboard

使用這些方法的優點是您不需要建立 TriggerTriggerAction 物件,只要參考您要管理的可控制的 Storyboard 即可。

注意:所有在 Clock 上執行的互動動作 (也等於是在 Storyboard 上執行的互動動作) 會在時間引擎跳到下一個時間時執行,然後很快就會執行下次的呈現作業。例如,如果您使用 Seek 方法跳至動畫中的其他點,屬性值不會立即變更,而是在時間引擎跳到下一個時間時變更。

下列範例顯示如何使用 Storyboard 類別的互動方法套用和控制動畫。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace SDKSample
{

    public class ControllableStoryboardExample : Page
    {
        private Storyboard myStoryboard;

        public ControllableStoryboardExample()
        {

            // Create a name scope for the page.

            NameScope.SetNameScope(this, new NameScope()); 

            this.WindowTitle = "Controllable Storyboard Example";
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(10);

            // Create a rectangle.
            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "myRectangle";

            // Assign the rectangle a name by 
            // registering it with the page, so that
            // it can be targeted by storyboard
            // animations.
            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            myRectangle.Fill = Brushes.Blue;
            myStackPanel.Children.Add(myRectangle);

            //
            // Create an animation and a storyboard to animate the
            // rectangle.
            //
            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 1.0;
            myDoubleAnimation.To = 0.0;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(5000));
            myDoubleAnimation.AutoReverse = true;

            // Create the storyboard.
            myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.OpacityProperty));

            //
            // Create some buttons to control the storyboard
            // and a panel to contain them.
            //
            StackPanel buttonPanel = new StackPanel();
            buttonPanel.Orientation = Orientation.Horizontal;
            Button beginButton = new Button();
            beginButton.Content = "Begin";
            beginButton.Click += new RoutedEventHandler(beginButton_Clicked);
            buttonPanel.Children.Add(beginButton);
            Button pauseButton = new Button();
            pauseButton.Content = "Pause";
            pauseButton.Click += new RoutedEventHandler(pauseButton_Clicked);
            buttonPanel.Children.Add(pauseButton);
            Button resumeButton = new Button();
            resumeButton.Content = "Resume";
            resumeButton.Click += new RoutedEventHandler(resumeButton_Clicked);
            buttonPanel.Children.Add(resumeButton);
            Button skipToFillButton = new Button();
            skipToFillButton.Content = "Skip to Fill";
            skipToFillButton.Click += new RoutedEventHandler(skipToFillButton_Clicked);
            buttonPanel.Children.Add(skipToFillButton);
            Button setSpeedRatioButton = new Button();
            setSpeedRatioButton.Content = "Triple Speed";
            setSpeedRatioButton.Click += new RoutedEventHandler(setSpeedRatioButton_Clicked);
            buttonPanel.Children.Add(setSpeedRatioButton);
            Button stopButton = new Button();
            stopButton.Content = "Stop";
            stopButton.Click += new RoutedEventHandler(stopButton_Clicked);
            buttonPanel.Children.Add(stopButton);
            myStackPanel.Children.Add(buttonPanel);
            this.Content = myStackPanel;        


        }

        // Begins the storyboard.
        private void beginButton_Clicked(object sender, RoutedEventArgs args)
        {
            // Specifying "true" as the second Begin parameter
            // makes this storyboard controllable.
            myStoryboard.Begin(this, true);

        }

        // Pauses the storyboard.
        private void pauseButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Pause(this);

        }

        // Resumes the storyboard.
        private void resumeButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Resume(this);

        }

        // Advances the storyboard to its fill period.
        private void skipToFillButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.SkipToFill(this);

        }

        // Updates the storyboard's speed.
        private void setSpeedRatioButton_Clicked(object sender, RoutedEventArgs args)
        {
            // Makes the storyboard progress three times as fast as normal.
            myStoryboard.SetSpeedRatio(this, 3);

        }

        // Stops the storyboard.
        private void stopButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Stop(this);

        }         

    }

}

在樣式中使用動畫

您可以在 Style 中使用 Storyboard 物件來定義動畫。在 Style 中使用 Storyboard 建立動畫,與在別處使用 Storyboard 類似,除了下列三點例外:

  • 您不會指定 TargetNameStoryboard 一律會以套用該 Style 的屬性為目標。若要以 Freezable 物件為目標,您必須使用間接目標。如需間接目標的詳細資訊,請參閱間接目標一節。

  • 您不能指定 EventTriggerTriggerSourceName

  • 您不能使用動態資源參考或資料繫結運算式設定 Storyboard 或動畫屬性值。這是因為 Style 內的每個項目都必須是安全執行緒 (Thread-Safe) 的,而且計時系統必須凍結 (Freeze) Storyboard 物件才能讓這些項目是安全執行緒的。Storyboard 或其子時刻表如果包含動態資源參考或資料繫結運算式,就不能凍結。如需凍結和其他 Freezable 功能的詳細資訊,請參閱 Freezable 物件概觀

  • 在 XAML 中,您不能針對 Storyboard 或動畫事件宣告事件處理常式。

如需如何在樣式中定義腳本的範例,請參閱 HOW TO:在樣式中建立動畫範例。

在 ControlTemplate 中建立動畫

您可以在 ControlTemplate 中使用 Storyboard 物件來定義動畫。在 ControlTemplate 中使用 Storyboard 建立動畫,與在別處使用 Storyboard 類似,除了下列三點例外:

如需如何在 ControlTemplate 中定義腳本的範例,請參閱 HOW TO:在 ControlTemplate 中建立動畫範例。

在屬性值變更時產生動畫

在樣式和控制項樣板中,您可以使用 Trigger 物件在屬性變更時啟動腳本。如需詳細資訊,請參閱 HOW TO:當屬性值變更時觸發動畫HOW TO:在 ControlTemplate 中建立動畫

由屬性 Trigger 物件套用的動畫,行為比 EventTrigger 動畫或使用 Storyboard 方法啟動的動畫更為複雜。它們以其他 Trigger 物件定義,但是是由 EventTrigger 和方法觸發動畫組成的動畫「傳遞」。

請參閱

概念

動畫概觀

建立屬性動畫技術概觀

Freezable 物件概觀