动画概述

Windows Presentation Foundation (WPF) 提供了一组强大的图形和布局功能,使用户能够创建引起注意的用户界面和有吸引力的文档。 动画不仅可以使引起注意的用户界面更加引人注目,还可以使其更加便于使用。 只需对背景色进行动画处理或应用经过动画处理的 Transform,即可创造出生动的屏幕过渡效果或提供有帮助的视觉提示。

本概述介绍了 WPF 动画和计时系统。 它使用情节提要重点讨论 WPF 对象的动画。

动画简介

动画是快速循环播放一系列图像(其中每个图像与下一个图像略微不同)给人造成的一种幻觉。 大脑感觉这组图像是一个变化的场景。 在电影中,摄像机每秒钟拍摄许多照片(帧),便可使人形成这种幻觉。 用投影仪播放这些帧时,观众便可以看电影了。

计算机上的动画与此类似。 例如,使一个矩形图形逐渐从视野中消失的程序可能按以下方式工作。

  • 程序创建一个计时器。

  • 程序按照设定的时间间隔检查计时器以查看经历了多长时间。

  • 程序每次检查计时器时,它将根据经历的时间来计算矩形的当前不透明度值。

  • 然后,程序用新值更新矩形并重画此矩形。

在 WPF 出现之前,Microsoft Windows 开发人员必须创建和管理自己的计时系统或使用特殊的自定义库。 WPF 包括一个通过托管代码和 XAML 公开的高效计时系统,该系统紧密地集成到 WPF 框架中。 通过使用 WPF 动画,可以轻松地对控件和其他图形对象进行动画处理。

WPF 可以高效地处理管理计时系统和重绘屏幕的所有后台任务。 它提供了计时类,使用户能够重点关注要创造的效果,而非实现这些效果的机制。 此外,WPF 通过公开动画基类(你使用的类可以继承这些类)可以轻松创建自己的动画,这样便可以制作自定义动画。 这些自定义动画获得了标准动画类的许多性能优点。

WPF 属性动画系统

如果了解关于计时系统的一些重要概念,在使用 WPF 动画时可能会更轻松一些。 最重要的是,在 WPF 中,通过对对象的个别属性应用动画,可以对对象进行动画处理。 例如,若要使框架元素增大,请对其 WidthHeight 属性进行动画处理。 若要使对象逐渐从视野中消失,可以对其 Opacity 属性进行动画处理。

若要使属性具有动画功能,属性必须满足以下三个要求:

  • 它必须是依赖属性。

  • 它必须属于派生自 DependencyObject 并实现 IAnimatable 接口的类。

  • 必须存在可用的兼容动画类型。 (如果 WPF 未提供此类动画类型,可以创建自己的兼容动画类型。请参阅自定义动画概述。)

WPF 包含许多具有 IAnimatable 属性的对象。 控件(如 ButtonTabControl)以及 PanelShape 对象继承自 DependencyObject。 其中大多数属性都是依赖属性。

几乎可以在任何地方使用动画,包括在样式和控件模板中使用。 动画未必可见;如果不属于用户界面的对象满足本部分中所述的条件,则可以对其进行动画处理。

示例:使元素逐渐进入视野并从视野中逐渐消失

此示例演示如何使用 WPF 动画对依赖属性的值进行动画处理。 它使用 DoubleAnimation(一种生成 Double 值的动画类型)对 RectangleOpacity 属性进行动画处理。 因此,Rectangle 将逐渐进入视野并从视野中逐渐消失。

示例的第一部分创建一个 Rectangle 元素。 下面的步骤展示如何创建动画并将其应用于矩形的 Opacity 属性。

下面演示在 XAML 中如何在 StackPanel 中创建 Rectangle 元素。

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

下面演示在代码中如何在 StackPanel 中创建 Rectangle 元素。

var myPanel = new StackPanel();
myPanel.Margin = new Thickness(10);

