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,通过转换器把枚举值转为对应角度:
- 创建转换器类:
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(); } }
- 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
相关产品推荐
相关产品推荐

