演示图板概述Storyboards Overview

本主题演示如何使用Storyboard对象来组织和应用动画。This topic shows how to use Storyboard objects to organize and apply animations. 它介绍了如何以交互Storyboard方式操作对象并描述间接属性目标语法。It describes how to interactively manipulate Storyboard objects and describes indirect property targeting syntax.

系统必备Prerequisites

若要了解本主题,应熟悉不同的动画类型及其基本功能。To understand this topic, you should be familiar with the different animation types and their basic features. 有关动画的简介,请参阅动画概述For an introduction to animation, see the Animation Overview. 还应了解如何使用附加属性。You should also know how to use attached properties. 有关附加属性的详细信息,请参阅附加属性概述For more information about attached properties, see the Attached Properties Overview.

什么是情节提要?What Is a Storyboard?

动画并非唯一有用的时间线类型。Animations are not the only useful type of timeline. 还提供了其他时间线类来帮助组织时间线集,并将时间线应用于属性。Other timeline classes are provided to help you organize sets of timelines, and to apply timelines to properties. 容器时间线派生自TimelineGroup类,并包括ParallelTimelineStoryboardContainer timelines derive from the TimelineGroup class, and include ParallelTimeline and Storyboard.

Storyboard是一种为其所包含的时间线提供目标信息的容器时间线。A Storyboard is a type of container timeline that provides targeting information for the timelines it contains. 情节提要可以包含任何类型Timeline,包括其他容器时间线和动画。A Storyboard can contain any type of Timeline, including other container timelines and animations. Storyboard使用对象,您可以将影响各种对象和属性的时间线合并为单个时间线树,以便于组织和控制复杂的计时行为。Storyboard objects enable you to combine timelines that affect a variety of objects and properties into a single timeline tree, making it easy to organize and control complex timing behaviors. 例如,假设需要一个执行以下三个操作的按钮。For example, suppose you want a button that does these three things.

  • 当用户选择该按钮时,按钮增大并更改颜色。Grow and change color when the user selects the button.

  • 当用户单击该按钮时,按钮缩小并恢复其原始大小。Shrink away and then grow back to its original size when clicked.

  • 当该按钮变为禁用状态时,按钮缩小且不透明度缩减到 50%。Shrink and fade to 50 percent opacity when it becomes disabled.

在此情况下,有多组动画适用于同一对象,并且需要根据按钮的状态在不同的时间播放它们。In this case, you have multiple sets of animations that apply to the same object, and you want to play at different times, dependent on the state of the button. Storyboard使用对象可以组织动画并将它们按组应用到一个或多个对象。Storyboard objects enable you to organize animations and apply them in groups to one or more objects.

何处可以使用情节提要?Where Can You Use a Storyboard?

可用于对动画处理类的依赖属性进行动画处理(有关如何动画处理类的详细信息,请参阅动画概述)。 StoryboardA Storyboard can be used to animate dependency properties of animatable classes (for more information about what makes a class animatable, see the Animation Overview). 但是,因为情节提要是一个框架级别功能,所以该对象必须属于NameScope FrameworkElementFrameworkContentElement的。However, because storyboarding is a framework-level feature, the object must belong to the NameScope of a FrameworkElement or a FrameworkContentElement.

例如,你可以使用Storyboard来执行以下操作:For example, you could use a Storyboard to do the following:

但是,您不能使用Storyboard对未向FrameworkElementSolidColorBrush FrameworkContentElement注册其名称的进行动画处理FrameworkElement ,也不能使用来设置或FrameworkContentElement的属性。However, you could not use a Storyboard to animate a SolidColorBrush that did not register its name with a FrameworkElement or FrameworkContentElement, or was not used to set a property of a FrameworkElement or FrameworkContentElement.

如何使用情节提要应用动画How to Apply Animations with a Storyboard

若要使用Storyboard来组织和应用动画,请将动画添加为的子时间线StoryboardTo use a Storyboard to organize and apply animations, you add the animations as child timelines of the Storyboard. 类提供属性Storyboard.TargetProperty和附加属性。 Storyboard.TargetName StoryboardThe Storyboard class provides the Storyboard.TargetName and Storyboard.TargetProperty attached properties. 可以在动画上设置这些属性以指定其目标对象和属性。You set these properties on an animation to specify its target object and property.

