Spiga

WPF学习笔记3:动画

2022-08-28 22:25:34

一、动画

  • 补间动画:动画本质就是在一个时间段内对象尺寸、位移、旋转角度、缩放、颜色、透明度等属性值的连续变化。也包括图形变形的属性。时间、变化的对象、变化的值
  • 工业应用场景:蚂蚁线、旋转、高度变化、指针偏移、小车 起始-》结束 多长时间
  • 使用要求
    • 必须针对依赖属性
    • 对象必须派生自DependencyObject,并且实现IAnimatable接口
    • 必须存在可用的兼容动画类(支持自定义)

二、简单线性动画

1. 类型

类型
ByteAnimation ColorAnimation DecimalAnimation DoubleAnimation
Int16Animation Int32Animation Int64Animation Point3DAnimation
PointAnimation QuaternionAnimation RectAnimation Rotation3DAnimation
SingleAnimation SizeAnimation ThicknessAnimation VectorAnimation
Vector3DAnimation

2. 动画类的选择

  • 根据属性类型确定

  • 变个大小、变个位置、变个颜色、变个显示(显示与隐藏)

3. 基本使用

  • 创建类对象,设置相关属性,动画的执行
    • Duration、From、To
  • 动画的独立控制与整合
  • StoryBoard
    • 控制动画的运行:开始,停止,暂停,恢复
    • 动画与对象的桥梁:动画对象与页面对象的关联
    • MediaElement

4. 实操

<Window x:Class="AnimationLesson.LinearAniamtionWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson"
        mc:Ignorable="d" FontSize="20"
        Title="LinearAniamtionWindow" Height="450" Width="800">
    <Window.Resources>
        <SolidColorBrush Color="Orange" x:Key="scb" x:Name="scb"/>
        
        <Storyboard x:Key="sb">
            <!--对象的尺寸变化动画-->
            <!--<DoubleAnimation Duration="0:0:5" From="100" To="300"
                                     Storyboard.TargetName="border"
                                     Storyboard.TargetProperty="Width"/>
            <DoubleAnimation Duration="0:0:3" From="50" To="350"
                                     Storyboard.TargetName="border"
                                     Storyboard.TargetProperty="Height"/>-->

            <!--对象的位移变化动画-->
            <!--<ThicknessAnimation Duration="0:0:5"
                                From="100,50,0,0"
                                To="300,150,0,0"
                                Storyboard.TargetName="border"
                                Storyboard.TargetProperty="Margin"/>-->

            <!--第二种方式-->
            <!--<DoubleAnimation Duration="0:0:5"
                             From="100"
                             To="300"
                             Storyboard.TargetName="border"
                             Storyboard.TargetProperty="Canvas.Left"/>-->

            <!--第三种方式-->
            <!--<DoubleAnimation Duration="0:0:5"
                             From="100" To="300"
                             Storyboard.TargetName="border"
                             Storyboard.TargetProperty="(Border.RenderTransform).(RotateTransform.Angle)"/>
            
            <DoubleAnimation Duration="0:0:5"
                             From="100" To="300"
                             Storyboard.TargetName="tt"
                             Storyboard.TargetProperty="X"/>-->
            
            <!--Brush画刷 包含颜色类型SolidColorBrush   **  ImageBrush-->
            <ColorAnimation Duration="0:0:3" 
                            From="Orange" 
                            To="Green"
                            Storyboard.TargetName="border"
                            Storyboard.TargetProperty="Background.Color"/>
            <ColorAnimation Duration="0:0:3" 
                            From="Green" 
                            To="Red"
                            Storyboard.TargetName="border"
                            Storyboard.TargetProperty="Background.Color"
                            BeginTime="0:0:3"/>           
            
            <!--不能直接变化资源对象,会找不到对象名称-->
            <!--<ColorAnimation Duration="0:0:3" 
                            From="Orange" 
                            To="Green"
                            Storyboard.TargetName="scb"
                            Storyboard.TargetProperty="Color"/>-->
            
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn" >
            <BeginStoryboard Storyboard="{StaticResource sb}">
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="100" Height="50" Background="{StaticResource scb}" Name="border"
                Margin="100,50,0,0" 
                Canvas.Left="100" Canvas.Top="50"
                Visibility="Visible" Opacity="1">
            <Border.RenderTransform>
                <TranslateTransform X="10" Y="5" x:Name="tt"/>
                <!--<RotateTransform Angle="0"/>-->
                <!--<ScaleTransform ScaleX="2" ScaleY="2"/>-->
            </Border.RenderTransform>
        </Border>

        <Button Content="开始" VerticalAlignment="Bottom" Name="btn"/>
        <!--<Button Content="开始" VerticalAlignment="Bottom" Click="Button_Click"/>-->
    </Grid>
</Window>
public partial class LinearAniamtionWindow : Window
{
    public LinearAniamtionWindow()
    {
        InitializeComponent();

    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        DoubleAnimation widthAnimation = new DoubleAnimation();
        widthAnimation.Duration = new TimeSpan(0, 0, 5);
        widthAnimation.From = 100;
        widthAnimation.To = 300;

        //this.border.BeginAnimation(WidthProperty, widthAnimation);


        DoubleAnimation heightAnimation = new DoubleAnimation();
        heightAnimation.Duration = new TimeSpan(0, 0, 3);
        heightAnimation.From = 50;
        heightAnimation.To = 350;

        //this.border.BeginAnimation(HeightProperty, heightAnimation);

        // 如果多个动画需要同时执行,可以将相应是对象放到一个StoryBoard
        // 多条故事线  同步推进
        // Storyboard

        Storyboard sb = new Storyboard();
        sb.Children.Add(widthAnimation);
        sb.Children.Add(heightAnimation);

        // 这里指定相关的动画对象,与哪个页面对象相关
        // 
        Storyboard.SetTarget(widthAnimation, this.border);
        Storyboard.SetTargetProperty(widthAnimation, new PropertyPath("Width"));

        Storyboard.SetTarget(heightAnimation,this.border);
        Storyboard.SetTargetProperty(heightAnimation, new PropertyPath("Height"));

        sb.Begin();
        
    }

    private void btn_Click(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("===btn_Click===");
    }
}