var myRectangle = new Rectangle();
myRectangle.Name = "myRectangle";
this.RegisterName(myRectangle.Name, myRectangle);
myRectangle.Width = 100;
myRectangle.Height = 100;
myRectangle.Fill = Brushes.Blue;
myPanel.Children.Add(myRectangle);
this.Content = myPanel;
Dim myPanel As New StackPanel()
myPanel.Margin = New Thickness(10)

Dim myRectangle As New Rectangle()
myRectangle.Name = "myRectangle"
Me.RegisterName(myRectangle.Name, myRectangle)
myRectangle.Width = 100
myRectangle.Height = 100
myRectangle.Fill = Brushes.Blue

myPanel.Children.Add(myRectangle)
Me.Content = myPanel

第 1 部分:创建 DoubleAnimation

使元素逐渐进入视野并从视野中逐渐消失的一种方法是对其 Opacity 属性进行动画处理。 由于 Opacity 属性的类型是 Double,因此需要一个产生双精度值的动画。 DoubleAnimation 是这样一个动画。 DoubleAnimation 创建两个双精度值之间的转换。 若要指定其起始值,可设置其 From 属性。 若要指定其终止值,可设置其 To 属性。

  1. 不透明度值 1.0 使对象完全不透明,不透明度值 0.0 使对象完全不可见。 若要使动画的不透明度值从 1.0 过渡为 0.0,可以将其 From 属性设置为 1.0,将其 To 属性设置为 0.0。 下面演示如何在 XAML 中创建 DoubleAnimation

    <DoubleAnimation From="1.0" To="0.0" />
    

    下面演示如何在代码中创建 DoubleAnimation

    var myDoubleAnimation = new DoubleAnimation();
    myDoubleAnimation.From = 1.0;
    myDoubleAnimation.To = 0.0;
    
    Dim myDoubleAnimation As New DoubleAnimation()
    myDoubleAnimation.From = 1.0
    myDoubleAnimation.To = 0.0
    
  2. 接下来,必须指定 Duration。 动画的 Duration 指定了从其起始值过渡为目标值所需的时间。 下面演示了如何在 XAML 中将 Duration 设置为五秒。

    <DoubleAnimation From="1.0" To="0.0" Duration="0:0:5" />
    

    下面演示了如何在代码中将 Duration 设置为五秒。

    myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
    
    myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(5))
    
  3. 上面的代码显示了不透明度值从 1.00.0 转换的动画,此转换使目标元素从完全不透明逐渐过渡为完全不可见。 若要使元素在消失后再逐渐回到视野中,请将动画的 AutoReverse 属性设置为 true。 若要使动画无限期重复,请将其 RepeatBehavior 属性设置为 Forever。 下面演示如何在 XAML 中设置 AutoReverseRepeatBehavior 属性。

    <DoubleAnimation From="1.0" To="0.0" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever"/>
    

    下面演示如何在代码中设置 AutoReverseRepeatBehavior 属性。

    myDoubleAnimation.AutoReverse = true;
    myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
    
    myDoubleAnimation.AutoReverse = True
    myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever
    

第 2 部分:创建演示图板

