Wednesday, October 21, 2015

Getting field names from anonymous types using WPF DataGrid

Often it is useful to use a bit of LINQ to prepare data for display in a WPF control. Here is a very simple example. The WPF window contains a DataGrid used to display the data.

<Window x:Class="DCView.Window15"
        Title="Window15" Height="300" Width="300" Loaded="Window_Loaded">
        <DataGrid x:Name="DataGrid1" AutoGenerateColumns="False" SelectionChanged="DataGrid1_SelectionChanged">
                <DataGridTextColumn Header="Number" Binding="{Binding NumberX1}" />
                <DataGridTextColumn Header="Number x 10" Binding="{Binding NumberX10}" />

The data might be prepared for display with a bit of LINQ. A new anonymous type is created using field names that are then used in the WPF control bindings.

private void Window_Loaded(object sender, RoutedEventArgs e)
 List<int> data = Enumerable.Range(1, 10).ToList();
 var query = from d in data
      select new { NumberX1 = d, NumberX10 = d * 10 };
 DataGrid1.ItemsSource = query;

The problem comes when you respond to selection changed events. How do you get to the fields in the anonymous type. You could create a new class instead of using the anonymous type but the advantage of LINQ is it is quick and easy.

private void DataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
 dynamic dynamictype1 = DataGrid1.SelectedItem;
 int number = dynamictype1.NumberX10;
 Title = number.ToString();

The problem is DataGrid1.SelectedItem returns an object and you can't cast it to an anonymous type. To solve the problem you can use a bit of dynamic black magic to get to the fields in the anonymous type. The example above shows how to use dynamic to get to the anonymous fields. There is no Visual Studio Smart Completion to help but as long as the field names match it will work.