演示图板概述

本主题演示如何使用 Storyboard 对象来组织和应用动画。 它介绍了如何以交互方式操作 Storyboard 对象并描述间接属性目标语法。

必备条件

若要了解本主题,应熟悉不同的动画类型及其基本功能。 有关动画的简介,请参阅动画概述。 还应了解如何使用附加属性。 有关附加属性的详细信息,请参阅附加属性概述

什么是情节提要

动画并非唯一有用的时间线类型。 还提供了其他时间线类来帮助组织时间线集,并将时间线应用于属性。 容器时间线派生自 TimelineGroup 类,并包括 ParallelTimelineStoryboard

Storyboard是一种为其所包含的时间线提供目标信息的容器时间线。 情节提要可以包含任何类型 Timeline ,包括其他容器时间线和动画。 Storyboard 使用对象,您可以将影响各种对象和属性的时间线合并为单个时间线树,以便于组织和控制复杂的计时行为。 例如,假设需要一个执行以下三个操作的按钮。

  • 当用户选择该按钮时,按钮增大并更改颜色。

  • 当用户单击该按钮时,按钮缩小并恢复其原始大小。

  • 当该按钮变为禁用状态时,按钮缩小且不透明度缩减到 50%。

在此情况下,有多组动画适用于同一对象,并且需要根据按钮的状态在不同的时间播放它们。 Storyboard 使用对象可以组织动画并将它们按组应用到一个或多个对象。

在哪里可以使用情节提要

Storyboard可用于对动画处理类的依赖属性进行动画处理 (有关如何动画处理类的详细信息,请参阅动画概述) 。 但是,因为情节提要是一个框架级别功能,所以该对象必须属于 NameScope FrameworkElement 或的 FrameworkContentElement

例如,你可以使用 Storyboard 来执行以下操作:

但是,您不能使用 Storyboard 对未向或注册其名称的进行动画处理,也不能使用来 SolidColorBrush FrameworkElement FrameworkContentElement 设置或的属性 FrameworkElement FrameworkContentElement

如何使用情节提要应用动画

若要使用 Storyboard 来组织和应用动画,请将动画添加为的子时间线 StoryboardStoryboard类提供 Storyboard.TargetName Storyboard.TargetProperty 属性和附加属性。 可以在动画上设置这些属性以指定其目标对象和属性。

若要将动画应用于其目标,请 Storyboard 使用触发器操作或方法开始。 在中 XAML ,可以使用 BeginStoryboard 具有 EventTrigger 、或的对象 Trigger DataTrigger 。 在代码中,还可以使用 Begin 方法。

下表显示支持每个开始技术的不同位置 Storyboard :每个实例、样式、控件模板和数据模板。 “基于实例”是指直接将动画或情节提要应用于对象实例(而不是在样式、控件模板或数据模板中应用)的技术。

情节提要开始时使用… 基于实例 Style 控件模板 数据模板 示例
BeginStoryboardEventTrigger 使用情节提要对属性进行动画处理
BeginStoryboard 和属性 Trigger 在属性值更改时触发动画
BeginStoryboard 和属性 MultiTrigger MultiTrigger 类示例
BeginStoryboardDataTrigger 如何:在数据更改时触发动画
BeginStoryboardMultiDataTrigger MultiDataTrigger 类示例
Begin 方法 使用情节提要对属性进行动画处理

下面的示例使用 Storyboard 对某个元素的 Width RectangleColor SolidColorBrush 用于绘制该 Rectangle 的的的。

<!-- This example shows how to animate with a storyboard.-->
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://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;
        }
    }
}

以下部分 TargetName TargetProperty 更详细地介绍了和附加属性。

以框架元素、框架内容元素和 Freezable 元素为目标

上一节提到过,对于要查找其目标的动画,必须知道目标的名称和要进行动画处理的属性。 指定要进行动画处理的属性是一种直接的方式:只需 TargetProperty 用要进行动画处理的属性的名称进行设置。 通过设置动画的属性,指定要为其设置动画的属性的对象的名称 Storyboard.TargetName

注意

尽管可以使用 Target 属性直接绑定到对象作为的替代项 TargetName ,但它不能序列化。 不保证 Target 可以在 XAML 中正确地引用该对象。

要使 TargetName 属性正常工作,目标对象必须具有名称。 为 FrameworkElement 或在中分配名称与 FrameworkContentElement 为 XAML 对象分配名称不同 Freezable

框架元素是从类继承的类 FrameworkElement 。 框架元素的示例包括 WindowDockPanelButtonRectangle 。 实质上,所有窗口、面板和控件都是元素。 框架内容元素是从类继承的类 FrameworkContentElement 。 框架内容元素的示例包括 FlowDocumentParagraph 。 如果不确定某个类型是框架元素还是框架内容元素,请查看它是否具有 Name 属性。 如果具有 Name 属性,则可能是框架元素或框架内容元素。 若要进一步确定,请检查其类型页面的“继承性分层”部分。

若要在中启用框架元素或框架内容元素的目标 XAML ,请设置其 Name 属性。 在代码中,还需要使用 RegisterName 方法来向已为其创建的元素注册元素的名称 NameScope

