polfosol polfosol - 3 months ago 33
C# Question

WPF- How to apply LayoutTransform to a specific DataGridColumnHeader

I have a

DataGrid
whose
ItemsSource
is bound to a
System.Data.DataTable
. This
DataTable
is filled at runtime with some text columns and some boolean columns. As expected, the text columns are displayed as
DataGridTextColumn
and the boolean ones are displayed as
DataGridCheckBoxColumn
. No problem so far. Now I want the column headers of the checkbox columns to be displayed as vertical. So I defined a style like this:

<Style x:Key="ColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
<Style.Triggers>
<!--<Trigger Property=??? Value=???>
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="270"/>
</Setter.Value>
</Setter>
</Trigger>-->
</Style.Triggers>
</Style>


The problem is -as commented in the code, I don't know what kind of trigger I should use for the style in order to be applied only to the
DataGridCheckBoxColumn
s and not other types of columns. Any ideas?

Answer

To fulfill both requisites:

  • Timing : Flip Headers after ItemSource is set
  • Filter : The Style should only be applied to CheckBoxColumns

You could resort to Attached Behaviour:

DataGridColumnsBehavior.cs

public static class DataGridColumnsBehavior
{
    public static readonly DependencyProperty
        FlipHeaderProperty =
            DependencyProperty.RegisterAttached("FlipHeader",
                typeof(bool), typeof(DataGridColumnsBehavior),
                    new PropertyMetadata(FlipHeaderChanged));

    public static bool GetFlipHeader(DependencyObject obj)
    {
        return (bool)obj.GetValue(FlipHeaderProperty);
    }
    public static void SetFlipHeader(DependencyObject obj, bool value)
    {
        obj.SetValue(FlipHeaderProperty, value);
    }

    private static void FlipHeaderChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs args)
    {
        var grid = d as DataGrid;
        var flip = (bool)grid.GetValue(FlipHeaderProperty);
        if (grid == null
         || grid.Columns.Count == 0
         || flip == false) return;

        foreach (var column in grid.Columns)
        {
            if (column.GetType() == typeof(DataGridCheckBoxColumn))
                column.HeaderStyle = 
                    (Style)grid.FindResource("CheckBoxColumnHeaderStyle");
        }
    }
}

XAML

<DataGrid ItemsSource="{Binding Collection}" 
          funk:DataGridColumnsBehavior.FlipHeader="{Binding Flip}">
    <DataGrid.Resources>
        <Style x:Key="CheckBoxColumnHeaderStyle" 
               TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="LayoutTransform">
                <Setter.Value>
                    <RotateTransform Angle="270"/>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.Resources>
</DataGrid>

The timing is controlled by a Flip property. Every time Collection is changed, set Flip to false and then to true again. The Columns are iterated and the Headers of the DataGridCheckBoxColumns are flipped. Note the way this is implemented setting Flip to false does nothing, so the Headers aren't flipped back.