6

I found the Columns collection in my datagrid, and was hoping to iterate through it to find a certain column Name. However, I can't figure out how to address the x:Name attribute of the column. This xaml illustrates my problem with a DataGridTextColumn and a DataGridTemplateColumn:

<t:DataGrid x:Name="dgEmployees" ItemsSource="{Binding Employees}" 
    AutoGenerateColumns="false" Height="300" >
    <t:DataGrid.Columns>
        <t:DataGridTextColumn x:Name="FirstName" Header="FirstName"
Binding="{Binding FirstName}" />
        <t:DataGridTemplateColumn x:Name="LastName" Header="LastName" >
            <t:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding LastName}" />
                </DataTemplate>
            </t:DataGridTemplateColumn.CellTemplate>
        </t:DataGridTemplateColumn>
    </t:DataGrid.Columns>
</t:DataGrid>

And here is my code:

    DataGrid dg = this.dgEmployees;
    foreach (var column in dg.Columns) 
    {
        System.Console.WriteLine("name: " + (string)column.GetValue(NameProperty));
    }

At runtime, no value is present; column.GetValue doesn't return anything. Using Snoop, I confirmed that there is no Name property on either DataGridTextColumn or DataGridTemplateColumn.

What am I missing?

Binil
  • 6,445
  • 3
  • 30
  • 40
Daniel R
  • 87
  • 1
  • 1
  • 8

2 Answers2

14

WPF has two different, yet similar concepts, x:Name, which is used to create a field which references an element defined in XAML, i.e. connecting your code-behind to your XAML, and FrameworkElement.Name, which uniquely names an element within a namescope.

If an element has a FrameworkElement.Name property, x:Name will set this property to the value given in XAML. However, there are instances where it is useful to link non FrameworkElement elements to fields in code-behind, such as in your example.

See this related question:

In WPF, what are the differences between the x:Name and Name attributes?

As an alternative, you could define your own attached property which can be used to name the columns. The attached property is defined as follows:

public class DataGridUtil
{

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

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

    public static readonly DependencyProperty NameProperty =
        DependencyProperty.RegisterAttached("Name", typeof(string), typeof(DataGridUtil), new UIPropertyMetadata(""));

}

You can then assign a name to each column ...

xmlns:util="clr-namespace:WPFDataGridExamples"

<t:DataGrid x:Name="dgEmployees" ItemsSource="{Binding Employees}" 
    AutoGenerateColumns="false" Height="300" >
    <t:DataGrid.Columns>
        <t:DataGridTextColumn util:DataGridUtil.Name="FirstName" Header="FirstName"
Binding="{Binding FirstName}" />
        <t:DataGridTemplateColumn util:DataGridUtil.Name="LastName" Header="LastName" >
            <t:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding LastName}" />
                </DataTemplate>
            </t:DataGridTemplateColumn.CellTemplate>
        </t:DataGridTemplateColumn>
    </t:DataGrid.Columns>
</t:DataGrid>

Then access this name in code as follows:

DataGrid dg = this.dgEmployees;
foreach (var column in dg.Columns) 
{
    System.Console.WriteLine("name: " + DataGridUtil.GetName(column));
}

Hope that helps

Community
  • 1
  • 1
ColinE
  • 68,894
  • 15
  • 164
  • 232
  • Your message and link are informative. But I'm not sure how they answer my question. Are you saying that this code will not work since DataGridColumn is not a FrameworkElement? Can you suggest an alternate approach? – Daniel R Jan 04 '11 at 16:56
  • Daniel, how about an attached property? See my edited answer above. – ColinE Jan 05 '11 at 08:41
  • Colin, that worked for me. Thank you. I wonder why they didn't make a 'Name' DP for DataGridColumns. – Daniel R Jan 05 '11 at 16:54
  • thnaks for your great answer,how can i use this property in codebehind?for example i want to set name property for this columns: `columnCollection = new ObservableCollection(); columnCollection.Add(new DataGridTextColumn { Header = "ColumnHeader", Binding = new Binding("ColumnName)" , ??Name=????}); ` – mahboub_mo Apr 18 '12 at 10:23
  • Sigh. -(Infinity) to Tinyflacid, I mean Microsoft, for not including a "Name" `DependencyProperty` in the `DataGridColumn` Class. I know much of the complexity (vs. WinForms) is (supposedly) needed for more flexibility, but I doubt they can claim that *excuse* in this case. And even *with* a "Name" DP, the Code Behind still needs to dupe the Magic String from XAML (ala when MS thought Magic Strings were ok in RaisePropertyChanged Call. SMH). WinForms created separate `DataGridViewTextBoxColumn` Objects in the *.Designer.cs with Names that could be Intellisensed / compile-time checked. – Tom May 22 '19 at 18:21
1

You can use linq query to find name of the datagrid column Headers

dgvReports.Columns.Select(a=>a.Header.ToString()).ToList()

where dgvReports is name of the datagrid.

Joee
  • 1,834
  • 18
  • 19