DXGrid change color of grid row DevExpress WPF

9.5k views Asked by At

I have entity with property IsRemoved. When it is become true grid row should be Gray.

To do this I am using this code:

    <dxg:TableView.RowStyle>
        <Style TargetType="{x:Type dxg:GridRowContent}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding DataContext.IsRemoved, Mode=OneWay}" Value="True">
                    <Setter Property="Background" Value="Gray" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </dxg:TableView.RowStyle>
</dxg:TableView>

But It will run only when grid shows first time. I want to change color when value is changing. Property implement INotifyPropertyChange Event.

3

There are 3 answers

0
fahrettin sevinç On

you should write just "Row" instead of "DataContext"

1
Adam On

Note: this answer is legacy (see my other answer).

This answer is for DevExpress versions prior to v14.1, or DevExpress versions v14.1 and after with UseLightweightTemplates="None".

You need to have an initial setter for the property you want to change. This is due to the order in which WPF uses styles.

Include this line after your style tag:

<Setter Property="Background" Value="Black" />

Full Example:

<dxg:TableView.RowStyle>
    <Style TargetType="{x:Type dxg:GridRowContent}">
        <Setter Property="Background" Value="Black" />
        <Style.Triggers>
            <DataTrigger Binding="{Binding DataContext.IsRemoved, Mode=OneWay}" Value="True">
                <Setter Property="Background" Value="Gray" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</dxg:TableView.RowStyle>   
1
Contango On

Starting with v14.1 of DevExpress, they introduced Optimized Mode which uses Lightweight Templates. This makes everything faster, but requires a change to how the styles and DataTriggers are specified.

Lightweight Templates are controlled by a the attached property UseLightweightTemplates="Row", which is on by default. It can be switched to None for backwards compatibility.

Here is a working MVVM example of how to color a row if the IsDirty property is set for any grid row.

<dxg:GridControl x:Name="MyGridControl"
        ItemsSource ="{Binding MyViewModelList}" 
        SelectionMode="None"
        VerticalAlignment="Stretch">
    <dxg:GridControl.Resources>
        <SolidColorBrush x:Key="GridRowIsDirty" Color="#FF602D2D" />
    </dxg:GridControl.Resources>
    <dxg:GridControl.View>
        <dxg:TableView UseLightweightTemplates="Row" >
            <dxg:TableView.RowStyle>
                <Style TargetType="dxg:RowControl">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Row.IsDirty}" Value="True">
                            <Setter Property="Background" Value="{StaticResource GridRowIsDirty}" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </dxg:TableView.RowStyle>
        </dxg:TableView>
    </dxg:GridControl.View>
    <dxg:GridControl.Columns>
        <dxg:GridColumn x:Name="Included" FieldName="Included"/>
        <dxg:GridColumn x:Name="ColumnB" Header="Column B" FieldName="ColumnB" ReadOnly="True"/>
        <dxg:GridColumn x:Name="ColumnC" Header="Column C" FieldName="ColumnC" ReadOnly="True"/>ReadOnly="True"/>
    </dxg:GridControl.Columns>
</dxg:GridControl>

In the ViewModel behind this grid:

public ObservableCollection<MyViewModel> MyViewModelList { get; set; }

Every row in the grid points to a class of type MyViewModel, which contains a custom IsDirty flag which we can set on demand:

public bool IsDirty
{
    get { return _isDirty; }
    set
    {
        _isDirty = value;
        OnPropertyChanged();
    }
}

Appendix A: Additional Links

Appendix B: Other solutions

This also works most of the time, but it will not work if the source of the event is via a context menu, so it is not recommended:

 <DataTrigger Binding="{Binding DataContext.IsDirty}" Value="True">
    <Setter Property="Background" Value="{StaticResource GridRowIsDirty}" />
 </DataTrigger>

Appendix C: AllowLiveDataShaping

If the trigger is not firing, try switching on AllowLiveDataShaping="True" in <GridControl>. However, try to avoid this as it (theoretically) has an impact on the speed of large, complex grids (it has no discernable impact on most grids of a reasonable size).

Appendix D: If all else fails, use a custom ControlTemplate

With the introduction of "UseLightweightTemplates", DevExpress has been focusing on speed. However, the techniques used for speed involve switching off bindings that might slow things down.

This means that if we change something in a DxGrid cell, the value in the ViewModel does not change until the user shifts to the next cell or row. This means that the ViewModel lags behind what is actually in the grid.

To fix this, the only solution that I could find was to bypass DevExpress's templates entirely, and use my own. This means that the DxGrid has no choice but to display a custom template which updates the ViewModel instantaneously as soon as the user edits it, which means that the row color changes immediately:

 <dxg:GridControl Grid.Row="3" x:Name="TrsGridControl"
        ItemsSource ="{Binding MyObservableCollection}"                             
        VerticalAlignment="Stretch"
        AllowLiveDataShaping ="True">
    <dxg:GridControl.Resources>
        <converter:TestConverter x:Key="TestConverter" />
        <ControlTemplate x:Key="DisplayedOnTicketTrs">
                <dxe:CheckEdit x:Name="DisplayedOnTicketCheckEdit" HorizontalAlignment="Center" IsChecked="{Binding RowData.Row.DisplayedOnTicket, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
         </ControlTemplate>
    </dxg:GridControl.Resources>
    <dxg:GridControl.View>
        <dxg:TableView UseLightweightTemplates="All"/>
    </dxg:GridControl.View>
    <dxg:GridControl.Columns>            
        <dxg:GridColumn x:Name="DisplayedOnTicketTrs" DisplayTemplate="{StaticResource DisplayedOnTicketTrs}" Header="Displayed On Ticket?" HeaderToolTip="Displayed On Ticket?" AllowEditing="False"/>
                        Header ="Displayed On Ticket?"/>
        <dxg:GridColumn x:Name="ColumnA" Header="ColumnA" FieldName="ColumnA" ReadOnly="True"/>
        <dxg:GridColumn x:Name="ColumnB" Header="ColumnB" FieldName="ColumnB" ReadOnly="True"/>            
    </dxg:GridControl.Columns>
 </dxg:GridControl>

After I made this change, everything started to work:

  • When the checkbox is clicked, the background color changes instantly (if we add the trigger to change the background color, above).
  • Editing the DxGrid changes the ViewModel instantaneously.
  • Changing the ViewModel updates the DxGrid instantaneously.
  • If a ContextMenu updates the ViewModel, then everything just works.