若要将动画应用于其目标,请Storyboard使用触发器操作或方法开始。To apply animations to their targets, you begin the Storyboard using a trigger action or a method. XAMLXAML中,可以BeginStoryboard使用具有EventTriggerTriggerDataTrigger的对象。In XAMLXAML, you use a BeginStoryboard object with an EventTrigger, Trigger, or DataTrigger. 在代码中,还可以使用Begin方法。In code, you can also use the Begin method.

下表显示支持每个Storyboard开始技术的不同位置:每个实例、样式、控件模板和数据模板。The following table shows the different places where each Storyboard begin technique is supported: per-instance, style, control template, and data template. “基于实例”是指直接将动画或情节提要应用于对象实例(而不是在样式、控件模板或数据模板中应用)的技术。"Per-Instance" refers to the technique of applying an animation or storyboard directly to instances of an object, rather than in a style, control template, or data template.

情节提要开始时使用…Storyboard is begun using… 基于实例Per-instance 样式Style 控件模板Control template 数据模板Data template 示例Example
BeginStoryboardEventTriggerBeginStoryboard and an EventTrigger Yes Yes Yes Yes 使用情节提要对属性进行动画处理Animate a Property by Using a Storyboard
BeginStoryboard和属性TriggerBeginStoryboard and a property Trigger NoNo Yes Yes Yes 在属性值更改时触发动画Trigger an Animation When a Property Value Changes
BeginStoryboardDataTriggerBeginStoryboard and a DataTrigger NoNo Yes Yes Yes 如何:数据发生更改时触发动画How to: Trigger an Animation When Data Changes
Begin 方法Begin method Yes No NoNo NoNo 使用情节提要对属性进行动画处理Animate a Property by Using a Storyboard

Storyboard下面的示例使用对Rectangle Width某个元素的和Color SolidColorBrush用于绘制该Rectangle的的的。The following example uses a Storyboard to animate the Width of a Rectangle element and the Color of a SolidColorBrush used to paint that 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了和附加属性。The following sections describe the TargetName and TargetProperty attached properties in more detail.

以框架元素、框架内容元素和 Freezable 元素为目标Targeting Framework Elements, Framework Content Elements, and Freezables

上一节提到过,对于要查找其目标的动画,必须知道目标的名称和要进行动画处理的属性。The previous section mentioned that, for an animation to find its target, it must know the target's name and the property to animate. 指定要进行动画处理的属性是一种直接Storyboard.TargetProperty的方式:只需用要进行动画处理的属性的名称进行设置。Specifying the property to animate is straight forward: simply set Storyboard.TargetProperty with the name of the property to animate. 通过设置动画的Storyboard.TargetName属性,指定要为其设置动画的属性的对象的名称。You specify the name of the object whose property you want to animate by setting the Storyboard.TargetName property on the animation.

要使TargetName属性正常工作,目标对象必须具有名称。For the TargetName property to work, the targeted object must have a name. FrameworkElement Freezable或在中XAMLXAML分配名称与为对象分配名称不同。 FrameworkContentElementAssigning a name to a FrameworkElement or a FrameworkContentElement in XAMLXAML is different than assigning a name to a Freezable object.

框架元素是从FrameworkElement类继承的类。Framework elements are those classes that inherit from the FrameworkElement class. 框架元素的示例包括Window ButtonDockPanel、和RectangleExamples of framework elements include Window, DockPanel, Button, and Rectangle. 实质上,所有窗口、面板和控件都是元素。Essentially all windows, panels, and controls are elements. 框架内容元素是从FrameworkContentElement类继承的类。Framework content elements are those classes that inherit from the FrameworkContentElement class. 框架内容元素的示例包括FlowDocumentParagraphExamples of framework content elements include FlowDocument and Paragraph. 如果不确定某个类型是框架元素还是框架内容元素,请查看它是否具有 Name 属性。If you're not sure whether a type is a framework element or a framework content element, check to see whether it has a Name property. 如果具有 Name 属性,则可能是框架元素或框架内容元素。If it does, it's probably a framework element or a framework content element. 若要进一步确定,请检查其类型页面的“继承性分层”部分。To be sure, check the Inheritance Hierarchy section of its type page.

