1
votes

Trying to setup the background of a cell dependend on a cell-object property in a WPF DataGrid I get an error, that the property is not found (but on the row-object):

System.Windows.Data Error: 40 : BindingExpression path error: 'IsOn' property not found on 'object' ''MyRow' (HashCode=48826322)'. BindingExpression:Path=IsOn; DataItem='MyRow' (HashCode=48826322); target element is 'DataGridCell' (Name=''); target property is 'NoTarget' (type 'Object')

I wonder, why the DataTrigger Binding is addressing the row object "MyRow", since the DataTrigger is defined for/inside a CellStyle.

XAML:

<DataGrid Name="tblTest" Grid.Column="2" IsReadOnly="True" AutoGenerateColumns="True">
    <DataGrid.CellStyle>
        <Style TargetType="{x:Type DataGridCell}">
            <Setter Property="Background" Value="PaleGreen" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsOn}" Value="True">
                    <Setter Property="Background" Value="Red"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
</DataGrid>

C#

class MyCell
{
    public MyCell( string v)
    {
        Value = v;
    }
    public string Value { get; set; }
    public bool IsOn { get => Value == "one";  }
    public override string ToString()
    {
        return Value;
    }
}

class MyRow
{
    public MyCell One { get; set;  }
    public MyCell Two { get; set;  }
}

void SetupTestTable()
{
    List<MyRow> data = new();
    data.Add(new MyRow
    {
        One = new MyCell("one"),
        Two = new MyCell("two")
    });
    tblTest.ItemsSource = data;
}

enter image description here

So how to bind against the cell object "MyCell" correctly?

1
Your datarow datacontext is Myrow instance and cells are displayed based on the properties defined on myrow instance. since these properties are complex type use should nagivate into the mycell and then access the IsOn property. <DataTrigger Binding="{Binding One.IsOn}" Value="True"> - neelesh bodgal
Thanks Neelesh, I assume your approach could be used for tables with static layouts, but is not usable for DataGrids with enabled AutogenerateColumns. - plasmobit

1 Answers

2
votes

DataGridCells have the same DataContext as DataGridRow - there are many obstacles to do differently in general-purpose manner. So single DataGrid.CellStyle won't work

I will use AutoGeneratingColumn to create cell styles for each column. However they will be based on existing style which is stored in DataGrid.Resources.

<DataGrid Name="tblTest" Grid.Column="2" IsReadOnly="True" 
          AutoGenerateColumns="True"
          AutoGeneratingColumn="tblTest_AutoGeneratingColumn">
    <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridCell}" x:Key="ColoredCellStyle">
            <Setter Property="Background" Value="Cyan" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Tag.IsOn, RelativeSource={RelativeSource Self}}" Value="True">
                    <Setter Property="Background" Value="Red"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.Resources>
</DataGrid>

I'm using binding to Tag instead of DataContext, because DataContext is MyRow object. In Tag there will be MyCell objects. It is achieved in event handler:

private void tblTest_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.Column is DataGridTextColumn tc && tc.Binding is Binding binding)
    {
        // unique value for each column
        var property = binding.Path.Path;

        // DataGrid reference to get Resources
        var dg = (DataGrid)sender;

        // new cell style which inherits trigger from ColoredCellStyle and binds Tag to MyCell property
        var cellStyle = new Style
        {
            TargetType = typeof(DataGridCell),
            BasedOn = (Style)dg.Resources["ColoredCellStyle"],
            Setters =
            {
                new Setter
                { 
                    Property = DataGridCell.TagProperty, 
                    Value = new Binding(property)
                }
            }
        };

        tc.CellStyle = cellStyle;
    };
}

ColoredCells