若要向对象应用动画,请创建 Storyboard 并使用 TargetNameTargetProperty 附加属性指定要进行动画处理的对象和属性。

  1. 创建 Storyboard 并将动画添加为子项。 下面演示如何在 XAML 中创建 Storyboard

    <Storyboard>
        <DoubleAnimation
            From="1.0" To="0.0" Duration="0:0:1" 
            AutoReverse="True" RepeatBehavior="Forever" />
    </Storyboard>
    

    若要在代码中创建 Storyboard,请在类级别声明 Storyboard 变量。

    public partial class MainWindow : Window
    {
        private Storyboard myStoryboard;
    
    Class MainWindow
    
        Private myStoryboard As Storyboard
    

    然后初始化 Storyboard 并将动画添加为子项。

    myStoryboard = new Storyboard();
    myStoryboard.Children.Add(myDoubleAnimation);
    
    myStoryboard = New Storyboard()
    myStoryboard.Children.Add(myDoubleAnimation)
    
  2. Storyboard 必须知道要在哪里应用动画。 使用 Storyboard.TargetName 附加属性指定要进行动画处理的对象。 下面演示了如何在 XAML 中将 DoubleAnimation 的目标名称设置为 MyRectangle

    <Storyboard>
        <DoubleAnimation
            Storyboard.TargetName="MyRectangle" 
            From="1.0" To="0.0" Duration="0:0:1" 
            AutoReverse="True" RepeatBehavior="Forever" />
    </Storyboard>
    

    下面演示了如何在代码中将 DoubleAnimation 的目标名称设置为 MyRectangle

    Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
    
    Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name)
    
  3. 使用 TargetProperty 附加属性指定要进行动画处理的属性。 下面演示了如何在 XAML 中将动画配置为面向 RectangleOpacity 属性。

    <Storyboard>
        <DoubleAnimation
            Storyboard.TargetName="MyRectangle" 
            Storyboard.TargetProperty="Opacity"
            From="1.0" To="0.0" Duration="0:0:5" 
            AutoReverse="True" RepeatBehavior="Forever" />
    </Storyboard>
    

    下面演示了如何在代码中将动画配置为面向 RectangleOpacity 属性。

    Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.OpacityProperty));
    
    Storyboard.SetTargetProperty(myDoubleAnimation, New PropertyPath(Rectangle.OpacityProperty))
    

有关 TargetProperty 语法的详细信息以及其他示例,请参阅情节提要概述

第 3 部分 (XAML):将演示图板与触发器关联

在 XAML 中应用和启动 Storyboard 的最简单方法是使用事件触发器。 本部分演示如何在 XAML 中将 Storyboard 与触发器关联。

  1. 创建一个 BeginStoryboard 对象并将情节提要与其关联。 BeginStoryboard 是应用并启动 Storyboard 的一种 TriggerAction 类型。

    <BeginStoryboard>
      <Storyboard>
        <DoubleAnimation
          Storyboard.TargetName="MyRectangle" 
          Storyboard.TargetProperty="Opacity"
          From="1.0" To="0.0" Duration="0:0:5" 
          AutoReverse="True" RepeatBehavior="Forever" />
      </Storyboard>
    </BeginStoryboard>
    
  2. 创建 EventTrigger 并将 BeginStoryboard 添加到其 Actions 集合中。 将 EventTriggerRoutedEvent 属性设置为要启动 Storyboard 的路由事件。 (有关路由事件的详细信息,请参阅路由事件概述。)

    <!-- Animates the rectangle's opacity. -->
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation
            Storyboard.TargetName="MyRectangle" 
            Storyboard.TargetProperty="Opacity"
            From="1.0" To="0.0" Duration="0:0:5" 
            AutoReverse="True" RepeatBehavior="Forever" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
    
  3. EventTrigger 添加到矩形的 Triggers 集合中。

    <Rectangle
      Name="MyRectangle"
      Width="100" 
      Height="100"
      Fill="Blue">
      <Rectangle.Triggers>
        <!-- Animates the rectangle's opacity. -->
        <EventTrigger RoutedEvent="Rectangle.Loaded">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation
                Storyboard.TargetName="MyRectangle" 
                Storyboard.TargetProperty="Opacity"
                From="1.0" To="0.0" Duration="0:0:5" 
                AutoReverse="True" RepeatBehavior="Forever" />
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle>
    

第 3 部分(代码):将演示图板与事件处理程序关联