二、关键帧动画

1. 类型

类型
BooleanAnimationUsingKeyFrames ByteAnimationUsingKeyFrames CharAnimationUsingKeyFrames ColorAnimationUsingKeyFrames
DecimalAnimationUsingKeyFrames DoubleAnimationUsingKeyFrames Int16AnimationUsingKeyFrames Int32AnimationUsingKeyFrames
Int64AnimationUsingKeyFrames MatrixAnimationUsingKeyFrames ObjectAnimationUsingKeyFrames Point3DAnimationUsingKeyFrames
PointAnimationUsingKeyFrames QuaternionAnimationUsingKeyFrames RectAnimationUsingKeyFrames Rotation3DAnimationUsingKeyFrames
SingleAnimationUsingKeyFrames SizeAnimationUsingKeyFrames StringAnimationUsingKeyFrames ThicknessAnimationUsingKeyFrames
Vector3DAnimationUsingKeyFrames VectorAnimationUsingKeyFrames

2. 大帧类型

  • Linear+【类型名称】+KeyFrame 线性变化关键帧,(简单线性动画的处理基本一样)

  • Discrete +【类型名称】+ KeyFrame 离散变化关键帧,不连续变化

  • Spline +【类型名称】+ KeyFrame 样条关键帧-》样条函数(二次贝塞尔曲线-Path)

  • Easing +【类型名称】+ KeyFrame 缓冲式关键帧,使用简单动画时介绍的缓动效果

  • ObjectAnimationUsingKeyFrames 理论让任意类型参与动画,只能离散形式的动画效果

3. 实操

<Window x:Class="AnimationLesson.KeyFrameAnnimationWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson"
        mc:Ignorable="d" FontSize="20"
        Title="KeyFrameAnnimationWindow" Height="450" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb">
            <!--1、如果动画对象的Duration时长大于子帧的时长,多出来的时间无变化-->
            <!--2、如果动画对象的Duration时长小于子帧的时长,以对象时间为准,超出的子帧时间不执-->
            <!--3、如果不指定动画对象的Duration属性,以子帧时间全部分执行-->

            <!--注意事项:关键帧的时间,没有先后顺序要求,严格按照时间轴进行执行-->
            <!--<ColorAnimationUsingKeyFrames Storyboard.TargetName="border"
                                          Storyboard.TargetProperty="Background.Color">
                <LinearColorKeyFrame Value="Orange" KeyTime="0:0:0"/>
                <LinearColorKeyFrame Value="Green" KeyTime="0:0:2"/>
                <LinearColorKeyFrame Value="Red" KeyTime="0:0:4"/>
                <DiscreteColorKeyFrame Value="Blue" KeyTime="0:0:6"/>
                <DiscreteColorKeyFrame Value="Gray" KeyTime="0:0:8"/>
            </ColorAnimationUsingKeyFrames>-->

            <!--只有离散关键帧动画-->
            <!--可以通过C#代码处理-->
            <StringAnimationUsingKeyFrames Storyboard.TargetName="tb" 
                                           Storyboard.TargetProperty="Text">
                <DiscreteStringKeyFrame Value="" KeyTime="0:0:0"/>
                <DiscreteStringKeyFrame Value="H" KeyTime="0:0:0.3"/>
                <DiscreteStringKeyFrame Value="He" KeyTime="0:0:0.6"/>
                <DiscreteStringKeyFrame Value="Hel" KeyTime="0:0:0.9"/>
                <DiscreteStringKeyFrame Value="Hell" KeyTime="0:0:1.2"/>
                <DiscreteStringKeyFrame Value="Hello" KeyTime="0:0:1.5"/>
                <DiscreteStringKeyFrame Value="Hello " KeyTime="0:0:1.8"/>
                <DiscreteStringKeyFrame Value="Hello Z" KeyTime="0:0:2.1"/>
            </StringAnimationUsingKeyFrames>

            <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="ellipse"
                                              Storyboard.TargetProperty="Margin">
                <SplineThicknessKeyFrame Value="0,0,0,0" KeyTime="0:0:0"/>
                <SplineThicknessKeyFrame KeyTime="00:00:04" Value="780,0,0,0" KeySpline="0.1,0.9,0.9,0.1">
                    <!--可以简化处理, 如上行KeySpline属性-->
                    <!--<SplineThicknessKeyFrame.KeySpline>
                        <KeySpline ControlPoint1="0.1,0.9" ControlPoint2="0.9,0.1"/>
                    </SplineThicknessKeyFrame.KeySpline>-->
                </SplineThicknessKeyFrame>
            </ThicknessAnimationUsingKeyFrames>


            <DoubleAnimationUsingKeyFrames>
                <SplineDoubleKeyFrame KeySpline="0.9,0.1,1,1"/>
                <LinearDoubleKeyFrame />
                <SplineDoubleKeyFrame KeySpline="0.9,0.1,1,1"/>
            </DoubleAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames>
                <DiscretePointKeyFrame Value="100,100" KeyTime="0:0:0"/>
            </PointAnimationUsingKeyFrames>

            <!--安排随机坐标线性变化案例-->
        </Storyboard>

        <ElasticEase x:Key="be"/>
        <Storyboard x:Key="ease_sb">
            <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="border"
                                              Storyboard.TargetProperty="Margin">
                <LinearThicknessKeyFrame Value="0" KeyTime="0:0:0"/>
                <LinearThicknessKeyFrame Value="100,0,0,0" KeyTime="0:0:2"/>
                <LinearThicknessKeyFrame Value="100,0,0,0" KeyTime="0:0:3"/>
                <EasingThicknessKeyFrame Value="300,0,0,0" KeyTime="0:0:5" EasingFunction="{StaticResource be}">
                    <!--<EasingThicknessKeyFrame.EasingFunction>
                        <CircleEase EasingMode="EaseInOut"/>
                    </EasingThicknessKeyFrame.EasingFunction>-->
                </EasingThicknessKeyFrame>
            </ThicknessAnimationUsingKeyFrames>
        </Storyboard>

        <Storyboard x:Key="obj_sb">
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="border"
                                           Storyboard.TargetProperty="Visibility">
                <DiscreteObjectKeyFrame KeyTime="0:0:0">
                    <DiscreteObjectKeyFrame.Value>
                        <Visibility>Visible</Visibility>
                    </DiscreteObjectKeyFrame.Value>
                </DiscreteObjectKeyFrame>
                <DiscreteObjectKeyFrame KeyTime="0:0:1">
                    <DiscreteObjectKeyFrame.Value>
                        <Visibility>Hidden</Visibility>
                    </DiscreteObjectKeyFrame.Value>
                </DiscreteObjectKeyFrame>
                <DiscreteObjectKeyFrame KeyTime="0:0:2">
                    <DiscreteObjectKeyFrame.Value>
                        <Visibility>Visible</Visibility>
                    </DiscreteObjectKeyFrame.Value>
                </DiscreteObjectKeyFrame>
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn" >
            <BeginStoryboard Storyboard="{StaticResource obj_sb}"/>
        </EventTrigger>
    </Window.Triggers>

    <Grid>
        <Border VerticalAlignment="Center" HorizontalAlignment="Left"
                Width="100" Height="50" Background="Orange" Name="border" Visibility="Visible"/>
        <TextBlock Text="Hello" VerticalAlignment="Center" HorizontalAlignment="Center"
                   Name="tb"/>

        <Ellipse Width="20" Height="20" Fill="Red" VerticalAlignment="Top" HorizontalAlignment="Left"
                 Margin="0,0,0,0" Name="ellipse"/>

        <Button Content="开始" VerticalAlignment="Bottom" Name="btn"/>
    </Grid>
