What does a WPF DataGrid bind to the headers DataTemplate?

55 views Asked by At

When creating a WPF DataGrid, I have the option to set a DataTemplate to each column's HeaderTemplate, like this:

<DataGridTextColumn Binding="{Binding Name}">
    <DataGridTextColumn.HeaderTemplate>
        <DataTemplate>

            <!-- just some random content, not important, but notice the bindings use RelativeSource-->
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Name" VerticalAlignment="Center"/>
                <Button Command="{Binding Path=DataContext.SortFoldersByNameCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}" Content="▲" 
                    Foreground="{Binding Path=DataContext.IsFoldersSortByName, Converter={StaticResource EnabledToBrushConverter}, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
            </StackPanel>


        </DataTemplate>
    </DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>

Now, notice that for my bindings to work inside that template, I need to set a RelativeSource, because this template is not bound to the grid's DataContext anymore.

The question is: what is bound to the header's DataTemplate?

If I simply try to put a <TextBlock Text="{Binding}"/>, for instance, the text is empty. I don't know what other kinds of tests I could do to find out.

2

There are 2 answers

0
Andy On BEST ANSWER

The short answer is that the datacontext is nothing.

I threw a quick template into some datagrid I have on disk.

I used this thing to answer a few questions years back.

The header isn't in the visual tree and does not inherit datacontext.

My quick and dirty header template:

            <DataGridTextColumn Binding="{Binding LastName}">
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="XXXX"/>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>

Examine that textblock using Snoop...

Datacontext is empty:

enter image description here

This is why you do all that relativesource stuff to get to your property in the datacontext.

As an aside.

If you're doing much wpf development I recommend you give Snoop a go.

It's still way better than the in built thing.

3
Daniel Möller On

Besides using Snoop (great tool!), you can also check that by adding a converter to the binding and inspecting it with a breakpoint. (The inspection is necessary if the binding is null, which is the case)

The Path=. indicates the current DataContext.

<DataGridTextColumn.HeaderTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding Path=., Converter={local:TestConverter}}"/>
    </DataTemplate>
</DataGridTextColumn.HeaderTemplate>

Where the converter is defined as:

class TestConverter : MarkupExtension, IValueConverter
{
    //source to target
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value.GetType().FullName;
    }

    //target to source
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}