WPF动画仅在一个方向上工作

WPF动画仅在一个方向上工作,wpf,xaml,Wpf,Xaml,我正在制作一个由xaml中的单选按钮控制的“红绿灯”动画。我正在使用椭圆样式来更改颜色并设置运动动画。问题是,动画仅在椭圆向下移动(到较高的Canvas.Top值)时起作用,但在向上移动(到较低的Canvas.Top值)时不起作用 代码如下: <Window x:Class="hw05.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quo

我正在制作一个由xaml中的单选按钮控制的“红绿灯”动画。我正在使用椭圆样式来更改颜色并设置运动动画。问题是,动画仅在椭圆向下移动(到较高的Canvas.Top值)时起作用,但在向上移动(到较低的Canvas.Top值)时不起作用

代码如下:

<Window x:Class="hw05.MainWindow"
        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:hw05"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.Resources>
        <Style TargetType="Ellipse">
            <Setter Property="Fill" Value="Red"></Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsChecked, ElementName=RedRB}" Value="True">
                    <Setter Property="Fill" Value="Red"></Setter>
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation
                                    Storyboard.TargetProperty="(Canvas.Top)" Duration="0:0:0.400" To="83">
                                </DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>

                <DataTrigger Binding="{Binding IsChecked, ElementName=YellowRB}" Value="True">
                    <Setter Property="Fill" Value="Orange"></Setter>
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation
                                    Storyboard.TargetProperty="(Canvas.Top)" Duration="0:0:0.400" To="133">
                                </DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>

                <DataTrigger Binding="{Binding IsChecked, ElementName=GreenRB}" Value="True">
                    <Setter Property="Fill" Value="Green"></Setter>
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation
                                    Storyboard.TargetProperty="(Canvas.Top)" Duration="0:0:0.400" To="183">
                                </DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    
    <Canvas>
        <RadioButton Name="RedRB" GroupName="One" IsChecked="True" Canvas.Left="50" Canvas.Top="100">first</RadioButton>
        <RadioButton Name="YellowRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="150">second</RadioButton>
        <RadioButton Name="GreenRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="200">third</RadioButton>
        <Ellipse Name="Light" Width="50" Height="50" Canvas.Left="180" Canvas.Top="83"></Ellipse>
    </Canvas>
</Window>


第一
第二
第三

您应该知道像
Trigger
DataTrigger
这样的触发器是基于状态的:您有一个enter操作来反映到状态的转换(例如,
IsChecked
false
=>
true
),还有一个exit操作来反映从状态的转换(例如,
IsChecked
true
=>
false
)。您当前仅为进入转换定义动画。因此,从动画的角度来看,进入状态永远不会保留。
DataTrigger。EnterAction
将保留动画状态,直到
DataTrigger。ExitAction
已执行=>基于状态

在您的场景中,触发基于事件的动画更有意义:动画在某个事件发生时执行(例如,
RadioButton.Checked
),并一直保持到下一个事件发生。每个动画都会为上一个动画的值设置动画(如果
FillBehavior=“hold”
,这是默认设置)

以下示例已将动画移动到
画布
,因为这定义了所有参与元素的通用名称范围:

<Canvas>
  <RadioButton Name="RedRB" GroupName="One" IsChecked="True" Canvas.Left="50" Canvas.Top="100">first</RadioButton>
  <RadioButton Name="YellowRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="150">second</RadioButton>
  <RadioButton Name="GreenRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="200">third</RadioButton>
  <Ellipse Name="Light" 
           Fill="Red" 
           Width="50" Height="50" 
           Canvas.Left="180" Canvas.Top="83"  />


  <Canvas.Triggers>
    <EventTrigger RoutedEvent="RadioButton.Checked" SourceName="RedRB">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" 
                           Storyboard.TargetName="Light" 
                           Duration="0:0:0.400" To="83" />
          <ColorAnimation Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" 
                          Storyboard.TargetName="Light"
                          To="Red" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
    <EventTrigger RoutedEvent="RadioButton.Checked" SourceName="YellowRB">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" 
                           Storyboard.TargetName="Light" 
                           Duration="0:0:0.400" To="133" />
          <ColorAnimation Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" 
                          Storyboard.TargetName="Light"
                          To="Yellow" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
    <EventTrigger RoutedEvent="RadioButton.Checked" SourceName="GreenRB">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" 
                           Storyboard.TargetName="Light" 
                           Duration="0:0:0.400" To="183" />
          <ColorAnimation Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" 
                          Storyboard.TargetName="Light"
                          To="Green" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Canvas.Triggers>
</Canvas>

第一
第二
第三

您应该知道像
Trigger
DataTrigger
这样的触发器是基于状态的:您有一个enter操作来反映到状态的转换(例如,
IsChecked
false
=>
true
),还有一个exit操作来反映从状态的转换(例如,
IsChecked
true
=>
false
)。您当前仅为进入转换定义动画。因此,从动画的角度来看,进入状态永远不会保留。
DataTrigger。EnterAction
将保留动画状态,直到
DataTrigger。ExitAction
已执行=>基于状态

在您的场景中,触发基于事件的动画更有意义:动画在某个事件发生时执行(例如,
RadioButton.Checked
),并一直保持到下一个事件发生。每个动画都会为上一个动画的值设置动画(如果
FillBehavior=“hold”
,这是默认设置)

以下示例已将动画移动到
画布
,因为这定义了所有参与元素的通用名称范围:

<Canvas>
  <RadioButton Name="RedRB" GroupName="One" IsChecked="True" Canvas.Left="50" Canvas.Top="100">first</RadioButton>
  <RadioButton Name="YellowRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="150">second</RadioButton>
  <RadioButton Name="GreenRB" GroupName="One" IsChecked="False" Canvas.Left="50" Canvas.Top="200">third</RadioButton>
  <Ellipse Name="Light" 
           Fill="Red" 
           Width="50" Height="50" 
           Canvas.Left="180" Canvas.Top="83"  />


  <Canvas.Triggers>
    <EventTrigger RoutedEvent="RadioButton.Checked" SourceName="RedRB">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" 
                           Storyboard.TargetName="Light" 
                           Duration="0:0:0.400" To="83" />
          <ColorAnimation Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" 
                          Storyboard.TargetName="Light"
                          To="Red" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
    <EventTrigger RoutedEvent="RadioButton.Checked" SourceName="YellowRB">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" 
                           Storyboard.TargetName="Light" 
                           Duration="0:0:0.400" To="133" />
          <ColorAnimation Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" 
                          Storyboard.TargetName="Light"
                          To="Yellow" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
    <EventTrigger RoutedEvent="RadioButton.Checked" SourceName="GreenRB">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" 
                           Storyboard.TargetName="Light" 
                           Duration="0:0:0.400" To="183" />
          <ColorAnimation Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" 
                          Storyboard.TargetName="Light"
                          To="Green" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Canvas.Triggers>
</Canvas>

第一
第二
第三

为什么不直接设置
From
?因为From值需要根据椭圆的位置进行更改,我不确定如何进行更改。为什么不直接设置
From
?因为From值需要根据椭圆的位置进行更改,我不确定如何进行更改。