wpf - Set width through binding in HeaderTemplate of DataGridColumn

I want so set the width of a DockPanel I use in my HeaderTemplate to the actual width of the column and am struggling with the binding.

<DataTemplate x:Key="MyHeaderTemplate">
    <DockPanel HorizontalAlignment="Stretch" 
               LastChildFill="False"
               Width="{Binding Width, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}}">
        <!-- Several items here. Some docked to the left side, some to the right-->
    </DockPanel>
</DataTemplate>

This gives me a binding error and renders all items squeezed together on the left side of the header.


[Edit]

Binding to ActualWidth instead of Width gave me these two binding errors and increases the width of the column way too much , so that all columns to the right of it are seemingly "pushed out" of the visible area:

  • System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.DataGrid', AncestorLevel='1''. BindingExpression:Path=AreRowDetailsFrozen; DataItem=null; target element is 'DataGridDetailsPresenter' (Name=''); target property is 'SelectiveScrollingOrientation' (type 'SelectiveScrollingOrientation')
  • System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.DataGrid', AncestorLevel='1''. BindingExpression:Path=HeadersVisibility; DataItem=null; target element is 'DataGridRowHeader' (Name=''); target property is 'Visibility' (type 'Visibility')

[Edit]

I don't care, whether the Layout Control is a DockPanel or something else as long as it fills the header and I can arrange one TextBlock on the left and a few icons on the right...


[Edit]

What I want is for "Left" to be shown on the left, "Right" on the right. Now it's "LeftRight" on the left.

<UserControl x:Class="Lb.Abrechnung.Kunden.Fbs.Client.Rechnungslauf.Dialoge.RechnungslaufWizard.Rechnungsvorschlaege.RechnungsvorschlagListe.TestView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         HorizontalContentAlignment="Stretch">
<Grid>
    <DataGrid Background="Black">
        <DataGrid.ColumnHeaderStyle>
            <Style TargetType="DataGridColumnHeader">
                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                <Setter Property="Foreground" Value="White" />
            </Style>
        </DataGrid.ColumnHeaderStyle>
        <DataGrid.Columns>
            <DataGridTextColumn>
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <DockPanel Width="{Binding Width, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}}">
                            <TextBlock Text="Left" DockPanel.Dock="Left"/>
                            <TextBlock Text="Right" DockPanel.Dock="Right"/>
                        </DockPanel>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

1 Answer

  1. Lorin- Reply

    2019-11-16

    I suspect the reason that code isn't working is one of these:

    • The DataGridColumnHeader is using Auto width, which is stored in the Width property as Double.NaN. You need to use the ActualWidth property to get the computed value.

    • You might have set up a two-way binding, so that instead of the DockPanel inheriting the DataGridColumnHeader's width, it's working the other way around. Using ActualWidth should solve this as well since it's a read-only property.

    The binding should not be necessary, however. If you set HorizontalContentAlignment to Stretch on the DataGridColumnHeader, the header template should automatically fill the header:

    <DataGrid>
        <DataGrid.ColumnHeaderStyle>
            <Style TargetType="DataGridColumnHeader">
                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            </Style>
        </DataGrid.ColumnHeaderStyle>
    </DataGrid>
    

    EDIT: This does work, you can tell by giving the DockPanel a background color and see that it covers the whole area of the header. The reason the content still doesn't show on the right is because of the DockPanel's LastChildFill behavior. The last child, "Right", is filling the remaining space (and the text is left-aligned so it doesn't move). To make it respect the DockPanel.Dock="Right" setting, you need to either set LastChildFill to False, or add a third child for filling the space in the middle.

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>