若要在中XAMLXAML启用框架元素或框架内容元素的目标,请设置其Name属性。To enable the targeting of a framework element or a framework content element in XAMLXAML, you set its Name property. 在代码中,还需要使用RegisterName方法来向已为其创建的NameScope元素注册元素的名称。In code, you also need to use the RegisterName method to register the element's name with the element for which you've created a NameScope.

下面的示例摘自前面的示例,它为指定了名称MyRectangle a Rectangle FrameworkElementThe following example, taken from the preceding example, assigns the name MyRectangle a Rectangle, a type of 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);

在该元素具有名称后,可以对其属性进行动画处理。After it has a name, you can animate a property of that element.

<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 types are those classes that inherit from the Freezable class. Freezable示例包括SolidColorBrushRotateTransform和。GradientStopExamples of Freezable include SolidColorBrush, RotateTransform, and GradientStop.

若要在中Freezable XAMLXAML启用动画的目标,可以使用x:Name 指令为其分配名称。To enable the targeting of a Freezable by an animation in XAMLXAML, you use the x:Name Directive to assign it a name. 在代码中,使用RegisterName方法将其名称注册到已为其NameScope创建的元素。In code, you use the RegisterName method to register its name with the element for which you've created a NameScope.

下面的示例将一个名称分配给Freezable对象。The following example assigns a name to a Freezable object.

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

然后动画便可以该对象为目标。The object can then be targeted by an animation.

<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属性。Storyboard objects use name scopes to resolve the TargetName property. 有关 WPF 名称范围的详细信息,请参阅 WPF XAML 名称范围For more information about WPF name scopes, see WPF XAML Namescopes. 如果省略TargetName该属性,则动画将以定义它的元素为目标; 对于样式为样式的元素。If the TargetName property is omitted, the animation targets the element on which it is defined, or, in the case of styles, the styled element.

有时,不能将名称分配Freezable给对象。Sometimes a name can't be assigned to a Freezable object. 例如,如果Freezable声明为资源或用于设置样式中的属性值,则不能为其指定名称。For example, if a Freezable is declared as a resource or used to set a property value in a style, it can't be given a name. 由于该对象没有名称,因此不能直接以它为目标,但可以间接以它为目标。Because it doesn't have a name, it can't be targeted directly—but it can be targeted indirectly. 下面几节描述如何使用间接目标。The following sections describe how to use indirect targeting.

间接目标Indirect Targeting

有时Freezable动画无法直接定位,例如, Freezable当声明为资源或用于设置样式中的属性值时。There are times a Freezable can't be targeted directly by an animation, such as when the Freezable is declared as a resource or used to set a property value in a style. 在这些情况下,即使您不能直接将其作为目标,您仍然Freezable可以对对象进行动画处理。In these cases, even though you can't target it directly, you can still animate the Freezable object. 不是将TargetName属性设置为的名称Freezable,而是为其提供Freezable "所属" 的元素的名称。Instead of setting the TargetName property with the name of the Freezable, you give it the name of the element to which the Freezable "belongs." 例如, SolidColorBrush用于Fill设置矩形元素的属于该矩形的。For example, a SolidColorBrush used to set the Fill of a rectangle element belongs to that rectangle. 若要对画笔进行动画处理,请设置动画TargetProperty的属性链,该链以用于Freezable设置的Freezable属性和结束于要进行动画处理的属性结束。To animate the brush, you would set the animation's TargetProperty with a chain of properties that starts at the property of the framework element or framework content element the Freezable was used to set and ends with the Freezable property to animate.

<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冻结,将进行克隆,并对该克隆进行动画处理。Note that, if the Freezable is frozen, a clone will be made, and that clone will be animated. 发生这种情况时,原始对象HasAnimatedProperties的属性将继续false返回,因为原始对象并未进行动画处理。When this happens, the original object's HasAnimatedProperties property continues to return false, because the original object is not actually animated. 有关克隆的详细信息,请参阅 "冻结对象概述"。For more information about cloning, see the Freezable Objects Overview.

