【发布时间】:2011-09-15 02:17:39
【问题描述】:
我在我的 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 不触发的问题,但会产生不希望的副作用。
问题视频
点击here查看破解版视频。
点击here查看修复版视频。
“固定”版本并不理想,因为 Thread.Sleep 导致单元格以明显顺序的方式更新,而不是像损坏的版本那样同时更新。此外,里面有一个 Thread.Sleep 让我感觉糟糕 :)
首先;我做错了吗?有没有更简单/更好的方法来实现我想要的?如果没有,有什么方法可以解决这个问题而无需添加 Thread.Sleep(代码异味!)?
当值快速更改时,为什么 WPF 不会触发 DataTrigger?是否存在导致 WPF“错过”属性更改的原因?还是 WPF 只是忽略从一个值到另一个值然后在特定时间范围内返回到原始值的更改?
感谢您的帮助!
【问题讨论】:
-
如果值在同一个调度程序操作中再次变回,WPF 可能会忽略该更改。尝试调度
HasValueChanged=truepart,而不是睡觉。
标签: c# wpf xaml animation datatrigger