下面的示例摘自前面的示例,它为指定了名称 MyRectangle a 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

若要 Freezable 在中启用动画的目标 XAML ,可以使用 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 XAML 名称范围。 如果 TargetName 省略该属性,则动画将以定义它的元素为目标; 对于样式为样式的元素。

有时,不能将名称分配给 Freezable 对象。 例如,如果 Freezable 声明为资源或用于设置样式中的属性值,则不能为其指定名称。 由于该对象没有名称,因此不能直接以它为目标,但可以间接以它为目标。 下面几节描述如何使用间接目标。

间接目标

有时 Freezable 动画无法直接定位,例如,当 Freezable 声明为资源或用于设置样式中的属性值时。 在这些情况下,即使您不能直接将其作为目标,您仍然可以对对象进行动画处理 Freezable 。 不是将属性设置为的 TargetName 名称,而是 Freezable 为其提供 "所属" 的元素的名称 Freezable 。 例如, 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 冻结,将进行克隆,并对该克隆进行动画处理。 发生这种情况时,原始对象的 HasAnimatedProperties 属性将继续返回 false ,因为原始对象并未进行动画处理。 有关克隆的详细信息,请参阅 " 冻结对象概述"。

另请注意,当使用间接属性目标时,可能会以不存在的对象为目标。 例如,你可能会假设使用 Background 设置了特定按钮的, SolidColorBrush 并尝试对其颜色进行动画处理(事实上, LinearGradientBrush 使用来设置按钮的背景)。 在这些情况下,不会引发异常;由于不 LinearGradientBrush 会对属性的更改做出反应,动画无法获得可见效果 Color

下面几节详细介绍间接属性目标语法。

在 XAML 中间接以 Freezable 的属性为目标

若要以可冻结的属性为目标 XAML ,请使用以下语法。

ElementPropertyName . FreezablePropertyName

Where

下面的代码演示如何对 Color SolidColorBrush 用于设置矩形元素的的的进行动画处理 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 是对象在其数组或集合中的索引。

例如,假设某个矩形有一个 TransformGroup 应用于其属性的资源 RenderTransform ,并且您想要对它所包含的其中一个转换进行动画处理。

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

下面的代码演示如何对 Angle RotateTransform 上一个示例中所示的的属性进行动画处理。

<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 其中包含依赖项属性标识符字段的列表。 第一个标识符字段用于的属性 FrameworkElementFrameworkContentElement Freezable 用于设置的。 下一个标识符字段表示目标为的属性 Freezable 。 将其视为一系列将连接到对象的属性 Freezable FrameworkElement

下面是依赖属性链的一个示例,它 Color SolidColorBrush 以用于设置矩形元素的的为目标 Fill

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

还需要指定 PathPath String ,它指示 Path 如何解释其 PathParameters 。 它使用以下语法。

( OwnerPropertyArrayIndex ).( FreezablePropertyArrayIndex )

Where

下面的示例演示 Path PathParameters 前面的示例中定义的。

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

下面的示例合并了前面的示例中的代码,以对 Color SolidColorBrush 用于设置 Fill 矩形元素的的的进行动画处理。


// 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 为目标。 例如,假设某个矩形有一个 TransformGroup 应用于其属性的资源 RenderTransform ,并且您想要对它所包含的其中一个转换进行动画处理。

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

若要以 Freezable 集合中包含的为目标,请使用以下路径语法。

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

其中, CollectionIndex 是对象在其数组或集合中的索引。

若要面向的 Angle 属性 RotateTransform (中的第二个转换), TransformGroup 请使用以下 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);

下面的示例演示了用于对中包含的的进行动画处理的完整代码 Angle RotateTransform TransformGroup

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 通过从 FrameworkElement 或开始 FrameworkContentElement 向子属性创建属性链来间接地定位 Freezable 。 你还可以使用 Freezable 作为起点,并间接定位其 Freezable 子属性之一。 当使用作为间接目标的起点时,还可以使用另一种限制 Freezable :起始位置 Freezable 以及 Freezable 它与间接目标的子属性之间的每一个都不能冻结。

在 XAML 中以交互方式控制情节提要

若要在中启动情节提要 可扩展应用程序标记语言 (XAML) ,请使用 BeginStoryboard 触发器操作。 BeginStoryboard 将动画分发到它们动画处理的对象和属性,并启动情节提要。 (有关此过程的详细信息,请参阅 动画和计时系统概述。 ) 如果你 BeginStoryboard 通过指定其属性来提供名称 Name ,则会使其成为可控制的情节提要。 然后,可以在情节提要启动后以交互方式对它进行控制。 下面列出了可与事件触发器一起使用来控制情节提要的可控制情节提要操作。

在下面的示例中,使用可控制的情节提要操作来以交互方式控制情节提要。

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>

使用代码以交互方式控制情节提要

前面的示例已演示了如何使用触发器操作进行动画处理。 在代码中,你还可以使用类的交互式方法控制情节提要 StoryboardStoryboard若要在代码中使成为交互,必须使用情节提要的方法的适当重载, 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);
        }
    }
}

Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Shapes
Imports System.Windows.Media
Imports System.Windows.Media.Animation