另请注意,当使用间接属性目标时,可能会以不存在的对象为目标。Also note that, when using indirect property targeting, it's possible to target objects that don't exist. 例如,你可能会假设Background使用设置SolidColorBrush了特定按钮的,并尝试对其颜色进行动画处理LinearGradientBrush (事实上,使用来设置按钮的背景)。For example, you might assume that the Background of a particular button was set with a SolidColorBrush and try to animate its Color, when in fact a LinearGradientBrush was used to set the button's Background. 在这些情况下,不会引发异常;由于LinearGradientBrush不会对属性的Color更改做出反应,动画无法获得可见效果。In these cases, no exception is thrown; the animation fails to have a visible effect because LinearGradientBrush does not react to changes to the Color property.

下面几节详细介绍间接属性目标语法。The following sections describe indirect property targeting syntax in more detail.

在 XAML 中间接以 Freezable 的属性为目标Indirectly Targeting a Property of a Freezable in XAML

若要以可冻结XAMLXAML的属性为目标,请使用以下语法。To target a property of a freezable in XAMLXAML, use the following syntax.

ElementPropertyName . FreezablePropertyNameElementPropertyName . FreezablePropertyName

WhereWhere

下面的代码演示如何对Color SolidColorBrush用于设置Fill矩形元素的的的进行动画处理。The following code shows how to animate the Color of a SolidColorBrush used to set the Fill of a rectangle element.

<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 为目标。Sometimes you need to target a freezable contained in a collection or array.

若要以集合中包含的 Freezable 为目标,可以使用以下路径语法。To target a freezable contained in a collection, you use the following path syntax.

ElementPropertyName .Children[ CollectionIndex ]. FreezablePropertyNameElementPropertyName .Children[ CollectionIndex ]. FreezablePropertyName

其中, CollectionIndex是对象在其数组或集合中的索引。Where CollectionIndex is the index of the object in its array or collection.

例如,假设某个矩形有一个TransformGroup应用于其RenderTransform属性的资源,并且您想要对它所包含的其中一个转换进行动画处理。For example, suppose that a rectangle has a TransformGroup resource applied to its RenderTransform property, and you want to animate one of the transforms it contains.

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

下面的代码演示如何对上一个Angle示例中所RotateTransform示的的属性进行动画处理。The following code shows how to animate the Angle property of the RotateTransform shown in the previous example.

<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 的属性为目标Indirectly Targeting a Property of a Freezable in Code

在代码中,您将PropertyPath创建一个对象。In code, you create a PropertyPath object. 当您创建PropertyPath时,可以Path指定和PathParametersWhen you create the PropertyPath, you specify a Path and PathParameters.

若要PathParameters创建,请创建一个类型DependencyProperty为的数组,其中包含依赖项属性标识符字段的列表。To create PathParameters, you create an array of type DependencyProperty that contains a list of dependency property identifier fields. 第一个标识符字段用于的属性FrameworkElementFrameworkContentElement Freezable用于设置的。The first identifier field is for the property of the FrameworkElement or FrameworkContentElement that the Freezable is used to set. 下一个标识符字段表示目标Freezable为的属性。The next identifier field represents the property of the Freezable to target. 将其视为一系列将连接Freezable FrameworkElement到对象的属性。Think of it as a chain of properties that connects the Freezable to the FrameworkElement object.

下面是依赖属性链的一个示例,它以Color SolidColorBrush用于设置Fill矩形元素的的为目标。The following is an example of a dependency property chain that targets the Color of a SolidColorBrush used to set the Fill of a rectangle element.

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

还需要指定PathYou also need to specify a Path. ,它指示如何解释其PathParametersPath Path StringA Path is a String that tells the Path how to interpret its PathParameters. 它使用以下语法。It uses the following syntax.

( OwnerPropertyArrayIndex ).( FreezablePropertyArrayIndex )( OwnerPropertyArrayIndex ).( FreezablePropertyArrayIndex )

WhereWhere

下面的示例演示Path PathParameters前面的示例中定义的。The following example shows the Path that would accompany the PathParameters defined in the preceding example.

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

下面的示例合并了前面的示例中的代码,以ColorSolidColorBrush用于设置Fill矩形元素的的的进行动画处理。The following example combines the code in the previous examples to animate the Color of a SolidColorBrush used to set the Fill of a rectangle element.


