Pau*_*ott 13 wpf datagrid mvvm storyboard
我有一个DataGrid,它的数据每15秒由后台进程刷新一次.如果任何数据发生变化,我想运行一个动画,突出显示黄色更改值的单元格,然后淡出为白色.我通过以下方式让它工作:
我在Binding.TargetUpdated上创建了一个带有事件触发器的样式
<Style x:Key="ChangedCellStyle" TargetType="DataGridCell">
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="00:00:15"
Storyboard.TargetProperty=
"(DataGridCell.Background).(SolidColorBrush.Color)"
From="Yellow" To="Transparent" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
Run Code Online (Sandbox Code Playgroud)
然后将其应用于我想要突出显示值的列
<DataGridTextColumn Header="Status"
Binding="{Binding Path=Status, NotifyOnTargetUpdated=True}"
CellStyle="{StaticResource ChangedCellStyle}" />
Run Code Online (Sandbox Code Playgroud)
如果数据库中状态字段的值发生更改,则单元格将以黄色突出显示,就像我想要的那样.但是,有一些问题.
首先,当最初加载数据网格时,整个列以黄色突出显示.这是有道理的,因为所有的值都是第一次加载,因此您可能希望触发TargetUpdated.我确信有一些方法可以阻止这一点,但这是一个相对较小的一点.
真正的问题是如果以任何方式对网格进行排序或过滤,整个列将以黄色突出显示.我想我不明白为什么排序会导致TargetUpdated触发,因为数据没有改变,只是它的显示方式.
所以我的问题是(1)如何在初始加载和排序/过滤时停止这种行为,以及(2)我是否在正确的轨道上,这是一个很好的方法吗?我应该提到这是MVVM.
因为TargetUpdated这确实是唯一基于 UI 更新的事件。更新如何发生并不重要。在对所有DataGridCells剩余的位置进行排序时,仅根据排序结果更改其中的数据,从而TargetUpdated引发。因此我们必须依赖WPF应用程序的数据层。为了实现这一点,我DataGridCell根据变量重置了绑定,如果更新发生在数据层,则进行跟踪。
XAML:
<Window.Resources>
<Style x:Key="ChangedCellStyle" TargetType="DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="00:00:04" Storyboard.TargetName="myTxt"
Storyboard.TargetProperty="(DataGridCell.Background).(SolidColorBrush.Color)"
From="Red" To="Transparent" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
<TextBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Transparent"
Name="myTxt" >
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=DataContext.SourceUpdating}" Value="True">
<Setter Property="Text" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=Content.Text,NotifyOnSourceUpdated=True,NotifyOnTargetUpdated=True}" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=DataContext.SourceUpdating}" Value="False">
<Setter Property="Text" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=Content.Text}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel Orientation="Vertical">
<DataGrid ItemsSource="{Binding list}" CellStyle="{StaticResource ChangedCellStyle}" AutoGenerateColumns="False"
Name="myGrid" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="ID" Binding="{Binding Id}" />
</DataGrid.Columns>
</DataGrid>
<Button Content="Change Values" Click="Button_Click" />
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
隐藏代码(Window的DataContext对象):
public MainWindow()
{
list = new ObservableCollection<MyClass>();
list.Add(new MyClass() { Id = 1, Name = "aa" });
list.Add(new MyClass() { Id = 2, Name = "bb" });
list.Add(new MyClass() { Id = 3, Name = "cc" });
list.Add(new MyClass() { Id = 4, Name = "dd" });
list.Add(new MyClass() { Id = 5, Name = "ee" });
list.Add(new MyClass() { Id = 6, Name = "ff" });
InitializeComponent();
}
private ObservableCollection<MyClass> _list;
public ObservableCollection<MyClass> list
{
get{ return _list; }
set{
_list = value;
updateProperty("list");
}
}
Random r = new Random(0);
private void Button_Click(object sender, RoutedEventArgs e)
{
int id = (int)r.Next(6);
list[id].Id += 1;
int name = (int)r.Next(6);
list[name].Name = "update " + r.Next(20000);
}
Run Code Online (Sandbox Code Playgroud)
模型类: SourceUpdating属性设置为 true(将绑定设置为TargetUpdate通过 ainDataTrigger正在进行任何通知并且更新通知到 后,设置为 false(然后将绑定重置为不通过 a) 。MyClassupdateProperty()UISourceUpdatingTargetUpdateDataTrigger
public class MyClass : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set {
name = value;updateProperty("Name");
}
}
private int id;
public int Id
{
get { return id; }
set
{
id = value;updateProperty("Id");
}
}
//the vaiable must set to ture when update in this calss is ion progress
private bool sourceUpdating;
public bool SourceUpdating
{
get { return sourceUpdating; }
set
{
sourceUpdating = value;updateProperty("SourceUpdating");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void updateProperty(string name)
{
if (name == "SourceUpdating")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
else
{
SourceUpdating = true;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
SourceUpdating = false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
两个同时更新/按钮被单击一次:
许多同时更新/按钮被点击多次:
因此,更新后,当发生排序或过滤时,绑定知道它不必调用该
TargetUpdated事件。仅当源集合更新正在进行时,绑定才会重置以调用事件TargetUpdated。最初的着色问题也可以通过此方法得到解决。
然而,由于编辑器的逻辑仍然存在一些问题,因此TextBox逻辑基于更复杂的数据类型和 UI 逻辑,对于初始绑定重置,代码也将变得更加复杂,整行将被动画化,就像TargetUpdated为一行的所有单元格引发的一样。
| 归档时间: |
|
| 查看次数: |
3704 次 |
| 最近记录: |