</Window>

三、路径动画

1. 分类

  • DoubleAnimationUsingPath:位移(TranslateTransform、Canvas LeftTop)、旋转(RoateTransform)
  • PointAnimationUsingPath:位移
  • MatrixAnimationUsingPath:合体,上面两个都包含

2. 使用方法

  • 根据Path数据,限定动画路径
  • 类型名称+ AnimationUsingPath
  • 3个对象 Double、Point(X、Y)、Matrix(不需要记矩阵)
  • 路径Path

3. 实操

<Window x:Class="AnimationLesson.PathAnimationWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson"
        mc:Ignorable="d" FontSize="30"
        Title="PathAnimationWindow" Height="450" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb">
            <DoubleAnimationUsingPath Duration="0:0:4"
                                      Storyboard.TargetName="tt"
                                      Storyboard.TargetProperty="X"
                                      Source="X">
                <DoubleAnimationUsingPath.PathGeometry>
                    <PathGeometry Figures="M0 0 60,100 A100 50 0 0 1 400 150"/>
                </DoubleAnimationUsingPath.PathGeometry>
            </DoubleAnimationUsingPath>
            <DoubleAnimationUsingPath Duration="0:0:4"
                                      Storyboard.TargetName="tt"
                                      Storyboard.TargetProperty="Y"
                                      Source="Y">
                <DoubleAnimationUsingPath.PathGeometry>
                    <PathGeometry Figures="M0 0 60,100 A100 50 0 0 1 400 150"/>
                </DoubleAnimationUsingPath.PathGeometry>
            </DoubleAnimationUsingPath>

            <DoubleAnimationUsingPath Duration="0:0:4"
                                      Storyboard.TargetName="rt"
                                      Storyboard.TargetProperty="Angle"
                                      Source="Angle">
                <DoubleAnimationUsingPath.PathGeometry>
                    <PathGeometry Figures="M0 0 60,100 A100 50 0 0 1 400 150"/>
                </DoubleAnimationUsingPath.PathGeometry>
            </DoubleAnimationUsingPath>

            <!--<DoubleAnimationUsingPath Duration="0:0:4"
                                      Storyboard.TargetName="rt1"
                                      Storyboard.TargetProperty="Angle"
                                      Source="Angle">
                <DoubleAnimationUsingPath.PathGeometry>
                    <PathGeometry Figures="M0 0 60,100 A100 50 0 0 1 400 150"/>
                </DoubleAnimationUsingPath.PathGeometry>
            </DoubleAnimationUsingPath>-->
            <PointAnimationUsingPath Duration="0:0:4"
                                     Storyboard.TargetName="eg"
                                     Storyboard.TargetProperty="Center">
                <PointAnimationUsingPath.PathGeometry>
                    <PathGeometry Figures="M0 0 60,100 A100 50 0 0 1 400 150"/>
                </PointAnimationUsingPath.PathGeometry>
            </PointAnimationUsingPath>

            <MatrixAnimationUsingPath Duration="0:0:4"
                                      Storyboard.TargetName="mt"
                                      Storyboard.TargetProperty="Matrix"
                                      DoesRotateWithTangent="True">
                <MatrixAnimationUsingPath.PathGeometry>
                    <PathGeometry Figures="M0 0 60,100 A100 50 0 0 1 400 150"/>
                </MatrixAnimationUsingPath.PathGeometry>
            </MatrixAnimationUsingPath>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn" >
            <BeginStoryboard Storyboard="{StaticResource sb}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Path Data="M0 0 60,100 A100 50 0 0 1 400 150" Stroke="Gray" StrokeThickness="2">
        </Path>
        <Path Fill="Orange" Visibility="Collapsed">
            <Path.Data>
                <EllipseGeometry Center="0,0" RadiusX="50" RadiusY="25" x:Name="eg">
                    <EllipseGeometry.Transform>
                        <RotateTransform x:Name="rt1"/>
                    </EllipseGeometry.Transform>
                </EllipseGeometry>
                
                <!--以下案例处理报错-->
                <!--<RectangleGeometry x:Name="rg">
                    <RectangleGeometry.Rect>
                        <Rect Location="0,0" Width="100" Height="50"/>
                    </RectangleGeometry.Rect>
                </RectangleGeometry>-->
            </Path.Data>
        </Path>

        <Border VerticalAlignment="Top" HorizontalAlignment="Left"
                Width="100" Height="50" Background="Orange" Name="border" Visibility="Collapsed">
            <Border.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="0" x:Name="rt"/>
                    <TranslateTransform X="0" Y="0" x:Name="tt"/>
                </TransformGroup>
            </Border.RenderTransform>
        </Border>

        <Border VerticalAlignment="Top" HorizontalAlignment="Left"
                Width="100" Height="50" Background="Green">
            <Border.RenderTransform>
                <MatrixTransform x:Name="mt"/>
            </Border.RenderTransform>
        </Border>

        <Button Content="开始" VerticalAlignment="Bottom" Name="btn"/>
    </Grid>
