2
votes

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>
3

3 Answers

4
votes
<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.

2
votes

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.

  1. 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).
  2. Add a DataTrigger in XAML referencing the ModifiedDate column and the formatting you want.
  3. 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).
  4. Add a RowChanged Event to your ADO.Net Dataset that populates something in your ModifiedDate column (should correspond with your first DataTrigger).
  5. 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.

1
votes

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.