You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中DataTrigger触发的旋转动画仅生效一次的问题排查

问题

我在窗口中放置了一个带箭头的Path控件,希望它根据BarcodeScanner.MovementDirection属性的值旋转,但动画仅在属性值第一次变化时生效,后续值变化时不再触发。以下是我的代码:

<Path Data="M12,7L17,12H14V16H10V12H7L12,7M19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21M19,19V5H5V19H19Z">
<Path.Style>
    <Style TargetType="Path" BasedOn="{StaticResource {x:Type Path}}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding BarcodeScanner.MovementDirection}" Value="Stay">
                <Setter Property="Visibility" Value="Hidden"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding BarcodeScanner.MovementDirection}" Value="Up">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)" To="0" Duration="0:0:0.2" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding BarcodeScanner.MovementDirection}" Value="Down">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)" To="180" Duration="0:0:0.2" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding BarcodeScanner.MovementDirection}" Value="Left">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)" To="-90" Duration="0:0:0.2" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding BarcodeScanner.MovementDirection}" Value="Right">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)" To="90" Duration="0:0:0.2" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
        </Style.Triggers>
        <Setter Property="RenderTransformOrigin" Value="0.5, 0.5"/>
        <Setter Property="RenderTransform">
            <Setter.Value>
                <RotateTransform Angle="0"/>
            </Setter.Value>
        </Setter>
    </Style>
</Path.Style>
原因与解决方法

问题核心是BeginStoryboard默认不会重启已完成的Storyboard,当同一个方向的属性值再次触发时,动画处于已完成状态,不会重新执行。

方法一:修改BeginStoryboard行为

给每个BeginStoryboard添加Name并设置Behavior="Stop",让触发时先停止之前的动画,再重新启动:

<DataTrigger Binding="{Binding BarcodeScanner.MovementDirection}" Value="Up">
    <DataTrigger.EnterActions>
        <BeginStoryboard Name="UpStoryboard" Behavior="Stop">
            <Storyboard>
                <DoubleAnimation Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)" To="0" Duration="0:0:0.2" />
            </Storyboard>
        </BeginStoryboard>
    </DataTrigger.EnterActions>
</DataTrigger>

对所有方向的DataTrigger重复此修改即可。

方法二:使用值转换器(更简洁)

直接将RotateTransform.Angle绑定到MovementDirection,通过转换器把枚举值转为对应角度:

  1. 创建转换器类:
public class DirectionToAngleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is MovementDirection direction)
        {
            return direction switch
            {
                MovementDirection.Up => 0,
                MovementDirection.Down => 180,
                MovementDirection.Left => -90,
                MovementDirection.Right => 90,
                _ => 0
            };
        }
        return 0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
  1. XAML中引用并绑定:
<Window.Resources>
    <local:DirectionToAngleConverter x:Key="DirectionToAngleConverter"/>
</Window.Resources>

<Path Data="M12,7L17,12H14V16H10V12H7L12,7M19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21M19,19V5H5V19H19Z">
    <Path.Style>
        <Style TargetType="Path" BasedOn="{StaticResource {x:Type Path}}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding BarcodeScanner.MovementDirection}" Value="Stay">
                    <Setter Property="Visibility" Value="Hidden"/>
                </DataTrigger>
            </Style.Triggers>
            <Setter Property="RenderTransformOrigin" Value="0.5, 0.5"/>
            <Setter Property="RenderTransform">
                <Setter.Value>
                    <RotateTransform Angle="{Binding BarcodeScanner.MovementDirection, Converter={StaticResource DirectionToAngleConverter}}"/>
                </Setter.Value>
            </Setter>
        </Style>
    </Path.Style>
</Path>

这种方法无需管理Storyboard,属性变化时会自动更新角度,逻辑更清晰。

内容的提问来源于stack exchange,提问作者Denis Schaf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 13:06:07