</Window>

四、辅助属性

1. 属性介绍

  • SpeedRatio:播放速度
  • AccelerationRatio:加速速率
  • DecelerationRatio:减速速率
  • AutoReverse:是否执行相反的动画
  • FillBehavior:动画结束状态:HoldEnd、Stop
  • RepeatBehavior:动画重复方式,包括三种值:Forever、次数、时间

前面这些属性在Animation对象中也可以设置

  • IsAddtive:将目标属性的当前值添加到动画的起始值

  • IsCumulative:如果动画不断重复,就累积动画值

  • BeginTime:动画线启动等待时长

  • EasingFunction:动画缓动属性,EasingMode

  • BackEase、CircleEase、CubicEase、ElasticEase、ExponentialEase、PowerEase、QuadraticEase、QuarticEase、QuinticEase、SineEase

  • Timeline.DesiredFrameRate:设置帧率

2. 实操

public class ViewModel : INotifyPropertyChanged
{
    public Thickness Value { get; set; } = new Thickness(300, 0, 0, 0);

    public event PropertyChangedEventHandler? PropertyChanged;


    public ViewModel()
    {
        Task.Run(async () =>
        {
            await Task.Delay(5000);
            Value = new Thickness(100, 0, 0, 0);
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
        });
    }
}
<Window x:Class="AnimationLesson.AnimationPropertyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson"
        mc:Ignorable="d"
        Left="0"
        Title="AnimationPropertyWindow" Height="450" Width="800" Name="win">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <Storyboard x:Key="sb">
            <!--动画控制窗口位置-->
            <!--<DoubleAnimation Duration="0:0:4"
                             Storyboard.TargetName="win"
                             Storyboard.TargetProperty="Left"
                             From="0"
                              To="300"/>-->
            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border1"
                                Storyboard.TargetProperty="Margin"
                                From="{Binding Value}" To="400,0,0,0"/>
            
            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border2"
                                Storyboard.TargetProperty="Margin"
                                From="0" To="400,0,0,0"
                                SpeedRatio="2"/>

            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border3"
                                Storyboard.TargetProperty="Margin"
                                From="{Binding}" To="400,0,0,0"
                                AccelerationRatio="0.3"
                                DecelerationRatio="0.7"/>

            <!--自动返回起点-->
            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border4"
                                Storyboard.TargetProperty="Margin"
                                From="0" To="400,0,0,0"
                                AutoReverse="True"/>


            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border5"
                                Storyboard.TargetProperty="Margin"
                                From="0" To="400,0,0,0"
                                FillBehavior="Stop"/>

            <!--RepeatBehavior三个类型的参数值:Forever永远重复、指定重复次数(2x)、指定重复执行时间-->
            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border6"
                                Storyboard.TargetProperty="Margin"
                                From="0" To="400,0,0,0"
                                RepeatBehavior="0:0:5" AutoReverse="True"/>


            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border7"
                                Storyboard.TargetProperty="Margin"
                                From="0" To="200,0,0,0"
                                IsAdditive="True"/>

            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border8"
                                Storyboard.TargetProperty="Margin"
                                To="200,0,0,0"/>

            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border9"
                                Storyboard.TargetProperty="Margin"
                                From="0" To="200,0,0,0"
                                IsCumulative="True"
                                RepeatBehavior="3x"/>
            
            <ThicknessAnimation Duration="0:0:4"
                                Storyboard.TargetName="border10"
                                Storyboard.TargetProperty="Margin"
                                To="200,0,0,0"
                                IsCumulative="True"/>

        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn" >
            <BeginStoryboard Storyboard="{StaticResource sb}">
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <StackPanel>
            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Orange" Name="border1">
            </Border>
            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Green" Name="border2">
            </Border>
            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Gray" Name="border3">
            </Border>
            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Blue" Name="border4">
            </Border>
            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Red" Name="border5">
            </Border>
            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Brown" Name="border6">
            </Border>
            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Pink" Name="border7">
            </Border>
            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Pink" Name="border8">
            </Border>

            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Aqua" Name="border9">
            </Border>
            <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
                Width="80" Height="30" Background="Aqua" Name="border10">
            </Border>
        </StackPanel>

        <Button Content="开始" VerticalAlignment="Bottom" Name="btn"/>
    </Grid>
</Window>

五、生命周期事件

1. 事件介绍

  • Completed
  • CurrentGlobalSpeedInvalidated:速度变化
  • CurrentStateInvalidated:状态变化
  • CurretnTimeInvalidated:时间线

2. 实操

