如何解决属性值在短窗口内多次更改时,不会触发DataTrigger
| 我在WPF应用程序中发现了一个有趣的问题,该问题与multidatatrigger没有启动StoryBoard来为数据网格单元设置动画有关。我有一个WPF数据网格控件,该控件绑定到包含实现INotifyPropertyChanged的POCO的ObservableCollection。 我想要实现的目标 实时数据网格,随着值的变化闪烁更新。当该值增加时,我希望该单元格闪烁绿色;当值减小时,我希望单元格闪烁红色。动画仅在1秒的时间间隔内将单元格的背景颜色从纯色变为透明。 问题 第一次后,multidatatrigger不会启动情节提要。 multidatatrigger正在监视对两个属性的更改:IsPositive和HasValueChanged。最初,HasValueChanged为false,然后在设置Value属性后立即从false更改为true,并且动画第一次生效。此后,HasValueChanged从false变为true,以触发更改通知,但动画未开始。 这是我应用于每个数据网格单元的XAML样式:<Style targettype=\"{x:Type TextBlock}\">
<Style.Setters>
<Setter Property=\"Background\"
Value=\"Aqua\" />
</Style.Setters>
<Style.Triggers>
<multidatatrigger>
<multidatatrigger.Conditions>
<Condition Binding=\"{Binding Path=HasValueChanged}\"
Value=\"True\" />
<Condition Binding=\"{Binding Path=IsPositive}\"
Value=\"True\" />
</multidatatrigger.Conditions>
<multidatatrigger.Enteractions>
<RemoveStoryboard BeginStoryboardName=\"PositiveValueCellStoryboard\" />
<RemoveStoryboard BeginStoryboardName=\"NegativeValueCellStoryboard\" />
<BeginStoryboard Name=\"PositiveValueCellStoryboard\"
Storyboard=\"{StaticResource PositiveValueCellAnimation}\"
HandoffBehavior=\"SnapShotAndReplace\" />
</multidatatrigger.Enteractions>
</multidatatrigger>
<multidatatrigger>
<multidatatrigger.Conditions>
<Condition Binding=\"{Binding Path=HasValueChanged}\"
Value=\"True\" />
<Condition Binding=\"{Binding Path=IsPositive}\"
Value=\"False\" />
</multidatatrigger.Conditions>
<multidatatrigger.Enteractions>
<RemoveStoryboard BeginStoryboardName=\"PositiveValueCellStoryboard\" />
<RemoveStoryboard BeginStoryboardName=\"NegativeValueCellStoryboard\" />
<BeginStoryboard Name=\"NegativeValueCellStoryboard\"
Storyboard=\"{StaticResource NegativeValueCellAnimation}\"
HandoffBehavior=\"SnapShotAndReplace\" />
</multidatatrigger.Enteractions>
</multidatatrigger>
</Style.Triggers>
</Style>
这是动画的XAML:
<Storyboard x:Key=\"NegativeValueCellAnimation\">
<ColorAnimation Storyboard.TargetProperty=\"Background.(SolidColorBrush.Color)\"
Timeline.DesiredFrameRate=\"10\"
RepeatBehavior=\"1x\"
From=\"Red\"
To=\"Transparent\"
Duration=\"0:0:1\" />
</Storyboard>
<Storyboard x:Key=\"PositiveValueCellAnimation\">
<ColorAnimation Storyboard.TargetProperty=\"Background.(SolidColorBrush.Color)\"
Timeline.DesiredFrameRate=\"10\"
RepeatBehavior=\"1x\"
From=\"Green\"
To=\"Transparent\"
Duration=\"0:0:1\" />
</Storyboard>
这是绑定到每个单元格的POCO对象的代码:
using System;
using System.Threading;
using Microsoft.Practices.Prism.viewmodel;
namespace RealTimeDataGrid
{
public class Cell : NotificationObject
{
public Cell(int ordinal,int value)
{
Ordinal = ordinal;
_value = value;
LastUpdated = DateTime.MaxValue;
}
public void SetValue(int value)
{
Value = value;
// pulse value changed to get WPF to fire DataTriggers
HasValueChanged = false;
Thread.Sleep(100);
HasValueChanged = true;
}
private int _value;
public int Value
{
get { return _value; }
private set
{
if (_value == value)
return;
_value = value;
// Performance optimization,using lambdas here causes performance issues
RaisePropertyChanged(\"IsPositive\");
RaisePropertyChanged(\"Value\");
}
}
private bool _hasValueChanged;
public bool HasValueChanged
{
get { return _hasValueChanged; }
set
{
if (_hasValueChanged == value)
return;
_hasValueChanged = value;
// Performance optimization,using lambdas here causes performance issues
RaisePropertyChanged(\"HasValueChanged\");
}
}
public int Ordinal { get; set; }
public DateTime LastUpdated { get; set; }
public bool IsPositive
{
get { return Value >= 0; }
}
public TimeSpan TimeSinceLastUpdate
{
get { return DateTime.Now.Subtract(LastUpdated); }
}
}
}
表观修复
在SetValue方法的两次设置HasValueChanged之间添加Thread.Sleep(100)似乎可以解决multidatatrigger不触发但具有不良副作用的问题。
问题的视频
单击此处查看损坏版本的视频。
单击此处观看固定版本的视频。
\'fixed \'版本不是理想的,因为Thread.Sleep导致单元以明显的顺序方式更新,而不是像损坏版本中那样同时更新。此外,在其中拥有Thread.Sleep会让我感觉很不好:)
首先;我要解决所有这些错误吗?有没有更简单/更好的方法来实现我想要的?如果不是,那么无需添加Thread.Sleep(代码气味!),该问题的解决方案是什么?
当值快速更改时,WPF为什么不触发DataTrigger?是否有某些因素导致WPF的'miss \'属性更改;还是WPF只是忽略在某个时间范围内从一个值到另一个值然后又回到原始值的更改?
谢谢你的帮助!
解决方法
对我来说,使用像事件这样的属性似乎比ѭ3更糟,我建议结合使用两个RoutedEvents(以区分
Changed+Positive
和Changed+Negative
)和EventTriggers。
如果您想坚持使用Thread.Sleep
,则可能应该在后台执行:
// IDE-free code,may be broken
HasValueChanged = false;
new Thread((ThreadStart)(() =>
{
Thread.Sleep(100);
HasValueChanged = true;
})).Start();
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。