// 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 为目标。Sometimes you need to target a freezable contained in a collection or array. 例如,假设某个矩形有一个TransformGroup应用于其RenderTransform属性的资源,并且您想要对它所包含的其中一个转换进行动画处理。For example, suppose that a rectangle has a TransformGroup resource applied to its RenderTransform property, and you want to animate one of the transforms it contains.

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

若要以Freezable集合中包含的为目标,请使用以下路径语法。To target a Freezable contained in a collection, you use the following path syntax.

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

其中, CollectionIndex是对象在其数组或集合中的索引。Where CollectionIndex is the index of the object in its array or collection.

若要面向Angle的属性RotateTransform(中TransformGroup的第二个转换),请使用以下PathPathParametersTo target the Angle property of the RotateTransform, the second transform in the TransformGroup, you would use the following Path and PathParameters.

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包含的的进行动画处理的完整代码。The following example shows the complete code for animating the Angle of a RotateTransform contained within a 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 为目标并将其作为起点Indirectly Targeting with a Freezable as the Starting Point

前面的部分Freezable介绍了如何通过从FrameworkElementFrameworkContentElement开始向Freezable子属性创建属性链来间接地定位。The previous sections described how to indirectly target a Freezable by starting with a FrameworkElement or FrameworkContentElement and creating a property chain to a Freezable sub-property. 你还可以使用Freezable作为起点,并间接定位其Freezable子属性之一。You can also use a Freezable as a starting point and indirectly target one of its Freezable sub-properties. 当使用Freezable作为间接目标的起点时,还可以使用另一种限制: Freezable起始位置Freezable以及它与间接目标的子属性之间的每一个都不能冻结。One additional restriction applies when using a Freezable as a starting point for indirect targeting: the starting Freezable and every Freezable between it and the indirectly targeted sub-property must not be frozen.

在 XAML 中以交互方式控制情节提要Interactively Controlling a Storyboard in XAML

若要在中可扩展应用程序标记语言 (XAML)Extensible Application Markup Language (XAML)启动情节提要,请BeginStoryboard使用触发器操作。To start a storyboard in 可扩展应用程序标记语言 (XAML)Extensible Application Markup Language (XAML), you use a BeginStoryboard trigger action. BeginStoryboard将动画分发到它们动画处理的对象和属性,并启动情节提要。BeginStoryboard distributes the animations to the objects and properties they animate, and starts the storyboard. (有关此过程的详细信息,请参阅动画和计时系统概述。)如果通过指定名称的Name属性来指定名称,则会使其成为可控制的BeginStoryboard情节提要。(For details about this process, see the Animation and Timing System Overview.) If you give the BeginStoryboard a name by specifying its Name property, you make it a controllable storyboard. 然后,可以在情节提要启动后以交互方式对它进行控制。You can then interactively control the storyboard after it's started. 下面列出了可与事件触发器一起使用来控制情节提要的可控制情节提要操作。The following is a list of controllable storyboard actions that you use with event triggers to control a storyboard.

在下面的示例中,使用可控制的情节提要操作来以交互方式控制情节提要。In the following example, controllable storyboard actions are used to interactively control a storyboard.

<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>

使用代码以交互方式控制情节提要Interactively Controlling a Storyboard by Using Code

前面的示例已演示了如何使用触发器操作进行动画处理。The previous examples have shown how to animate using trigger actions. 在代码中,你还可以使用Storyboard类的交互式方法控制情节提要。In code, you may also control a storyboard using interactive methods of the Storyboard class. 若要在代码中使成为交互,必须使用情节提要的Begin方法的适当重载,并指定true以使其可控制。 StoryboardFor a Storyboard to be made interactive in code, you must use the appropriate overload of the storyboard's Begin method and specify true to make it controllable. 有关详细信息,请参阅页。Begin(FrameworkElement, Boolean)See the Begin(FrameworkElement, Boolean) page for more information.

以下列表显示了可用于在启动后操作的Storyboard方法:The following list shows the methods that can be used to manipulate a Storyboard after it has started:

使用这些方法的优点是不需要创建TriggerTriggerAction对象; 只需引用要操作的可控制Storyboard对象即可。The advantage to using these methods is that you don't need to create Trigger or TriggerAction objects; you just need a reference to the controllable Storyboard you want to manipulate.

备注

