带有情节提要的数据触发器未触发
Datatrigger with Storyboard not firing
我在同一个图像上有 5 个不同的 DataTriggers,每个都用于相同的绑定但具有不同的值,每个都将图像旋转不同的角度。
每次更改值后,该值都会重置为 0。
当我没有添加 DataTrigger.ExitActions> <RemoveStoryboard>
东西时它们工作了一次,但它们只工作了一次,所以如果 steps
绑定再次获得这个值,它们就不会触发。
<Image x:Name="drehteller" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Source="{Binding drehteller_image}">
<Image.RenderTransform>
<RotateTransform/>
</Image.RenderTransform>
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding steps}" Value="1">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard1Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="72"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard1Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding steps}" Value="2">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard2Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="144"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard2Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding steps}" Value="3">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard3Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="216"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard3Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding steps}" Value="4">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard4Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="72"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard4Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding steps}" Value="5">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard5Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="360"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard5Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
也许有人知道我做错了什么,我认为 RemoveStoryboard
可能会解决他们只触发一个的问题,但看起来他们没有。
编辑:发现如果没有 ExitActions
我可以随心所欲地触发值为 1 的触发器,只要值永远不会高于 1,所以如果我一次触发值为 1 的触发器2,值为 1 的触发器将不再工作,如果我触发值为 3 的触发器,则值为 2 的触发器将不再工作。等等,我猜你明白了。
一个非常简单直接的解决方案是 运行 隐藏代码中的动画:
var viewModel = new ViewModel();
viewModel.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(viewModel.Steps))
{
drehteller.RenderTransform.BeginAnimation(
RotateTransform.AngleProperty,
new DoubleAnimation
{
By = viewModel.Steps * 72,
Duration = TimeSpan.FromSeconds(3)
});
}
};
DataContext = viewModel;
这与 MVVM 并不矛盾,因为视图模型仍然对视图一无所知。这是一个纯视图方面。
您也可以使用 attached behavior 执行此操作。这些是一些可重用的视图逻辑,您可以将它们附加到各种 UI 元素,而无需将它们放在代码隐藏中。
您需要 Microsoft.Xaml.Behaviors.Wpf NuGet package(这曾经作为 Visual Studio 的 "Blend for Visual Studio SDK for .NET" 组件的一部分分发,但这在 VS 2019 中发生了变化)。
定义你的行为。请注意,AssociatedObject
指的是与此行为关联的 Image
,请参见下文。
public class AnimateBehavior : Behavior<Image>
{
public int Steps
{
get => (int)GetValue(StepsProperty);
set => SetValue(StepsProperty, value);
}
public static readonly DependencyProperty StepsProperty =
DependencyProperty.Register(nameof(Steps), typeof(int), typeof(AnimateBehavior), new PropertyMetadata(0, (d, e) => ((AnimateBehavior)d).StepsChanged(e)));
private void StepsChanged(DependencyPropertyChangedEventArgs e)
{
if (AssociatedObject == null)
return;
AssociatedObject.RenderTransform.BeginAnimation(
RotateTransform.AngleProperty,
new DoubleAnimation()
{
By = (int)e.NewValue * 72,
Duration = TimeSpan.FromSeconds(3),
});
}
}
然后在您的 XAML 中,您将需要此命名空间:
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
然后:
<Image ...>
<Image.RenderTransform>
<RotateTransform/>
</Image.RenderTransform>
<behaviors:Interaction.Behaviors>
<local:AnimateBehavior Steps="{Binding steps}"/>
</behaviors:Interaction.Behaviors>
</Image>
我在同一个图像上有 5 个不同的 DataTriggers,每个都用于相同的绑定但具有不同的值,每个都将图像旋转不同的角度。 每次更改值后,该值都会重置为 0。
当我没有添加 DataTrigger.ExitActions> <RemoveStoryboard>
东西时它们工作了一次,但它们只工作了一次,所以如果 steps
绑定再次获得这个值,它们就不会触发。
<Image x:Name="drehteller" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Source="{Binding drehteller_image}">
<Image.RenderTransform>
<RotateTransform/>
</Image.RenderTransform>
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding steps}" Value="1">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard1Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="72"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard1Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding steps}" Value="2">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard2Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="144"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard2Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding steps}" Value="3">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard3Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="216"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard3Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding steps}" Value="4">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard4Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="72"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard4Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding steps}" Value="5">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard5Step">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
By="360"
Duration="00:00:00:03"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard5Step"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
也许有人知道我做错了什么,我认为 RemoveStoryboard
可能会解决他们只触发一个的问题,但看起来他们没有。
编辑:发现如果没有 ExitActions
我可以随心所欲地触发值为 1 的触发器,只要值永远不会高于 1,所以如果我一次触发值为 1 的触发器2,值为 1 的触发器将不再工作,如果我触发值为 3 的触发器,则值为 2 的触发器将不再工作。等等,我猜你明白了。
一个非常简单直接的解决方案是 运行 隐藏代码中的动画:
var viewModel = new ViewModel();
viewModel.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(viewModel.Steps))
{
drehteller.RenderTransform.BeginAnimation(
RotateTransform.AngleProperty,
new DoubleAnimation
{
By = viewModel.Steps * 72,
Duration = TimeSpan.FromSeconds(3)
});
}
};
DataContext = viewModel;
这与 MVVM 并不矛盾,因为视图模型仍然对视图一无所知。这是一个纯视图方面。
您也可以使用 attached behavior 执行此操作。这些是一些可重用的视图逻辑,您可以将它们附加到各种 UI 元素,而无需将它们放在代码隐藏中。
您需要 Microsoft.Xaml.Behaviors.Wpf NuGet package(这曾经作为 Visual Studio 的 "Blend for Visual Studio SDK for .NET" 组件的一部分分发,但这在 VS 2019 中发生了变化)。
定义你的行为。请注意,AssociatedObject
指的是与此行为关联的 Image
,请参见下文。
public class AnimateBehavior : Behavior<Image>
{
public int Steps
{
get => (int)GetValue(StepsProperty);
set => SetValue(StepsProperty, value);
}
public static readonly DependencyProperty StepsProperty =
DependencyProperty.Register(nameof(Steps), typeof(int), typeof(AnimateBehavior), new PropertyMetadata(0, (d, e) => ((AnimateBehavior)d).StepsChanged(e)));
private void StepsChanged(DependencyPropertyChangedEventArgs e)
{
if (AssociatedObject == null)
return;
AssociatedObject.RenderTransform.BeginAnimation(
RotateTransform.AngleProperty,
new DoubleAnimation()
{
By = (int)e.NewValue * 72,
Duration = TimeSpan.FromSeconds(3),
});
}
}
然后在您的 XAML 中,您将需要此命名空间:
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
然后:
<Image ...>
<Image.RenderTransform>
<RotateTransform/>
</Image.RenderTransform>
<behaviors:Interaction.Behaviors>
<local:AnimateBehavior Steps="{Binding steps}"/>
</behaviors:Interaction.Behaviors>
</Image>