Jatin
Jatin

Reputation: 4063

How to get name of DatagridTextColumn from DataGridColumnHeader using xaml

I have the following xaml code defined for DataGridTextColumn of a DataGrid.

<DataGridTextColumn x:Name="UserIdColumn" Binding="{Binding Path=UserId}" HeaderStyle="{StaticResource DataGridHeaderStyle}"/>

And Here is the HeaderStyle for the DataGridTextColumn

<Style x:Key="DataGridHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="DataGridColumnHeader">
                <StackPanel>
                    <TextBlock x:Name="ColumnName" Text="UserId" />
                    <TextBox x:Name="UserIdFilter" Width="100">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="TextChanged">
                                <cal:ActionMessage MethodName="UserIdFilterChanged">
                                    <cal:Parameter Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridTextColumn}}, Path=Name}"/>
                                    <cal:Parameter Value="{Binding ElementName=UserIdFilter, Path=Text}" />
                                </cal:ActionMessage>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </TextBox>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>    

As one can see I am trying to access the DataGridTextColumn's Name property inside the DataGridColumnHeader's ControlTemplate using this line of code

<cal:Parameter Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridTextColumn}}, Path=Name}"/>

The above line is returning null, why ?

Is there any other way to get hold of DataGridTextColumn's Name property from DataGridColumnHeader's control template ?

Upvotes: 0

Views: 3675

Answers (1)

Charles HETIER
Charles HETIER

Reputation: 2066

You are recovering a null value for 2 different reasons: The first one is that the DataGridTextColumn is not part of the visual tree and is not a visual instance of the datagrid. This is just an instance that descibes how a column of the datagrid should be displayed. Thus, DataGridTextColumn is not part of the ancestors of you cell. The only way I see to recover your DataGridTextColumn is to proceed somehow like that:

<TextBox x:Name="UserIdFilter" Width="100" Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}, Path=Columns[0]}">

This way, you should set the Tag property of the Textbox with the instance of the DataGridTextColumn (you can check with snoop that it works properly)

Then, the second reason explaining why you have a null value is that the DataGridTextColumn has no Name property. What you could do is simply create an attached property like this one:

public class XamlHelper
{
    public static readonly DependencyProperty NameProperty = DependencyProperty.RegisterAttached("Name", typeof(string), typeof(XamlHelper));

    public static string GetName(DependencyObject obj)
    {
        return (string)obj.GetValue(NameProperty);
    }

    public static void SetName(DependencyObject obj, string value)
    {
        obj.SetValue(NameProperty, value);
    }
}

... replace the name of the column definition by this one:

<DataGridTextColumn alias:XamlHelper.Name="UserIdColumn" Binding="{Binding Path=UserId}" HeaderStyle="{StaticResource DataGridHeaderStyle}"/>

and retrieve the property this way:

<Style x:Key="DataGridHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="DataGridColumnHeader">
                <StackPanel>
                    <TextBlock x:Name="ColumnName" Text="UserId" />
                    <TextBox x:Name="UserIdFilter" Width="100"  Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}, Path=Columns[0]}">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="TextChanged">
                                <cal:ActionMessage MethodName="UserIdFilterChanged">
                                    <cal:Parameter Value="{Binding ElementName=UserIdFilter, Path=Tag.(alias:XamlHelper.Name)}"/>
                                    <cal:Parameter Value="{Binding ElementName=UserIdFilter, Path=Text}" />
                                </cal:ActionMessage>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </TextBox>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>   

... hope I didn't made too much mistakes in this code but I think something like that should work

Notice that I used the tag property of the textbox has a buffer because I am note sure the findAncestor mode of the binding is able to recover the datagrid properly (I had some issues on elements that are not is the visual tree). Maybe having a unique binding in you parameter also work...

Tag is also great to make tests because it allows to see the value in snoop!

Do not hesitate if some points are not clear enougth

edit: I checked out the DataGridCOlumnHeaderClass and I discovered the property that seems to contain what you expected... Thus, it should be possible to do that:

<Style x:Key="DataGridHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="DataGridColumnHeader">
                <StackPanel>
                    <TextBlock x:Name="ColumnName" Text="UserId" />
                    <TextBox x:Name="UserIdFilter" Width="100"  Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridColumnHeader}}, Path=Column}">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="TextChanged">
                                <cal:ActionMessage MethodName="UserIdFilterChanged">
                                    <cal:Parameter Value="{Binding ElementName=UserIdFilter, Path=Tag.(alias:XamlHelper.Name)}"/>
                                    <cal:Parameter Value="{Binding ElementName=UserIdFilter, Path=Text}" />
                                </cal:ActionMessage>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </TextBox>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>   

Upvotes: 2

Related Questions