在代码中应用和启动 Storyboard 的最简单方法是使用事件处理程序。 本部分演示如何在代码中将 Storyboard 与事件处理程序关联。

  1. 注册矩形的 Loaded 事件。

    myRectangle.Loaded += new RoutedEventHandler(myRectangleLoaded);
    
    AddHandler myRectangle.Loaded, AddressOf myRectangleLoaded
    
  2. 声明事件处理程序。 在事件处理程序中,使用 Begin 方法来应用情节提要。

    private void myRectangleLoaded(object sender, RoutedEventArgs e)
    {
        myStoryboard.Begin(this);
    }
    
    Private Sub myRectangleLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
        myStoryboard.Begin(Me)
    End Sub
    

完整的示例

下面演示了如何在 XAML 中创建逐渐进入视野并从视野中逐渐消失的矩形。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel Margin="10">
            <Rectangle
                Name="MyRectangle"
                Width="100" 
                Height="100"
                Fill="Blue">
                <Rectangle.Triggers>
                    <!-- Animates the rectangle's opacity. -->
                    <EventTrigger RoutedEvent="Rectangle.Loaded">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation
                                    Storyboard.TargetName="MyRectangle" 
                                    Storyboard.TargetProperty="Opacity"
                                    From="1.0" To="0.0" Duration="0:0:5" 
                                    AutoReverse="True" RepeatBehavior="Forever" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Rectangle.Triggers>
            </Rectangle>
        </StackPanel>
    </Grid>
</Window>

下面演示了如何在代码中创建逐渐进入视野并从视野中逐渐消失的矩形。

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

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        private Storyboard myStoryboard;

        public MainWindow()
        {
            InitializeComponent();

            StackPanel myPanel = new StackPanel();
            myPanel.Margin = new Thickness(10);

            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "myRectangle";
            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            myRectangle.Fill = Brushes.Blue;

            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 1.0;
            myDoubleAnimation.To = 0.0;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
            myDoubleAnimation.AutoReverse = true;
            myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;

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

            // Use the Loaded event to start the Storyboard.
            myRectangle.Loaded += new RoutedEventHandler(myRectangleLoaded);
            myPanel.Children.Add(myRectangle);
            this.Content = myPanel;
        }

        private void myRectangleLoaded(object sender, RoutedEventArgs e)
        {
            myStoryboard.Begin(this);
        }
    }
}
Imports System.Windows.Media.Animation

Class MainWindow

    Private myStoryboard As Storyboard

    Public Sub New()
        InitializeComponent()

        Dim myPanel As New StackPanel()
        myPanel.Margin = New Thickness(10)

        Dim myRectangle As New Rectangle()
        myRectangle.Name = "myRectangle"
        Me.RegisterName(myRectangle.Name, myRectangle)
        myRectangle.Width = 100
        myRectangle.Height = 100
        myRectangle.Fill = Brushes.Blue

        Dim myDoubleAnimation As New DoubleAnimation()
        myDoubleAnimation.From = 1.0
        myDoubleAnimation.To = 0.0
        myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(5))
        myDoubleAnimation.AutoReverse = True
        myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever

        myStoryboard = New Storyboard()
        myStoryboard.Children.Add(myDoubleAnimation)
        Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name)
        Storyboard.SetTargetProperty(myDoubleAnimation, New PropertyPath(Rectangle.OpacityProperty))

        ' Use the Loaded event to start the Storyboard.
        AddHandler myRectangle.Loaded, AddressOf myRectangleLoaded

        myPanel.Children.Add(myRectangle)
        Me.Content = myPanel
    End Sub

    Private Sub myRectangleLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
        myStoryboard.Begin(Me)
    End Sub

End Class

动画类型