<Window x:Class="AnimationLesson.AnimationProperty2Window"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson"
        mc:Ignorable="d"
        Title="AnimationProperty2Window" Height="500" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb" Timeline.DesiredFrameRate="60"
                    Completed="Storyboard_Completed"
                    CurrentGlobalSpeedInvalidated="Storyboard_CurrentGlobalSpeedInvalidated"
                    CurrentStateInvalidated="Storyboard_CurrentStateInvalidated"
                    CurrentTimeInvalidated="Storyboard_CurrentTimeInvalidated">
            <ThicknessAnimation Duration="0:0:4"
                     Storyboard.TargetName="border1"
                     Storyboard.TargetProperty="Margin"
                     From="0" To="400,0,0,0"/>

            <!--<ThicknessAnimation Duration="0:0:4"
                     Storyboard.TargetName="border2"
                     Storyboard.TargetProperty="Margin"
                     From="0" To="400,0,0,0"
                                BeginTime="0:0:2"/>-->

            <ThicknessAnimation Duration="0:0:4"
                     Storyboard.TargetName="border2"
                     Storyboard.TargetProperty="Margin"
                     From="0" To="400,0,0,0"/>


            <ThicknessAnimation Duration="0:0:4"
                     Storyboard.TargetName="border3"
                     Storyboard.TargetProperty="Margin"
                     From="0" To="400,0,0,0">
            </ThicknessAnimation>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn" >
            <BeginStoryboard Storyboard="{StaticResource sb}">
            </BeginStoryboard>
        </EventTrigger>

        <EventTrigger RoutedEvent="Button.Click" SourceName="bt1">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:1" From="0" To="500,0,0,0" Storyboard.TargetName="bor1" Storyboard.TargetProperty="Margin"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt2">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor2" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <BounceEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt3">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor3" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <BackEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt4">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor4" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <CircleEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt5">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor5" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <CubicEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt6">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor6" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <ElasticEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt7">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor7" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <ExponentialEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt8">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor8" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <PowerEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt9">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor9" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <QuadraticEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt10">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor10" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <QuarticEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt11">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor11" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <QuinticEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Button.Click" SourceName="bt12">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:5" From="0" To="500,0,0,0" Storyboard.TargetName="bor12" Storyboard.TargetProperty="Margin">
                        <ThicknessAnimation.EasingFunction>
                            <SineEase/>
                        </ThicknessAnimation.EasingFunction>
                    </ThicknessAnimation>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>
    <StackPanel>
        <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
     Width="80" Height="30" Background="Orange" Name="border1">
        </Border>
        <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
     Width="80" Height="30" Background="Green" Name="border2">
        </Border>
        <Border VerticalAlignment="Top" HorizontalAlignment="Left" 
     Width="80" Height="30" Background="Gray" Name="border3">
        </Border>


        <Grid Height="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="auto"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBlock Text="无" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            <TextBlock Text="BounceEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="1"/>
            <TextBlock Text="BackEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="2"/>
            <TextBlock Text="CircleEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="3"/>
            <TextBlock Text="CubicEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="4"/>
            <TextBlock Text="ElasticEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="5"/>
            <TextBlock Text="ExponentialEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="6"/>
            <TextBlock Text="PowerEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="7"/>
            <TextBlock Text="QuadraticEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="8"/>
            <TextBlock Text="QuarticEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="9"/>
            <TextBlock Text="QuinticEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="10"/>
            <TextBlock Text="SineEase" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="11"/>

            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Name="bor1"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="1" Name="bor2"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="2" Name="bor3"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="3" Name="bor4"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="4" Name="bor5"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="5" Name="bor6"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="6" Name="bor7"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="7" Name="bor8"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="8" Name="bor9"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="9" Name="bor10"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="10" Name="bor11"/>
            <Border Width="30" Height="30" Background="Orange" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="11" Name="bor12"/>

            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Name="bt1"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="1" Name="bt2"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="2" Name="bt3"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="3" Name="bt4"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="4" Name="bt5"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="5" Name="bt6"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="6" Name="bt7"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="7" Name="bt8"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="8" Name="bt9"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="9" Name="bt10"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="10" Name="bt11"/>
            <Button Width="40" Height="30" Content="开始" Grid.Column="1" VerticalAlignment="Center" Grid.Row="11" Name="bt12"/>
        </Grid>
        <Button Content="开始" VerticalAlignment="Bottom" Name="btn"/>
        <Button Content="Button" VerticalAlignment="Bottom" Click="Button_Click"/>
    </StackPanel>
</Window>
public partial class AnimationProperty2Window : Window
{
    public AnimationProperty2Window()
    {
        InitializeComponent();
    }

    private void Storyboard_Completed(object sender, EventArgs e)
    {
        Debug.WriteLine("===========Storyboard_Completed============");
    }

    private void Storyboard_CurrentGlobalSpeedInvalidated(object sender, EventArgs e)
    {
        Debug.WriteLine("===========Storyboard_CurrentGlobalSpeedInvalidated============");
    }

    private void Storyboard_CurrentStateInvalidated(object sender, EventArgs e)
    {
        Debug.WriteLine("===========Storyboard_CurrentStateInvalidated============");
    }

    private void Storyboard_CurrentTimeInvalidated(object sender, EventArgs e)
    {
        Debug.WriteLine("===========Storyboard_CurrentTimeInvalidated============");
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var v1 = this.border1.Margin;
        var v2 = this.border2.Margin;
        var v3 = this.border3.Margin;

        this.border1.Margin = new Thickness(200, 0, 0, 0);
        // 对象先进行动画变化     完成之后进行相关的属性设置,发现 ,设置不了?
    }
}

六、动画控制

1. 动画控制方式

  • 动画的启动:事件、触发器、视觉管理器
  • 事件控制
    • BeginStoryboard:开始中一个故事板
    • PauseStoryboard:暂停
    • ResumeStoryboard:恢复
    • StopStoryboard:停止
    • SeekStoryboard:跳转某一帧,某个时刻
    • SetStoryboardSpeedRatio:加速、减速
  • 触发器控制
    • EnterActions
    • ExitActions

2. 事件控制实操

<Window x:Class="AnimationLesson.AnimationControlWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson"
        mc:Ignorable="d"
        Title="AnimationControlWindow" Height="450" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb">
            <ThicknessAnimation Duration="0:0:5"
                                From="0" To="600,0,0,0"
                                Storyboard.TargetName="bor_1"
                                Storyboard.TargetProperty="Margin"/>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <!--开始-->
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn_1">
            <BeginStoryboard Storyboard="{StaticResource sb}" Name="bsb"/>
        </EventTrigger>
        <!--暂停-->
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn_2">
            <PauseStoryboard BeginStoryboardName="bsb"/>
        </EventTrigger>
        <!--恢复-->
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn_3">
            <ResumeStoryboard BeginStoryboardName="bsb"/>
        </EventTrigger>
        <!--停止-->
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn_4">
            <StopStoryboard BeginStoryboardName="bsb"/>
        </EventTrigger>
        <!--跳转到某个时刻-->
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn_5">
            <SeekStoryboard BeginStoryboardName="bsb" Offset="0:0:3"/>
        </EventTrigger>
        <!--加速-->
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn_6">
            <SetStoryboardSpeedRatio BeginStoryboardName="bsb" SpeedRatio="3"/>
        </EventTrigger>
        <!--减速-->
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn_7">
            <SetStoryboardSpeedRatio BeginStoryboardName="bsb" SpeedRatio="0.3"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Border Background="Orange" Width="50" Height="50" Name="bor_1" HorizontalAlignment="Left"/>
        <UniformGrid Rows="1" VerticalAlignment="Bottom">
            <Button Content="开始" Name="btn_1"/>
            <Button Content="暂停" Name="btn_2"/>
            <Button Content="恢复" Name="btn_3"/>
            <Button Content="停止" Name="btn_4"/>
            <Button Content="跳转某一帧" Name="btn_5"/>
            <Button Content="加速" Name="btn_6"/>
            <Button Content="减速" Name="btn_7"/>
        </UniformGrid>
    </Grid>
