WPF DataGrid CellStyle Binding Problem

Jun 5, 2009 at 3:30 PM

I have been experimenting with the WPF DataGrid from Microsoft.  What I am attempting to
do is to set the background color of the grid to red and the background color of the cells
in the grid to green.  I am using two Styles.  For the one I give the key GridStyle
and it has a Setter to set the Background property to red.  For the other I give the key
GridCellStyle and set the background color to green.  The XAML is given as follows and it works.
When a window is displayed containing the UserControl, the datagrid shows a red background and
the rows all have a green background.  However, different behavior occurs when I try to use a
binding as shown below.


<UserControl x:Class="Test.MyDataGrid"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:WpfToolkit="http://schemas.microsoft.com/wpf/2008/toolkit">
    <UserControl.Resources>
        <Style x:Key="GridStyle" TargetType="{x:Type WpfToolkit:DataGrid}">
            <Setter Property="Background" Value="Red" />
        </Style>
        <Style x:Key="GridCellStyle" TargetType="{x:Type WpfToolkit:DataGridCell}">
            <Setter Property="Background" Value="Green" />
        </Style>
    </UserControl.Resources>
    <WpfToolkit:DataGrid x:Name="outageGrid" ItemsSource="{Binding Path=Outages}"
                         Style="{StaticResource GridStyle}"
                         CellStyle="{StaticResource GridCellStyle}">
    </WpfToolkit:DataGrid>
</UserControl>


Here is the XAML where the Value attributes have been replaced by bindings.
The first binding uses a property in the code behind called RedBackground. 
The second binding uses a property called GreenBackground.  The properties
are very simple.  The first returns the red SolidColorBush with the statement:
return Brushes.Red;  The second returns the green SolidColorBush with the statement:
return Brushes.Green;

When the code is executed the background of the grid does, in fact, change to red.  However,
the background of the rows does not change.  It remains white.

I verified that the RedBackground property is being called with a breakpoint.  However,
the GreenBackground property is not being called because its breakpoint is never hit.

To summarize, if the Value in the GridCellStyle is hardcoded to "Green", then the cell
background is displayed as green as expected.  However, if the Value is written to use
a binding, then nothing happens.

<UserControl x:Class="Test.MyDataGrid"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:WpfToolkit="http://schemas.microsoft.com/wpf/2008/toolkit">
    <UserControl.Resources>
        <Style x:Key="GridStyle" TargetType="{x:Type WpfToolkit:DataGrid}">
            <Setter Property="Background" Value="{Binding Path=RedBackground}" />
        </Style>
        <Style x:Key="GridCellStyle" TargetType="{x:Type WpfToolkit:DataGridCell}">
            <Setter Property="Background" Value="{Binding Path=GreenBackground}" />
        </Style>
    </UserControl.Resources>
    <WpfToolkit:DataGrid x:Name="outageGrid" ItemsSource="{Binding Path=Outages}"
                         Style="{StaticResource GridStyle}"
                         CellStyle="{StaticResource GridCellStyle}">
    </WpfToolkit:DataGrid>
</UserControl>

 

Any thoughts about this behavior?

Thanks

David

Jun 6, 2009 at 3:34 AM

After some experimentation I managed to figure out what is happening with this code. The key to setting the cell's color is to use the following setter for the GridCellStyle:

<Setter Property="Background" Value="{Binding Path=GreenBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"/>

The TargetType of GridCellStyle is WpfToolkit:DataGridCell.  Although CellStyle is a property of DataGrid, the style itself is applied to each DataGridCell.  The binding path is to a property called GreenBackground.  GreenBackground is a property in the code behind for the UserControl.  The rendering engine, however, was looking for the property in the DataGridCell that is being rendered.  Because DataGridCell does not contain such a property, the background doesn't change.  There are no warnings or error messages.  The background simply doesn't change.

Because DataGridCell is contained in a DataGrid which, in turn, is contained in a UserControl, you can use RelativeSource to specify the path to find the GreenBackground property.  The trick is to look for the UserControl where the GreenBackground property is defined.  This is accomplished by using the FindAncestor mode of RelativeSource.

Jun 6, 2009 at 4:30 PM

After some additional research I came across some statements that child controls inherit their DataContext from their parent.  If the UserControl's DataContext is set, then would the DataGrid and DataGridCell also inherit the same DataContext?  Thus it shouldn't be necessary to use RelativeSource.  The Path should have been sufficient for the DataGridCell to find the bound property.

Is my understanding of this correct or is there a bug in the DataGrid?