14

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

4

3 回答 3

0

我对第 (1) 点的想法是在代码中处理这个问题。一种方法是处理 DataGridTextColumn 的 TargetUpdated 事件,并对旧值与新值进行额外检查,并仅在值不同时应用样式,也许另一种方法是创建和删除绑定以编程方式基于代码中的不同事件(如初始加载、刷新等)。

于 2012-06-01T19:50:49.030 回答
0

我建议对视图模型中的每个道具使用 OnPropertyChanged 并更新相关的 UIElement(启动动画或其他),这样您的问题将得到解决(加载、排序、过滤等),用户也可以看到哪个单元格发生了变化!

于 2015-05-07T14:34:20.847 回答
0

因为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>

后面的代码(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(将绑定设置为TargetUpdate通过 aDataTrigger)当任何通知正在进行时MyClassinupdateProperty()方法并且在更新被通知到之后UISourceUpdating设置为 false(然后将绑定重置为不TargetUpdate通过 aDataTrigger) .

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

}

输出:

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

更新1

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

更新2

所以更新后,当排序或过滤发生时,绑定知道它不必调用TargetUpdated 事件。仅当源集合的更新正在进行时,绑定才会重置以调用TargetUpdated事件。初始着色问题也由此得到处理。

然而,由于逻辑仍然存在某种形式,因为对于编辑器TextBox,逻辑基于更复杂的数据类型和 UI 逻辑,代码将变得更复杂,初始绑定重置整行动画,因为TargetUpdated为一行的所有单元格设置.

于 2016-06-02T09:59:57.463 回答