Friday, December 13, 2013

Finding a column in a DataGrid by Name

WPF Version 4.0

The various types of datagrid columns do not expose a Name attribute, probably because they do not derive from FrameworkElement, unlike the parent DataGrid class. Pretty much every class in WPF does expose an x:Name attribute so the markup...

<DataGridTextColumn x:Name="Description" Binding="{Binding Path=Description}"/>

will assign the name "Description" to the column. But how do we find it in code? Easy...

MyDataGrid.FindName("Description")

which is much nicer than...

MyDataGrid.Columns(8)

But, there's a gotcha. Consider the markup below...

<DataGrid Name="DataGrid1" ItemsSource="{Binding Path=Path1}" AutoGenerateColumns="false">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="Description" Binding="{Binding Path=Description}"/>
    </DataGrid.Columns>
</DataGrid>
<DataGrid Name="DataGrid2" ItemsSource="{Binding Path=Path2}" AutoGenerateColumns="false">
    <DataGrid.Columns>
        <DataGridComboBoxColumn x:Name="Description" Binding="{Binding Path=Description}"/>
    </DataGrid.Columns>
</DataGrid>

Now watch this carefully. What do you think this line of code will do?

Debug.Print(DirectCast(DataGrid2.FindName("Description"),DataGridComboBoxColumn).ToString())

It will actually throw an invalid cast exception. Even though you executed the FindName method on DataGrid2 it will return the Description column from DataGrid1 which is a DataGridTextColumn and cannot be cast to DataGridComboBoxColumn.

Columns must be uniquely named in the Window or User Control.

Even though you cannot retrieve the name of a column in a grid's column collection i.e. there is no way to code If Grid1.columns(0).Name = "Col1" Then, you can test for equality like this...

If Grid1.Columns(0) is Col1 Then...

Note: In WPF 4.5 under VS2012 you get a design time error if you give the same name to two columns in different grids.

No comments:

Post a Comment