</Window>

3. 触发器控制实操

<Window x:Class="AnimationLesson.AnimationTriggerWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson"
        mc:Ignorable="d"
        Title="AnimationTriggerWindow" Height="450" Width="800">
    <Window.Resources>
        <ControlTemplate TargetType="CheckBox" x:Key="cbTemp">
            <Border Background="{TemplateBinding Background}" Name="border"
                    Width="50" Height="50">
                <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="IsChecked" Value="True">
                    <Setter TargetName="border" Property="Background" Value="Orange"/>

                    <!--触发器条件满足的时候执行-->
                    <!--执行时机:这个对象的IsChecked属性为True的时候-->
                    <Trigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:2"
                                                 From="50" To="100"
                                                 Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="Width"/>
                                <DoubleAnimation Duration="0:0:2"
                                                 From="50" To="100"
                                                 Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="Height"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                    <!--触发器条件不满足的时候执行-->
                    <!--没有写From:表示动画执行的起始值从对象当前状态下的相关属性值开始变化-->
                    <!--没有写To:表示动画执行的目标值以对象的初始状态下的相关属性值为结束-->
                    <Trigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:2"
                                                 Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="Width"/>
                                <DoubleAnimation Duration="0:0:2"
                                                 Storyboard.TargetName="border"
                                                 Storyboard.TargetProperty="Height"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.ExitActions>
                </Trigger>

            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Window.Resources>
    <Grid>
        <CheckBox Background="Gray" Template="{StaticResource cbTemp}"
                  VerticalAlignment="Center"  HorizontalAlignment="Center"/>
    </Grid>
</Window>

七、视觉状态管理器

1. 视图状态相关属性介绍

  • VisualState: 视图状态(Visual States)表示控件在一个特殊的逻辑状态下的样式、外观;
  • VisualStateGroup: 状态组由相互排斥的状态组成,状态组与状态组并不互斥;
  • VisualTransition: 视图转变 (Visual Transitions) 代表控件从一个视图状态向另一个状态转换时的过渡;
  • VisualStateManager: 由它负责在代码中来切换到不同的状态;
  • GoToState:针对控件模板中的视觉状态进行切换
  • GoToElementState:针对某个对象中的视觉状态进行切换

2. 实操

<Window x:Class="AnimationLesson.AnimationStateWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson"
        mc:Ignorable="d"
        Title="AnimationStateWindow" Height="450" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb">
            <ThicknessAnimation Duration="0:0:5"
                            From="0" To="600,0,0,0"
                            Storyboard.TargetName="bor_1"
                            Storyboard.TargetProperty="Margin"/>
        </Storyboard>
    </Window.Resources>

    <VisualStateManager.VisualStateGroups>
        <!--这里可以存放多个Group-->
        <VisualStateGroup>
            <VisualState Name="state_1">
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:2"
                                        From="0" To="600,0,0,0"
                                        Storyboard.TargetName="bor_1"
                                        Storyboard.TargetProperty="Margin"/>
                </Storyboard>
            </VisualState>
            <VisualState Name="state_2">
                <Storyboard>
                    <ColorAnimation Duration="0:0:2"
                        To="Green"
                        Storyboard.TargetName="bor_1"
                        Storyboard.TargetProperty="Background.Color"/>
                </Storyboard>
            </VisualState>
            <VisualState Name="state_3"/>
        </VisualStateGroup>

        <!--<VisualStateGroup>
            
        </VisualStateGroup>-->
    </VisualStateManager.VisualStateGroups>    
    
    <Grid>

        <Border Background="Orange" Width="50" Height="50" Name="bor_1" HorizontalAlignment="Left"/>

        <StackPanel VerticalAlignment="Bottom">
            <Button Content="执行第一个状态" Click="Button_Click"/>
            <Button Content="执行第二个状态" Click="Button_Click_1"/>
            <Button Content="执行第三个状态" Click="Button_Click_2"/>
        </StackPanel>
    </Grid>
</Window>
public partial class AnimationStateWindow : Window
{
    public AnimationStateWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        VisualStateManager.GoToElementState(this, "state_1", true);
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        VisualStateManager.GoToElementState(this, "state_2", true);
    }

    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        VisualStateManager.GoToElementState(this, "state_3", true);
    }
}

八、案例

1. 菜单隐藏

<Window x:Class="AnimationLesson.Example.DrawerWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson.Example"
        mc:Ignorable="d"
        Title="DrawerWindow" Height="450" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb">
            <ThicknessAnimation Duration="0:0:0.5"
                            To="0"
                            Storyboard.TargetName="border"
                            Storyboard.TargetProperty="Margin"/>
        </Storyboard>
    </Window.Resources>

    <Window.Triggers>
        <EventTrigger RoutedEvent="Button.Click" SourceName="btn_1">
            <BeginStoryboard Storyboard="{StaticResource sb}"/>
        </EventTrigger>

        <EventTrigger RoutedEvent="Button.Click" SourceName="btn_2">
            <BeginStoryboard>
                <Storyboard>
                    <ThicknessAnimation Duration="0:0:0.5"
                    Storyboard.TargetName="border"
                    Storyboard.TargetProperty="Margin"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Button Width="30" Height="30" VerticalAlignment="Top" HorizontalAlignment="Left"
                Name="btn_1"/>
        <Border Width="180" Background="#DDD" HorizontalAlignment="Left"
                Margin="-180,0,0,0" Name="border">
            <Button Width="30" Height="30" VerticalAlignment="Top" HorizontalAlignment="Right"
                    Name="btn_2"/>
        </Border>
    </Grid>
