Is there a way to highlight all the modified rows on a DataGrid? Since the grid is bound to a System.Data.DataTable
I figured I might be able to bind the colour of each row to it's RowState (example below), but that doesn't seem to work.
Any ideas?
xmlns:data="clr-namespace:System.Data;assembly=System.Data"
<Style x:Key="DataGridRowStyle" TargetType="{x:Type toolkit:DataGridRow}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="Blue" />
</Trigger>
<DataTrigger Binding="{Binding RowState}" Value="{x:Static data:DataRowState.Modified}">
<Setter Property="Background" Value="LightYellow" />
</DataTrigger>
</Style.Triggers>
</Style>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding RowState}" Value="{x:Static data:DataRowState.Modified}">
<Setter Property="Background" Value="LightYellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
Update
After you have posted also your xaml, it's obvious that the problem is not to be found in the xaml. I have shortly looked at msdn for the DataTable-class and I can not see a mechanism that let WPF detect changes of the RowState
-property. Therefore, direct binding to this property will not give you reliable results.
It seems that you have to wrap your data items. I recommend to make a ViewModel for the items and add a property that says if the row has changed with change notification (INotifyPropertyChanged
or DP) and bind to this property. Surely there will be also other alternatives, but IMO creating a VM per item is in most cases the best solution.
I know this thread is old, but since this issue wasn't fixed in .Net 4, I figured I'd post my workaround. It's a bit clunky (not elegant), but at least it uses data triggers and works.
- Add a dummy ModifiedDate column to your DataTable (or if you don't care about the date, just add a dummy column to indicate rowstate).
- Add a DataTrigger in XAML referencing the ModifiedDate column and the formatting you want.
- Add a DataTrigger in XAML referencing the RowState (this will only take care of Adds and unchanged, so it's one less event to worry about).
- Add a RowChanged Event to your ADO.Net Dataset that populates something in your ModifiedDate column (should correspond with your first DataTrigger).
- In your saved event that pushes data to your database, blank out your dummy ModifiedDate column at the end (where RowState=unchanged (IMPORTANT: Be sure to check rowstate to verify that no error occured during save.
This works and, best of all, you don't need to do an Items.Refresh every time you modify a row. With that said, if anyone has a better (more elegant) way to accomplish this, then please post.
INotifyPropertyChanged
is not the only interface that WPF binding can use for change notification, it's just the one we're most used to. As Bea Stollnitz writes, the ADO DataView
implements IBindingList
, which implements change notification by raising ListChanged
when the list or an item in it changes.
This suggests a way to get what you want, though I haven't tried it to see how it works. You can derive a class from DataView
that listens to the DataTable.RowChanged
event and raises ListChanged
if the row is in the view and its RowState
changed.
You won't be able to instantiate this new DataView
in XAML without using any code-behind or implementing a view model, since if you just bind to the DataTable
it will create a normal DataView
. But you can fix that, too: subclass DataTable
and override GetDefaultView
to make it return an instance of your new DataView
, and then subclass DataSet
and override Tables
to make it return an instance of your new DataTable
. (None of these classes appear to be sealed, thank goodness.)
Edit
Of course it's not as simple as that. The list that DataView
exposes is a collection of DataRowView
objects. DataRowView
implements INotifyPropertyChanged
. I think that WPF uses the IBindingList
interface on DataView
for collection-changed notification and listens to PropertyChanged
on DataRowView
, though honestly I'd need to dig quite a bit more to be sure.
DataRowView
only raises PropertyChanged
when the value of a column in its row changes. I can't see any way to inject change-notification for other properties into that without subclassing DataRowView
, and while that's possible in principle, I can't see a straightforward way of subclassing DataView
to create these new DataRowView
objects.