GilShalit
GilShalit

Reputation: 6493

How can I set the background colour of part of a WPF DataGrid row, depending on column values?

Say I have a DataGrid with 5 columns, loaded (using AutoGenerateColumns=True) from a custome class collection. Based on the value in the first, third and fourth columns, I need to set the background of the row with one of the following options:

col num:    1    2    3    4    5
 Option1: gray gray gray gray gray
 Option2: gray red  red  gray gray
 Option3: gray gray gray red  red
 Option4: gray blue blue blue blue

This needs to be done for each row separately.

I've seen some examples of setting a converter for the row background, but how can I set individual cell backgrounds?

Upvotes: 1

Views: 898

Answers (2)

brunnerh
brunnerh

Reputation: 185589

You probably need to use custom columns, then you can pass the whole row into a converter while using the ConverterParameter to specify the current column, that way you can compare all the values:

<DataGridTextColumn Binding="{Binding Column1}">
    <DataGridTextColumn.ElementStyle>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Background"
                    Value="{Binding Converter={StaticResource ValueToBrushConverter},
                                    ConverterParameter=1}"/>
        </Style>
    </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Column2}">
    <DataGridTextColumn.ElementStyle>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Background"
                    Value="{Binding Converter={StaticResource ValueToBrushConverter},
                                    ConverterParameter=2}"/>
        </Style>
    </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<!-- ... -->

I do not quite that table of yours but you probably can figure out how to return the correct value in the converter on your own.


Converter skeleton could be something like this:

public class ValueToBrushConverter : IValueConverter
{
    /// <summary>
    /// 1st Indexer: Columns
    /// 2nd Indexer: Options
    /// </summary>
    Brush[,] _brushMatrix = new Brush[5,4]
    {
        { Brushes.Gray, Brushes.Gray, Brushes.Gray, Brushes.Gray },
        { Brushes.Gray, Brushes.Red, Brushes.Gray, Brushes.Blue },
        { Brushes.Gray, Brushes.Red, Brushes.Gray, Brushes.Blue },
        { Brushes.Gray, Brushes.Gray, Brushes.Red, Brushes.Blue },
        { Brushes.Gray, Brushes.Gray, Brushes.Red, Brushes.Blue }
    };

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        RowDataItem item = value as RowDataItem;
        int currentColumn = int.Parse(parameter as string);
        int currentRowOption;

        #region Internal logic here, e.g
        if (item.Col1 == "I" && item.Col3 == "Love" && item.Col2 == "Converters")
        {
            currentRowOption = 1;
        }
        //...
        #endregion

        return _brushMatrix[currentColumn, currentRowOption];
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

Upvotes: 2

Nathan Tregillus
Nathan Tregillus

Reputation: 6354

If you want a back end code solution, I'm sure you could get the LoadingRow event to check the individual row's datacontext, and find the generated cell that way as well. I haven't done that before though!

Upvotes: 0

Related Questions