gpt4 book ai didi

wpf - 当绑定(bind)值更改时突出显示 WPF DataGrid 中的单元格

转载 作者:行者123 更新时间:2023-12-02 01:12:10 27 4
gpt4 key购买 nike

我有一个 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>

然后将其应用到我想要在值发生变化时突出显示的列

<DataGridTextColumn Header="Status" 
Binding="{Binding Path=Status, NotifyOnTargetUpdated=True}"
CellStyle="{StaticResource ChangedCellStyle}" />

如果数据库中状态字段的值发生变化,单元格就会像我想要的那样以黄色突出显示。但是,存在一些问题。

首先,当数据网格最初加载时,整个列以黄色突出显示。这是有道理的,因为所有值都是第一次加载,因此您预计 TargetUpdated 会触发。我确信有某种方法可以阻止这种情况,但这是一个相对较小的问题。

真正的问题是,如果网格以任何方式排序或过滤,整个列都会以黄色突出显示。我想我不明白为什么排序会导致 TargetUpdated 触发,因为数据没有改变,只是显示的方式改变了。

所以我的问题是(1)如何在初始加载和排序/过滤时停止这种行为,以及(2)我是否走在正确的轨道上,这是否是一个好方法?我应该提到这是 MVVM。

最佳答案

因为 TargetUpdated 实际上只是基于 UI 更新的事件。更新如何发生并不重要。在对所有 DataGridCells 进行排序时,它们仍保留在其位置,仅根据排序结果更改其中的数据,因此会引发 TargetUpdated。因此我们必须依赖WPF应用程序的数据层。为了实现这一目标,我根据一个变量重置了 DataGridCell 的绑定(bind),该变量在数据层发生更新时进行跟踪。

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>

代码隐藏(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);
}

模型类: SourceUpdating 属性设置为 true(这将绑定(bind)设置为通过DataTrigger)当 updateProperty() 方法中的 MyClass 正在进行任何通知时,并且在更新后通知到 UISourceUpdating 设置为 false(然后重置绑定(bind)以不通过 DataTrigger 通知 TargetUpdate)。

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;
}
}

}

输出:

两个同时更新/按钮被单击一次:

update1

许多同时更新/按钮被点击多次:

update2

SO after update, when sorting or filtering is happening the bindings know that it doesn't have to invoke the TargetUpdatedevent. Only when the update of source collection is in progress thebinding is reset to invoke the TargetUpdated event. Also initial coloring problem is also get handled by this.

但是,由于编辑器 TextBox 的逻辑仍然存在一些问题,因此逻辑基于数据类型和 UI 逻辑更加复杂,对于初始绑定(bind)重置整行,代码也会变得更加复杂当针对一行的所有单元格引发 TargetUpdated 时,会进行动画处理。

关于wpf - 当绑定(bind)值更改时突出显示 WPF DataGrid 中的单元格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10853845/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com