突出细胞WPF数据网格当结合值的变化(Highlighting cells in WPF DataG

2019-06-25 02:37发布

我有一个具有由每15秒一个后台进程更新了它的数据一个DataGrid。 如果有任何的数据变化,我想运行一个动画,突出在黄色更改后的值单元格,然后淡出回白色。 我排序的有它通过执行以下工作:

我创建了一个风格与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。

Answer 1:

由于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>

代码(窗口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属性被设置为真(即设置结合以通知TargetUpdate经由DataTrigger )当任何通知有进步MyClassupdateProperty()方法和更新通知给后UISourceUpdating设置为false(其然后重置绑定到不通知TargetUpdate经由DataTrigger )。

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

}

输出:

两个同步更新/按钮被点击一次:

许多同时发生的更新/按钮被点击多少次:

SO更新后,排序或筛选正在发生的事情,当绑定知道它没有调用TargetUpdated事件。 只有当源集合的更新过程中,结合被重置调用TargetUpdated事件。 此外初期着色问题也得到由该处理。

然而,由于逻辑仍然具有某种缺憾为编辑TextBox的逻辑是基于更多的数据类型和UI逻辑的代码将变得更为复杂也为初始绑定复位整排的复杂动画作为TargetUpdated被上调的所有细胞一排。



Answer 2:

我对点(1)的想法会在代码中处理这个问题。 一种方法是处理为DataGridTextColumn的TargetUpdated事件和做旧值与新值额外的检查,并且只适用于如果值是不同的风格,也许另一种方式是创建和删除绑定编程根据您的代码不同的事件(如初始加载,刷新等)。



Answer 3:

我建议在你的视图模型和更新相关的UIElement使用OnPropertyChanged每一个道具(开始动画或其他),所以您的问题将得到解决(负载,排序,过滤,...),还用户可以看到哪些细胞变了!



文章来源: Highlighting cells in WPF DataGrid when the bound value changes