c# - WPF DataTrigger 动画只触发一次
问题描述
我有一个 MVVM 模式应用程序,我希望用户能够输入日期,但也对这些日期应用一些验证。我通过检查他们输入的任何内容并用最近的有效日期覆盖它来做到这一点,如果他们的输入无效。为了让用户知道他们的日期已被覆盖,我会尝试为日期选择器文本框的前景设置动画,但我发现动画仅在他们的日期第一次以这种方式“更正”时可见.
在 MainViewModel 中,我有一个 Ping 属性,它在每次设置为“true”时通知 UI,以及一个验证方法,Ping = true
每次设置它必须覆盖一个日期:
public bool Ping
{
get => _ping;
set
{
if (value && !_ping)
{
_ping = value;
OnPropertyChanged();
_ping = false;
}
}
}
private DateTime _from;
//Bound to the Date input field in the UI
public DateTime From
{
get { return _from; }
set
{
if (_from != value)
{
_from = giveValidDate("From", value);
OnPropertyChanged();
}
}
}
private DateTime giveValidDate(string posn, DateTime givenDate)
{
DateTime validDate = new DateTime();
// [...A Load of validation that results in a valid Date output...] //
Ping = givenDate != validDate;
return validDate;
}
我正在使用一种 TextBox 样式,上面有动画:
<Style x:Key="PingableTextBox" TargetType="TextBox">
<Setter Property="TextBlock.FontSize" Value="18"/>
<Setter Property="TextElement.FontSize" Value="18"/>
<Setter Property="TextElement.Foreground" Value="{StaticResource Text_LightBrush}"/>
<Setter Property="TextElement.FontWeight" Value="Normal"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
CornerRadius="2"
BorderBrush="{StaticResource Highlight_LightBrush}"
Background="{StaticResource Empty_DarkBrush}"
x:Name="border"
SnapsToDevicePixels="True">
<ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
Name="PART_ContentHost" Focusable="False" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter Property="Border.BorderBrush" TargetName="border" Value="{StaticResource Good_MidBrush}"/>
<Setter Property="Cursor" Value="IBeam"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Ping}" Value="true">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="Pinger"/>
<BeginStoryboard Name="Pinger">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
From="{StaticResource Bad_Bright}" To="{StaticResource Text_Light}" FillBehavior="Stop"
Duration="0:0:0:1.0"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Pinger"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
但是,当我运行应用程序时,触发器只会执行一次(选择无效日期时会出现短暂的红色闪烁):
我在 Stack Overflow 上看到过很多关于同一问题的其他问题,但解决方案一直是<StopStoryboard BeginStoryboardName="Pinger"/>
在 Enter Actions 中添加该行,将该行添加<RemoveStoryboard BeginStoryboardName="Pinger"/>
到 Exit Actions 或添加FillBehavior="Stop"
到情节提要中。我已经在我能想到的所有地方尝试了每一种组合,但问题仍然存在。
对于我可能错过的问题是否有其他解释可以为我解决它,或者我未能正确实施的问题。简而言之,为什么它只触发一次?
PS - 我用来实现您在上面看到的代码的一些问题:
解决方案
您必须PropertyChanged
在重置Ping
属性后提高 才能触发Trigger.ExitAction
。
设置支持字段_ping
不会将任何更改通知传播到视图。
这意味着您的问题不是您引用的答案试图解决的问题。
你也不应该Trigger.ExitAction
在你的场景中定义。由于您已将动画配置为在时间线完成后自动停止 ( FillBehavior="Stop"
),因此您无需执行任何操作来停止它。请注意,RemoveStoryboard
这对您的情况没有任何帮助。它只会使重置属性的逻辑复杂化,因为RemoveStoryboard
会在即时属性切换时立即终止动画。这意味着,避免Trigger.ExitAction
或更准确地说,RemoveStoryboard
允许您立即切换属性:
// Trigger the animation
Ping = givenDate != validDate;
// Reset the property immediately to reset the animation trigger.
// Because the `Trigger.ExitAction` is deleted,
// the currently running animation will complete the timeline.
Ping = false;
如果您想更优雅地实现逻辑,您可以切换Ping
属性并定义Trigger.EnterAction
状态true
和Trigger.ExitAction
状态false
(从而将每个状态转换为验证错误信号):
public bool Ping
{
get => _ping;
set
{
if (value && !_ping)
{
_ping = value;
OnPropertyChanged();
}
}
}
private DateTime giveValidDate(string posn, DateTime givenDate)
{
DateTime validDate = new DateTime();
// [...A Load of validation that results in a valid Date output...] //
// Trigger the animation by toggling the property.
if (givenDate != validDate)
{
Ping ^= true;
}
return validDate;
}
<DataTrigger Binding="{Binding Ping}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
From="{StaticResource Bad_Bright}" To="{StaticResource Text_Light}" FillBehavior="Stop"
Duration="0:0:0:1.0"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
From="{StaticResource Bad_Bright}" To="{StaticResource Text_Light}" FillBehavior="Stop"
Duration="0:0:0:1.0"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
推荐阅读
- azure - Azure DevOps 我无法获得 1800 分钟的 MS 托管
- python - 如何使用python脚本分析不同图形的图像(图像格式)
- reactjs - API 响应在使用时未定义,但在 console.log() 时未定义
- python - 如何在样式化的 QFrame 中设置 QWidget 的背景样式?
- javascript - 如何使用 NextJS 预渲染解决“无法读取未定义的属性 'title'”?
- amazon-cloudformation - CloudFormation 的托管区域 ID
- android - 为什么更改默认应用程序名称在使用颤振构建的 android productFlavors 中不起作用
- r - 如何找到文件在容器内的位置?
- javascript - 根据api更改切换主路径
- ios - 程序化导航 SwiftUI:重新选择和选择屏幕外链接的问题