I have a DataGrid that has its data refreshed by a background process every 15 seconds. If any of the data changes, I want to run an animation that highlights the cell with the changed value in yellow and then fade back to white. I sort-of have it working by doing the following:
I created a style with event trigger on 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>
And then applied it to the columns I wanted to highlight if a value changes
<DataGridTextColumn Header="Status"
Binding="{Binding Path=Status, NotifyOnTargetUpdated=True}"
CellStyle="{StaticResource ChangedCellStyle}" />
If the value for the status field in the database changes, the cell highlights in yellow just like I want. But, there are a few problems.
First, when the data grid is initially loaded, the entire column is highlighted in yellow. This makes sense, because all of the values are being loaded for the first time so you would expect TargetUpdated to fire. I'm sure there is some way I can stop this, but it's a relatively minor point.
The real problem is the entire column is highlighted in yellow if the grid is sorted or filtered in any way. I guess I don't understand why a sort would cause TargetUpdated to fire since the data didn't change, just the way it is displayed.
So my question is (1) how can I stop this behavior on initial load and sort/filter, and (2) am I on the right track and is this even a good way to do this? I should mention this is MVVM.
Since
TargetUpdated
is truly only UI update based event. It doesn't matter how update in happening. While sorting all theDataGridCells
remain at their places only data is changed in them according to sorting result henceTargetUpdated
is raised. hence we have to be dependent on data layer of WPF app. To achieve this I've reset the Binding ofDataGridCell
based on a variable that kind of trace if update is happening at data layer.XAML:
Code Behind(DataContext object of Window):
Model Class:
SourceUpdating
property is set to true(which set the binding to notifyTargetUpdate
via aDataTrigger
) when any notification is in progress forMyClass
inupdateProperty()
method and after update is notified toUI
,SourceUpdating
is set to false(which then reset the binding to not notifyTargetUpdate
via aDataTrigger
).Outputs:
Two simultaneous Updates/ Button is clicked once :
Many simultaneous Updates/ Button is clicked many times :
However as the logic still has some sort comings as for editor
TextBox
the logic is based on with more complexity of data types and UI logic the code will become more complex also for initial binding reset whole row is animated asTargetUpdated
is raised for all cells of a row.I suggest to use OnPropertyChanged for every props in your viewmodel and update related UIElement (start animation or whatever), so your problem will solved (on load, sort, filter,...) and also users can saw which cell changed!
My ideas for point (1) would be to handle this in the code. One way would be to handle the TargetUpdated event for the DataGridTextColumn and do an extra check on the old value vs. the new value, and apply the style only if the values are different, and perhaps another way would be to create and remove the binding programmatically based on different events in your code (like initial load, refresh, etc).