由于动画生成属性值,因此不同的属性类型具有不同的动画类型。 要为采用 Double 的属性(例如元素的 Width 属性)进行动画处理,可以使用生成 Double 值的动画。 要为采用 Point 的属性进行动画处理,请使用生成 Point 值的动画,依此类推。 由于存在许多不同的属性类型,因此 System.Windows.Media.Animation 命名空间中存在一些动画类。 幸运的是,它们都遵循严格的命名约定,因此可以轻松地区分它们:

  • <类型>Animation

    这些动画称为“From/To/By”或“基本”动画,它们在起始值和目标值之间进行动画处理,或者通过将偏移量值与其起始值相加来进行动画处理。

    • 若要指定起始值,请设置动画的“From”属性。

    • 若要指定终止值,请设置动画的“To”属性。

    • 若要指定偏移量值,请设置动画的“By”属性。

    此概述中的示例使用这些动画,因为这些动画使用起来最简单。 From/To/By 动画概述中详细描述了“From/To/By”动画。

  • <类型>AnimationUsingKeyFrames

    关键帧动画的功能比“From/To/By”动画的功能更强大,因为可以指定任意多个目标值,甚至可以控制它们的插值方法。 某些类型只能用关键帧动画进行动画处理。 关键帧动画概述中详细描述了关键帧动画。

  • <类型>AnimationUsingPath

    路径动画支持使用几何路径来生成动画值。

  • <类型>AnimationBase

    在实现时对 <类型> 值进行动画处理的抽象类。 此类用作 <类型>Animation 和 <类型>AnimationUsingKeyFrames 类的基类。 只有在想要创建自己的自定义动画时,才需要直接处理这些类。 否则,请使用 <类型>Animation 或 KeyFrame<类型>Animation。

在大多数情况下,将要使用 <类型>Animation 类,如 DoubleAnimationColorAnimation

下表显示了一些常用动画类型以及一些与这些类型一起使用的属性。

属性类型 对应的基本 (From/To/By) 动画 对应的关键帧动画 对应的路径动画 用例
Color ColorAnimation ColorAnimationUsingKeyFrames SolidColorBrushGradientStopColor 进行动画处理。
Double DoubleAnimation DoubleAnimationUsingKeyFrames DoubleAnimationUsingPath DockPanelWidthButtonHeight 进行动画处理。
Point PointAnimation PointAnimationUsingKeyFrames PointAnimationUsingPath EllipseGeometryCenter 位置进行动画处理。
String StringAnimationUsingKeyFrames TextBlockTextButtonContent 进行动画处理。

动画是时间线

所有动画类型均继承自 Timeline 类;因此,所有动画都是专用类型的时间线。 Timeline 定义一个时间段。 可以指定时间线的以下计时行为Duration 和重复次数,甚至可以为时间线指定时间走得多快。

因为动画是 Timeline,所以它还表示时间段。 在动画的指定时间段(或 Duration)内运行动画时,动画还会计算输出值。 在运行或“播放”动画时,动画将更新与其关联的属性。

三个经常使用的计时属性为 DurationAutoReverseRepeatBehavior

Duration 属性

如前文所述,时间线表示时间段。 该时间段的长度由时间线的 Duration(通常用 TimeSpan 值指定)确定。 当时间线达到其持续时间的终点时,表示时间线完成了一次迭代。

动画使用其 Duration 属性来确定当前值。 如果没有为动画指定 Duration 值,它将使用 1 秒(这是默认值)。

下面的语法显示了 Duration 属性的 Extensible Application Markup Language (XAML) 特性语法的简化版本。

小时:分钟:

下表显示了一些 Duration 设置及其所得值。

设置 所得值
0:0:5.5 5.5 秒。
0:30:5.5 30 分 5.5 秒。
1:30:5.5 1 小时 30 分 5.5 秒。

在代码中指定 Duration 的一种方法是使用 FromSeconds 方法创建 TimeSpan,然后使用该 TimeSpan 声明新的 Duration 结构。

有关 Duration 值和完整的 Extensible Application Markup Language (XAML) 语法的详细信息,请参阅 Duration 结构。

AutoReverse

AutoReverse 属性指定时间线在到达 Duration 的终点后是否倒退。 如果将此动画属性设置为 true,则动画在到达 Duration 的终点后将倒退,即从其终止值向其起始值反向播放。 默认情况下,此属性为 false