Namespace SDKSample

    Public Class ControllableStoryboardExample
        Inherits Page
        Private myStoryboard As Storyboard

        Public Sub New()

            ' Create a name scope for the page.

            NameScope.SetNameScope(Me, New NameScope())

            Me.WindowTitle = "Controllable Storyboard Example"
            Dim myStackPanel As New StackPanel()
            myStackPanel.Margin = New Thickness(10)

            ' Create a rectangle.
            Dim myRectangle As 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.
            Me.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.
            '
            Dim myDoubleAnimation As 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.
            '
            Dim buttonPanel As New StackPanel()
            buttonPanel.Orientation = Orientation.Horizontal
            Dim beginButton As New Button()
            beginButton.Content = "Begin"
            AddHandler beginButton.Click, AddressOf beginButton_Clicked
            buttonPanel.Children.Add(beginButton)
            Dim pauseButton As New Button()
            pauseButton.Content = "Pause"
            AddHandler pauseButton.Click, AddressOf pauseButton_Clicked
            buttonPanel.Children.Add(pauseButton)
            Dim resumeButton As New Button()
            resumeButton.Content = "Resume"
            AddHandler resumeButton.Click, AddressOf resumeButton_Clicked
            buttonPanel.Children.Add(resumeButton)
            Dim skipToFillButton As New Button()
            skipToFillButton.Content = "Skip to Fill"
            AddHandler skipToFillButton.Click, AddressOf skipToFillButton_Clicked
            buttonPanel.Children.Add(skipToFillButton)
            Dim setSpeedRatioButton As New Button()
            setSpeedRatioButton.Content = "Triple Speed"
            AddHandler setSpeedRatioButton.Click, AddressOf setSpeedRatioButton_Clicked
            buttonPanel.Children.Add(setSpeedRatioButton)
            Dim stopButton As New Button()
            stopButton.Content = "Stop"
            AddHandler stopButton.Click, AddressOf stopButton_Clicked
            buttonPanel.Children.Add(stopButton)
            myStackPanel.Children.Add(buttonPanel)
            Me.Content = myStackPanel


        End Sub

        ' Begins the storyboard.
        Private Sub beginButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            ' Specifying "true" as the second Begin parameter
            ' makes this storyboard controllable.
            myStoryboard.Begin(Me, True)

        End Sub

        ' Pauses the storyboard.
        Private Sub pauseButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Pause(Me)

        End Sub

        ' Resumes the storyboard.
        Private Sub resumeButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Resume(Me)

        End Sub

        ' Advances the storyboard to its fill period.
        Private Sub skipToFillButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.SkipToFill(Me)

        End Sub

        ' Updates the storyboard's speed.
        Private Sub setSpeedRatioButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            ' Makes the storyboard progress three times as fast as normal.
            myStoryboard.SetSpeedRatio(Me, 3)

        End Sub

        ' Stops the storyboard.
        Private Sub stopButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Stop(Me)

        End Sub

    End Class

End Namespace

在样式中进行动画处理

可以使用 Storyboard 对象定义中的动画 Style 。 使用在中的进行动画处理 Storyboard Style 类似于在 Storyboard 其他地方使用,具有以下三个例外:

  • 不指定 TargetName ; Storyboard 始终以应用到的元素为目标 Style 。 若要以对象为目标 Freezable ,必须使用间接目标。 有关间接目标的详细信息,请参阅 间接目标 部分。

  • 不能 SourceNameEventTrigger 或指定 Trigger

  • 不能使用动态资源引用或数据绑定表达式设置 Storyboard 或动画属性值。 这是因为内的所有内容都 Style 必须是线程安全的,并且计时系统必须具有 Freeze Storyboard 对象,才能使它们线程安全。 Storyboard如果无法冻结,则为; 否则它的子时间线包含动态资源引用或数据绑定表达式。 有关冻结和其他功能的详细信息 Freezable ,请参阅 " 冻结对象概述"。

  • 在中 XAML ,不能为 Storyboard 或动画事件声明事件处理程序。

有关演示如何在样式中定义情节提要的示例,请参阅在 样式示例中进行动画处理

在 ControlTemplate 中进行动画处理

可以使用 Storyboard 对象定义中的动画 ControlTemplate 。 使用在中的进行动画处理 Storyboard ControlTemplate 类似于在 Storyboard 其他位置使用,但有以下两个例外:

有关演示如何在中定义情节提要的示例 ControlTemplate ,请参阅 system.windows.controls.controltemplate> 示例中的动画

在属性值更改时进行动画处理

在样式和控件模板中,当属性更改时,可以使用 Trigger 对象来启动情节提要。 有关示例,请参阅在 System.windows.controls.controltemplate> 中 更改属性值并对进行动画处理时触发动画。

属性对象应用的动画的 Trigger 行为方式比 EventTrigger 使用方法启动动画或动画更复杂 Storyboard 。 它们使用其他对象定义的动画 "切换" Trigger ,但使用 EventTrigger 和方法触发的动画进行组合。

请参阅