对执行的Clock所有交互操作,因此,也Storyboard会在计时引擎的下一计时周期发生,这将在下一次呈现之前发生。All interactive actions taken on a Clock, and therefore also on a Storyboard will occur on the next tick of the timing engine which will happen shortly before the next render. 例如,如果使用Seek方法跳转到动画中的其他点,则属性值不会立即更改,而是在计时引擎的下一计时周期更改。For example, if you use the Seek method to jump to another point in an animation, the property value does not change instantly, rather, the value changes on the next tick of the timing engine.

下面的示例演示如何使用Storyboard类的交互式方法来应用和控制动画。The following example shows how to apply and control animations using the interactive methods of the Storyboard class.

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

在样式中进行动画处理Animate in a Style

可以使用Storyboard对象定义中的Style动画。You can use Storyboard objects to define animations in a Style. 使用Storyboard 在中Storyboard的进行动画处理类似于在其他地方使用,具有以下三个例外:StyleAnimating with a Storyboard in a Style is similar to using a Storyboard elsewhere, with the following three exceptions:

  • 不指定TargetName Storyboard ; 始终以应用到的元素为Style目标。You don't specify a TargetName; the Storyboard always targets the element to which the Style is applied. 若要Freezable以对象为目标,必须使用间接目标。To target Freezable objects, you must use indirect targeting. 有关间接目标的详细信息,请参阅间接目标部分。For more information about indirect targeting, see the Indirect Targeting section.

  • 不能SourceName EventTrigger为或Trigger指定。You can't specify a SourceName for an EventTrigger or a Trigger.

  • 不能使用动态资源引用或数据绑定表达式设置Storyboard或动画属性值。You can't use dynamic resource references or data binding expressions to set Storyboard or animation property values. 这是因为内的Style所有内容都必须是线程安全的,并且计时系统必须Freeze Storyboard具有对象,才能使它们线程安全。That's because everything inside a Style must be thread-safe, and the timing system must FreezeStoryboard objects to make them thread-safe. 如果Storyboard无法冻结,则为; 否则它的子时间线包含动态资源引用或数据绑定表达式。A Storyboard cannot be frozen if it or its child timelines contain dynamic resource references or data binding expressions. 有关冻结和其他Freezable功能的详细信息,请参阅 "冻结对象概述"。For more information about freezing and other Freezable features, see the Freezable Objects Overview.

  • XAMLXAML中,不能为Storyboard或动画事件声明事件处理程序。In XAMLXAML, you can't declare event handlers for Storyboard or animation events.

有关演示如何在样式中定义情节提要的示例,请参阅在样式示例中进行动画处理For an example showing how to define a storyboard in a style, see the Animate in a Style example.

在 ControlTemplate 中进行动画处理Animate in a ControlTemplate

可以使用Storyboard对象定义中的ControlTemplate动画。You can use Storyboard objects to define animations in a ControlTemplate. Storyboard使用在中的进行Storyboard动画处理类似于在其他位置使用,但有以下两个例外:ControlTemplateAnimating with a Storyboard in a ControlTemplate is similar to using a Storyboard elsewhere, with the following two exceptions:

有关演示如何在中ControlTemplate定义情节提要的示例,请参阅 system.windows.controls.controltemplate> 示例中的动画For an example showing how to define a storyboard in a ControlTemplate, see the Animate in a ControlTemplate example.

在属性值更改时进行动画处理Animate When a Property Value Changes

在样式和控件模板中,当属性更改时,可以使用 Trigger 对象来启动情节提要。In styles and control templates, you can use Trigger objects to start a storyboard when a property changes. 有关示例,请参阅在 System.windows.controls.controltemplate> 中更改属性值并对进行动画处理时触发动画。For examples, see Trigger an Animation When a Property Value Changes and Animate in a ControlTemplate.

属性Trigger对象应用的动画的行为方式比EventTrigger使用Storyboard方法启动动画或动画更复杂。Animations applied by property Trigger objects behave in a more complex fashion than EventTrigger animations or animations started using Storyboard methods. 它们使用其他Trigger对象定义的动画 "切换",但使用EventTrigger和方法触发的动画进行组合。They "handoff" with animations defined by other Trigger objects, but compose with EventTrigger and method-triggered animations.

请参阅See also