Home > Blockchain >  WPF - DataGrid - Set cell color based con cell content
WPF - DataGrid - Set cell color based con cell content

Time:01-14

I'm learning WPF. I'm trying to write an app that will display a table, built in code, based on data calculated by other methods. This seems to work ok. My xaml code is:

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                <DataGrid Height="308" Margin="12,21,0,0" Name="mydataGrid" Width="722"/>
</ScrollViewer>

The code behind created a DataTable and adds the columns I need:

dt = new DataTable("drx");
DataColumn sfn = new DataColumn("SFN", typeof(int));
DataColumn sbf0 = new DataColumn("subframe0", typeof(string));
DataColumn sbf1 = new DataColumn("subframe1", typeof(string));
DataColumn sbf2 = new DataColumn("subframe2", typeof(string));
DataColumn sbf3 = new DataColumn("subframe3", typeof(string));
DataColumn sbf4 = new DataColumn("subframe4", typeof(string));
DataColumn sbf5 = new DataColumn("subframe5", typeof(string));
DataColumn sbf6 = new DataColumn("subframe6", typeof(string));
DataColumn sbf7 = new DataColumn("subframe7", typeof(string));
DataColumn sbf8 = new DataColumn("subframe8", typeof(string));
DataColumn sbf9 = new DataColumn("subframe9", typeof(string));

dt.Columns.Add(sfn);
dt.Columns.Add(sbf0);
dt.Columns.Add(sbf1);
dt.Columns.Add(sbf2);
dt.Columns.Add(sbf3);
dt.Columns.Add(sbf4);
dt.Columns.Add(sbf5);
dt.Columns.Add(sbf6);
dt.Columns.Add(sbf7);
dt.Columns.Add(sbf8);
dt.Columns.Add(sbf9);

Later, when the data is calculated I display it:

foreach (var item in data.dataGrid)
{
    DataRow dr = dt.NewRow();
    dr[0] = item.sfn;
    dr[1] = item.subframes[0] ? "ON" : "";
    dr[2] = item.subframes[1] ? "ON" : "";
    dr[3] = item.subframes[2] ? "ON" : "";
    dr[4] = item.subframes[3] ? "ON" : "";
    dr[5] = item.subframes[4] ? "ON" : "";
    dr[6] = item.subframes[5] ? "ON" : "";
    dr[7] = item.subframes[6] ? "ON" : "";
    dr[8] = item.subframes[7] ? "ON" : "";
    dr[9] = item.subframes[8] ? "ON" : "";
    dr[10] = item.subframes[9] ? "ON" : "";

    dt.Rows.Add(dr);
}

mydataGrid.ItemsSource = dt.DefaultView;
mydataGrid.Items.Refresh();

This is producing the expected result:

enter image description here

I'd like now to change the cell color based on the cell content, basically to highlight those cells whose content is set to 'ON'

I've been doing some reading and looks like the best way is to use the binding. I tried different options I read online. The following looked ok to me, it does not crash or produce any exception, but it does not add any background color:

<DataGrid x:Name="mydataGrid">
    <DataGridTextColumn Binding="{Binding Name}">
        <DataGridTextColumn.ElementStyle>
            <Style TargetType="{x:Type TextBlock}">
                <Style.Triggers>
                    <Trigger Property="Text" Value="ON">
                        <Setter Property="Background" Value="LightGreen"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </DataGridTextColumn.ElementStyle>
    </DataGridTextColumn>
</DataGrid

Any tips?

Thanks a lot

[EDIT] the xaml has been updated to:

<DataGrid Name="mydataGrid" Height="239" Width="530">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding subframe0}">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="{x:Type TextBlock}">
                    <Style.Triggers>
                        <Trigger Property="Text" Value="ON">
                            <Setter Property="Background" Value="LightGreen"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

This produces an extra column, first on the left: enter image description here

CodePudding user response:

You have mistakes in your XAML.

  • Your binding is wrong: <DataGridTextColumn Binding="{Binding Name}"> Change it to the <DataGridTextColumn Binding="{Binding subframe0}">
  • Your trigger value is wrong: <Trigger Property="Text" Value="John"> Change it to the <Trigger Property="Text" Value="ON">

So it should work.

Addendum: Here is a general solution how to style the cells with variable number of columns:

<DataGrid x:Name="mydataGrid" CanUserAddRows="False" AutoGenerateColumns="True">
    <DataGrid.Resources>
        <local:ShouldHighlightConverter x:Key="shouldHighlightCnv"></local:ShouldHighlightConverter>
    </DataGrid.Resources>
    <DataGrid.CellStyle>
        <Style TargetType="DataGridCell">
            <Style.Triggers>
                <DataTrigger Value="True">
                    <DataTrigger.Binding>
                        <MultiBinding Converter="{StaticResource shouldHighlightCnv}" ConverterParameter="ON">
                            <MultiBinding.Bindings>
                                <Binding/>
                                <Binding Path="Column.DisplayIndex" RelativeSource="{RelativeSource Mode=Self}"/>
                            </MultiBinding.Bindings>
                        </MultiBinding>
                    </DataTrigger.Binding>
                    <Setter Property="Background" Value="LightGreen"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
</DataGrid>


using System;
using System.Data;
using System.Globalization;
using System.Windows.Data;
public class ShouldHighlightConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values[0] is DataRowView dr && parameter is string textToCompare)
        {
            try
            {
                return dr[(int)values[1]].Equals(textToCompare);
            }
            catch{}
        }

        return false;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException("It's a one way converter.");
    }
}
  • Related