</Window>

2. 进度等待

<Window x:Class="AnimationLesson.Example.LoadingWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson.Example"
        mc:Ignorable="d"  WindowStartupLocation="CenterScreen"
        Title="LoadingWindow" Height="450" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb" RepeatBehavior="Forever">
            <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="ellipse_1"
                                  Storyboard.TargetProperty="Margin">
                <SplineThicknessKeyFrame Value="0,0,0,0" KeyTime="0:0:0"/>
                <SplineThicknessKeyFrame KeyTime="00:00:02" Value="315,0,0,0" KeySpline="0.1,0.7,0.3,0.1"/>
            </ThicknessAnimationUsingKeyFrames>
            <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="ellipse_2"
                                  Storyboard.TargetProperty="Margin" BeginTime="0:0:0.3">
                <SplineThicknessKeyFrame Value="0,0,0,0" KeyTime="0:0:0"/>
                <SplineThicknessKeyFrame KeyTime="00:00:02" Value="315,0,0,0" KeySpline="0.1,0.7,0.3,0.1"/>
            </ThicknessAnimationUsingKeyFrames>

            <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="ellipse_3"
                                  Storyboard.TargetProperty="Margin" BeginTime="0:0:0.6">
                <SplineThicknessKeyFrame Value="0,0,0,0" KeyTime="0:0:0"/>
                <SplineThicknessKeyFrame KeyTime="00:00:02" Value="315,0,0,0" KeySpline="0.1,0.7,0.3,0.1"/>
            </ThicknessAnimationUsingKeyFrames>


            <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="ellipse_4"
                                  Storyboard.TargetProperty="Margin" BeginTime="0:0:0.9">
                <SplineThicknessKeyFrame Value="0,0,0,0" KeyTime="0:0:0"/>
                <SplineThicknessKeyFrame KeyTime="00:00:02" Value="315,0,0,0" KeySpline="0.1,0.7,0.3,0.1"/>
            </ThicknessAnimationUsingKeyFrames>
        </Storyboard>

        <Storyboard x:Key="sb_2">
            <RectAnimation Duration="0:0:1"
                           To="20,0,20,15"
                           Storyboard.TargetName="vb"
                           Storyboard.TargetProperty="Viewport"
                           RepeatBehavior="Forever"/>
        </Storyboard>
        <SolidColorBrush x:Key="ProgressBar.Progress" Color="#FF06B025"/>
        <SolidColorBrush x:Key="ProgressBar.Background" Color="#FFE6E6E6"/>
        <SolidColorBrush x:Key="ProgressBar.Border" Color="#FFBCBCBC"/>
        <Style x:Key="ProgressBarStyle1" TargetType="{x:Type ProgressBar}">
            <Setter Property="Foreground" Value="{StaticResource ProgressBar.Progress}"/>
            <Setter Property="Background" Value="{StaticResource ProgressBar.Background}"/>
            <Setter Property="BorderBrush" Value="{StaticResource ProgressBar.Border}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ProgressBar}">
                        <Grid x:Name="TemplateRoot">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Determinate"/>
                                    <VisualState x:Name="Indeterminate">
                                        <Storyboard RepeatBehavior="Forever">
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Animation" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
                                                <EasingDoubleKeyFrame KeyTime="0" Value="0.25"/>
                                                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.25"/>
                                                <EasingDoubleKeyFrame KeyTime="0:0:2" Value="0.25"/>
                                            </DoubleAnimationUsingKeyFrames>
                                            <PointAnimationUsingKeyFrames Storyboard.TargetName="Animation" Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)">
                                                <EasingPointKeyFrame KeyTime="0" Value="-0.5,0.5"/>
                                                <EasingPointKeyFrame KeyTime="0:0:1" Value="0.5,0.5"/>
                                                <EasingPointKeyFrame KeyTime="0:0:2" Value="1.5,0.5"/>
                                            </PointAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
                            <Rectangle x:Name="PART_Track"/>
                            <Grid x:Name="PART_Indicator" ClipToBounds="true" HorizontalAlignment="Left">
                                <Rectangle x:Name="Indicator" Fill="{TemplateBinding Foreground}"/>
                                <Rectangle x:Name="Animation" Fill="{TemplateBinding Foreground}" RenderTransformOrigin="0.5,0.5">
                                    <Rectangle.RenderTransform>
                                        <TransformGroup>
                                            <ScaleTransform/>
                                            <SkewTransform/>
                                            <RotateTransform/>
                                            <TranslateTransform/>
                                        </TransformGroup>
                                    </Rectangle.RenderTransform>
                                </Rectangle>
                            </Grid>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="Orientation" Value="Vertical">
                                <Setter Property="LayoutTransform" TargetName="TemplateRoot">
                                    <Setter.Value>
                                        <RotateTransform Angle="-90"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsIndeterminate" Value="true">
                                <Setter Property="Visibility" TargetName="Indicator" Value="Collapsed"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard Storyboard="{StaticResource sb_2}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Grid VerticalAlignment="Center" Width="300" Background="#EEE" ClipToBounds="True">
            <Ellipse Width="15" Height="15" Fill="Red" HorizontalAlignment="Left"
         Margin="-15,0,0,0" Name="ellipse_1"/>
            <Ellipse Width="15" Height="15" Fill="Red" HorizontalAlignment="Left"
Margin="-15,0,0,0" Name="ellipse_2"/>
            <Ellipse Width="15" Height="15" Fill="Red" HorizontalAlignment="Left"
Margin="-15,0,0,0" Name="ellipse_3"/>
            <Ellipse Width="15" Height="15" Fill="Red" HorizontalAlignment="Left"
Margin="-15,0,0,0" Name="ellipse_4"/>
        </Grid>

        <ProgressBar Style="{DynamicResource ProgressBarStyle1}" Height="15" Width="200" VerticalAlignment="Top"
                     Value="40">
            <ProgressBar.Foreground>
                <VisualBrush TileMode="Tile" Viewport="0,0,20,15" ViewportUnits="Absolute" x:Name="vb">
                    <VisualBrush.Visual>
                        <Border Background="Transparent">
                            <Border.RenderTransform>
                                <SkewTransform AngleX="-40"/>
                            </Border.RenderTransform>
                            <Border Width="20" Height="15" Margin="3,0" Background="Orange"/>
                        </Border>
                    </VisualBrush.Visual>
                </VisualBrush>
            </ProgressBar.Foreground>
        </ProgressBar>
    </Grid>