RepeatBehavior

RepeatBehavior 属性指定时间线的播放次数。 默认情况下,时间线的迭代次数为 1.0,即播放一次时间线,根本不进行重复。

有关这些属性和其他属性的详细信息,请参阅计时行为概述

对属性应用动画

前面部分介绍了动画的不同类型及其计时属性。 本部分演示如何对要进行动画处理的属性应用动画。 Storyboard 对象提供了对属性应用动画的一种方法。 Storyboard 是一个为其所包含的动画提供目标信息的容器时间线

以对象和属性为目标

Storyboard 类提供 TargetNameTargetProperty 附加属性。 通过在动画上设置这些属性,告诉动画对哪些内容进行动画处理。 但是,通常必须为对象提供一个名称,动画才能以该对象作为目标。

FrameworkElement 分配名称不同于为 Freezable 对象分配名称。 大多数控件和面板是框架元素;而大多数纯图形对象(如画笔、转换和几何图形)是 Freezable 对象。 如果不确定类型是 FrameworkElement 还是 Freezable,请参阅参考文档的“继承层次结构”部分。

  • 若要使 FrameworkElement 成为动画目标,应通过设置 Name 属性为其提供一个名称。 在代码中,还必须使用 RegisterName 方法向元素名称所属的页面注册该元素名称。

  • 若要使 Freezable 对象成为 XAML 中的动画目标,应使用 x:Name 指令为其分配一个名称。 在代码中,只需使用 RegisterName 方法向对象所属的页面注册该对象。

以下部分举例说明如何使用 XAML 和代码为元素命名。 有关命名和设定目标的更多详细信息,请参阅情节提要概述

应用和启动演示图板

若要使用 XAML 启动情节提要,应将其与 EventTrigger 关联。 EventTrigger 是一个描述在发生指定事件时执行哪些操作的对象。 其中一个操作可以是 BeginStoryboard 操作,该操作用于启动情节提要。 事件触发器与事件处理程序的概念类似,因为通过它们可以指定应用程序响应特定事件的方式。 与事件处理程序不同,可以使用 XAML 来全面描述事件触发器,而无需使用其他代码。

若要在代码中启动 Storyboard,可以使用 EventTrigger 或使用 Storyboard 类的 Begin 方法。

以交互方式控制演示图板

前面的示例演示如何在事件发生时启动 Storyboard。 也可以在 Storyboard 启动后以交互方式控制它:可以暂停、继续和停止它,并可以使其进入到其填充期,还可以查找和移除 Storyboard。 有关详细信息以及演示如何以交互方式控制 Storyboard 的示例,请参阅情节提要概述

动画结束后,会发生什么情况?

FillBehavior 属性指定时间线结束时的行为方式。 默认情况下,时间线结束时将启动 Filling。 处于 Filling 状态的动画将保持其最终输出值。

上一示例中的 DoubleAnimation 没有结束,因为其 RepeatBehavior 属性设置为 Forever。 下面的示例使用类似的动画对矩形进行动画处理。 与前面的示例不同,此动画的 RepeatBehaviorAutoReverse 属性保留默认值。 因此,动画运行五秒钟使其不透明度值从 1 转变成 0,然后停止。

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

    <!-- Animates the rectangle's opacity. -->
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation
            Storyboard.TargetName="MyRectangle" 
            Storyboard.TargetProperty="Opacity"
            From="1.0" To="0" Duration="0:0:5" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>
DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 1.0;
myDoubleAnimation.To = 0.0;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
Dim myDoubleAnimation As New DoubleAnimation()
myDoubleAnimation.From = 1.0
myDoubleAnimation.To = 0.0
myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(5))

因为动画的 FillBehavior 未发生变化,仍然为其默认值 HoldEnd,所以当动画结束时动画将保持最终值 0。 因此,在动画结束后,矩形的 Opacity 仍然为 0。 如果将矩形的 Opacity 设置为另一个值,代码似乎无效,因为动画仍将影响 Opacity 属性。

