Alignment of WPF DataGrid header


In the previous post I described how you can wrap the text in the column header of the WPF DataGrid. In this post we are going to extend the style so is also possible to align the header text. The default alignment of the header text is left.

First we create 3 styles, one for each alignment possibility (left, center and right alignment).

<Style x:Key="LeftAlignmentColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource WrappedColumnHeaderStyle}">
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
</Style>

<Style x:Key="CenterAlignmentColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource WrappedColumnHeaderStyle}">
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>

<Style x:Key="RightAlignmentColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource WrappedColumnHeaderStyle}">
    <Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style>

In the styles above we use the BasedOn property so the style is based on the WrappedColumnHeaderStyle we created in the previous post. The property HorizontalContentAligment is used for setting the alignment because in the default control template of the DataGridColumnHeader this property is used for aligning the content of the header.

In the column definitions we can set the HeaderStyle to a specific alignment style.

<DataGrid ItemsSource="{Binding }" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Long header text (alignment = left)" HeaderStyle="{StaticResource LeftAlignmentColumnHeaderStyle}" Width="50" Binding="{Binding Name}"/>
        <DataGridTextColumn Header="Long header text (alignment = center)" HeaderStyle="{StaticResource CenterAlignmentColumnHeaderStyle}" Width="50" Binding="{Binding Name}"/>
        <DataGridTextColumn Header="Long header text (alignment = right)" HeaderStyle="{StaticResource RightAlignmentColumnHeaderStyle}" Width="50" Binding="{Binding Name}"/>
     </DataGrid.Columns>
</DataGrid> 

As you can see in the picture below the header text is aligned.

There is one issue we have to fix. For wrapping the text we make use of a TextBlock. This TextBlock is correctly aligned but when the text is wrapped the text lines in the TextBlock are always aligned to the left within the TextBlock. To solve this we extend the WrappedColumnHeaderStyle with some data triggers which set the TextAlignment property of the TextBlock to the correct value.

<Style x:Key="WrappedColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <TextBlock x:Name="TextBlock" TextWrapping="Wrap" Text="{Binding}"></TextBlock>
                <DataTemplate.Triggers>
                     <DataTrigger Binding="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}}" Value="Center">
                        <Setter TargetName="TextBlock" Property="TextAlignment" Value="Center"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}}" Value="Left">
                        <Setter TargetName="TextBlock" Property="TextAlignment" Value="Left"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}}" Value="Right">
                        <Setter TargetName="TextBlock" Property="TextAlignment" Value="Right"/>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

As you can see in the picture below also in case the text is wrapped the alignment for all text lines is correct.

7 thoughts on “Alignment of WPF DataGrid header”

  1. After following this and the previous text wrapping article, I keep getting an unhandled XamlParseException with the text:
    “Provide value on ‘System.Windows.Markup.StaticresourceHolder’ threw an exception.

    The InnerException message is:
    “Cannot find resource named ‘WrappedColumnHeaderStyle’. Resource names are case sensitive.”

    but i’ve even copied and pasted the names and all looks ok.

    Have you come across this before when you were working on this solution?

    1. Hello Stephen,

      Have you defined the WrappedColumnHeaderStyle style before using it in another style? The order in the XAML file is important because it is a static resource.

      Example:

      <Style x:Key="WrappedColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}"/>
      
      <Style x:Key="LeftAlignmentColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource WrappedColumnHeaderStyle}">
      </Style>
      

      Regards,

      Marcel.

  2. Hi Marcel,

    Thanks for such a quick response, wasn’t expecting you to get back so quickly. Yes, thats the exact order I have it specified.

    then center and right

    With the WrappedColumnHeaderStyle using the version with the 3 DataTriggers. I have it at the end of my Application Styles Dictionary right before I call:

    and none of those contain anything similar so it’s not a case of being defined twice and not knowing which to go to.

  3. Thanks Marcel for your help. For anyone else who comes across the same issue:

    If you have dialogs / DataTemplate defined in a resource dictionary and the above code in another resource dictionary, the styles dictionary must be called from the DataTemplate dictionary. Calling the DataTemplate from the Styles resource dictionary will result in an error as I mentioned above

Leave a comment