</Window>

3. 机械臂控制

<Window x:Class="AnimationLesson.Example.RobotWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson.Example"
        mc:Ignorable="d"
        Title="RobotWindow" Height="450" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb" AutoReverse="True" RepeatBehavior="Forever">
            <DoubleAnimation Duration="0:0:2"
                             To="200"
                             Storyboard.TargetName="tt"
                             Storyboard.TargetProperty="X"/>

            <DoubleAnimation Duration="0:0:3"
                             From="-40"
                             To="20"
                             Storyboard.TargetName="rt1"
                             Storyboard.TargetProperty="Angle"/>

            <DoubleAnimation Duration="0:0:2"
                             From="30"
                             To="70"
                             Storyboard.TargetName="rt2"
                             Storyboard.TargetProperty="Angle"/>
        </Storyboard>

        <TranslateTransform x:Key="tt" X="50"/>

    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard Storyboard="{StaticResource sb}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Border Width="50" Height="50" Background="Orange" CornerRadius="10">
            <Border.RenderTransform>
                <TranslateTransform X="0" x:Name="tt"/>
            </Border.RenderTransform>

            <Canvas>
                <Border Height="20" Width="120" Background="Green" Canvas.Left="13" Canvas.Top="-10"
                        CornerRadius="10">
                    <Border.RenderTransform>
                        <RotateTransform Angle="-40" x:Name="rt1" CenterX="10" CenterY="10"/>
                    </Border.RenderTransform>


                    <Canvas HorizontalAlignment="Right">
                        <Border Height="13" Width="100" Background="Red" Canvas.Left="-15" Canvas.Top="3"
                                CornerRadius="7">
                            <Border.RenderTransform>
                                <RotateTransform Angle="50" x:Name="rt2" CenterX="7.5" CenterY="7.5"/>
                            </Border.RenderTransform>
                        </Border>
                    </Canvas>
                </Border>
            </Canvas>
        </Border>

        <Border Width="50" Height="50" Background="Gray" VerticalAlignment="Bottom"
                RenderTransform="{StaticResource tt}">
        </Border>

        <Border Width="30" Height="100" Background="Orange" VerticalAlignment="Bottom">
            <Border.RenderTransform>
                <TransformGroup>
                    <TranslateTransform/>
                    <RotateTransform/>
                </TransformGroup>
            </Border.RenderTransform>
        </Border>

        <Border Width="130" Height="20" Background="Green" VerticalAlignment="Bottom"
                RenderTransform="{StaticResource tt}">
        </Border>

    </Grid>
</Window>

4. 蚂蚁线

<Window x:Class="AnimationLesson.Example.AntLineWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson.Example"
        mc:Ignorable="d" WindowStartupLocation="CenterScreen"
        Title="AntLineWindow" Height="450" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb" RepeatBehavior="Forever">
            <DoubleAnimation Duration="0:0:1"
                             To="-6"
                             Storyboard.TargetName="path"
                             Storyboard.TargetProperty="StrokeDashOffset"/>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard Storyboard="{StaticResource sb}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Path Data="M0,0  100 100A50 50 0 0 0 200 150" Stroke="Orange" StrokeThickness="5"
              StrokeDashArray="3,3" StrokeDashOffset="0" Name="path"/>
    </Grid>
</Window>

5. 液面

<Window x:Class="AnimationLesson.Example.WaterWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationLesson"
        mc:Ignorable="d"
        Title="WaterWindow" Height="450" Width="800">
    <Window.Resources>
        <Storyboard x:Key="sb">
            <DoubleAnimation Duration="0:0:1"
                             To="-100"
                             Storyboard.TargetName="tt"
                             Storyboard.TargetProperty="X" RepeatBehavior="Forever"/>
            <DoubleAnimation Duration="0:0:1.6"
                             To="-100"
                             Storyboard.TargetName="tt1"
                             Storyboard.TargetProperty="X"
                             BeginTime="0:0:0.2" RepeatBehavior="Forever"/>
            
            <DoubleAnimation Duration="0:0:1.2"
                             To="0"
                             Storyboard.TargetName="tt2"
                             Storyboard.TargetProperty="X"
                             BeginTime="0:0:0.4" RepeatBehavior="Forever"/>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard Storyboard="{StaticResource sb}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Border Width="100" Height="100" Background="#DDD" CornerRadius="50">
            <Border.Clip>
                <EllipseGeometry Center="50,50" RadiusX="50" RadiusY="50"/>
            </Border.Clip>
            <Canvas ClipToBounds="True">
                <Path Data="
                      M0 0
                      A40 40 0 0 0 50 0
                      A40 40 0 0 1 100 0
                      A40 40 0 0 0 150 0
                      A40 40 0 0 1 200 0
                      L200 100 0 100" Fill="#9F90">
                    <Path.RenderTransform>
                        <TranslateTransform X="0" Y="40" x:Name="tt1"/>
                    </Path.RenderTransform>
                </Path>
                
                <Path Data="
                  M0 0
                  A50 50 0 0 0 50 0
                  A50 50 0 0 1 100 0
                  A50 50 0 0 0 150 0
                  A50 50 0 0 1 200 0
                  L200 100 0 100" Fill="Orange">
                    <Path.RenderTransform>
                        <TranslateTransform X="0" Y="40" x:Name="tt"/>
                    </Path.RenderTransform>
                </Path>

                <Path Data="
                  M0 0
                  A50 50 0 0 0 50 0
                  A50 50 0 0 1 100 0
                  A50 50 0 0 0 150 0
                  A50 50 0 0 1 200 0
                  L200 100 0 100" Fill="Green" Opacity="0.2">
                    <Path.RenderTransform>
                        <TranslateTransform X="-100" Y="40" x:Name="tt2"/>
                    </Path.RenderTransform>
                </Path>
            </Canvas>
        </Border>
    </Grid>
</Window>