在代码中重新获得动画属性控制权的一种方法是使用 BeginAnimation 方法,并将 AnimationTimeline 参数指定为 null。 有关详细信息及示例,请参阅在使用情节提要对属性进行动画处理后设置该属性

请注意,虽然设置一个具有 ActiveFilling 动画的属性值好像不起作用,但属性值确实发生了变化。 有关详细信息,请参阅动画和计时系统概述

对动画进行数据绑定和动画处理

可以对大多数动画属性进行数据绑定或动画处理;例如,可以对 DoubleAnimationDuration 属性进行动画处理。 但是,由于计时系统工作方式的缘故,进行了数据绑定和动画处理的动画的行为与其他进行了数据绑定和动画处理的对象不同。 若要了解它们的行为,请了解对属性应用动画的意义,这将十分有用。

请参考上一部分中演示如何对矩形的 Opacity 进行动画处理的示例。 加载前面示例中的矩形时,它的事件触发器将应用 Storyboard。 计时系统会创建 Storyboard 及其动画的副本。 系统将冻结这些副本(使它们成为只读副本),并且将根据它们来创建 Clock 对象。 这些时钟将执行对目标属性进行动画处理的实际工作。

计时系统会为 DoubleAnimation 创建时钟,并将其应用于由 DoubleAnimationTargetNameTargetProperty 指定的对象和属性。 在本例中,计时系统将时钟应用于名为“MyRectangle”的对象的 Opacity 属性。

虽然也会为 Storyboard 创建一个时钟,但未对任何属性应用该时。 该时钟的用途是控制其子时钟(为 DoubleAnimation 创建的时钟)。

若要使动画反映数据绑定或动画更改,必须重新生成时钟。 系统不会自动生成时钟。 若要使动画反映更改,请使用 BeginStoryboardBegin 方法重新应用其情节提要。 当使用其中一种方法时,动画将重新启动。 在代码中,可以使用 Seek 方法将情节提要移回到从前的位置。

有关数据绑定动画的示例,请参阅主曲线动画示例。 有关动画和计时系统的工作原理的详细信息,请参阅动画和计时系统概述

其他动画处理方式

此概述中的示例演示如何使用演示图板进行动画处理。 如果使用代码,可以采用一些其他方法进行动画处理。 有关详细信息,请参阅属性动画技术概述

动画示例

以下示例有助于开始向应用程序添加动画。

Title 说明
动画和计时系统概述 描述计时系统如何使用 TimelineClock 类,通过这两个类可以创建动画。
动画提示和技巧 列出用于解决与动画有关的问题(如性能)的有用提示。
自定义动画概述 描述如何使用关键帧、动画类或逐帧回叫来扩展动画系统。
From/To/By 动画概述 描述如何创建在两个值之间转换的动画。
关键帧动画概述 描述如何使用多个目标值创建动画(包括控制内插方法的功能)。
缓动函数 说明如何将数学公式应用于动画以获得真实行为(如反弹)。
路径动画概述 描述如何沿复杂路径移动或旋转对象。
属性动画技术概述 描述使用演示图板、本地动画、时钟以及逐帧动画的属性动画。
情节提要概述 描述如何将演示图板与多个时间线一起使用,以创建复杂动画。
计时行为概述 描述动画中使用的 Timeline 类型和属性。
计时事件概述 描述 TimelineClock 对象上可用于在时间线中的各点上执行代码的事件(如开始、暂停、继续、跳过或停止)。
操作指南主题 包含演示在应用程序中使用动画和时间线的代码示例。
时钟操作说明主题 包含在应用程序中使用 Clock 对象的代码示例。
关键帧操作说明主题 包含在应用程序中使用关键帧动画的代码示例。
路径动画操作说明主题 包含在应用程序中使用路径动画的代码示例。

参考