I have a DataGrid with a DataTable with as ItemsSource. The number of columns differ from time to time. If the DataType of a column is of class A I want to use a DataTemplate to customize the appearance of the cell content.
I have set
AutoGenerateColumns="True"
on the DataGrid so that all columns in the DataTable will be generated.
I replace the DataGridColumn with a DataGridTemplateColumn if the DataType is of type A
private void DataGrid_AutoGeneratingColumn(object sender, system.Windows.Controls.DataGridAutoGeneratingColumnEventArgs e)
{
if (e.PropertyType == typeof(A))
{
e.Column = new DataGridTemplateColumn
{
CellTemplate = (DataTemplate)Resources["ATemplate"],
Header = e.Column.Header,
HeaderTemplate = e.Column.HeaderTemplate,
HeaderStringFormat = e.Column.HeaderStringFormat
};
}
}
The DataTemplate looks like this.
<DataTemplate x:Key="ATemplate">
<RadioButton Content="{Binding Name}" GroupName="{Binding GroupName}" IsChecked="{Binding IsSelected}" />
</DataTemplate>
The radiobutton is shown, but I get binding errors for all properties, like
BindingExpression path error: 'IsSelected' property not found on 'object' ''DataRowView'
Class A looks like this
public class A
{
public string Name { get; set; }
public string GroupName { get; set; }
public bool IsSelected { get; set; }
}
How can i databind the DataTemplate to the right cell and property?
(If you have a MVVM solution in which I don't have to use DataGrid_AutoGeneratingColumn it would be great)
EDIT
I have tried this solution too with no luck. Only the classname is shown in the cell as usual when it doesen't know how to render the class.
<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Items}">
<DataGrid.Resources>
<DataTemplate DataType="{x:Type viewModel:A}">
<RadioButton Content="{Binding Path=Name}" GroupName="{Binding Path=GroupName}" IsChecked="{Binding Path=IsSelected}" />
</DataTemplate>
</DataGrid.Resources>
</DataGrid>
Best Answer
The bindings in the template don't work because the DataContext is a DataRowView from the DataTable.
One solution is to change your template to set the DataContext to the object you want (of type A), then all your bindings would work (Name, GroupName, IsSelected). To do that, you will need to make a converter and have your template use it.
The DataContext in the template, is bound to it's DataGridCell ancestor which is passed into the converter. From the cell, we can get the DataContext (DataRowView) and we can get the cell's Column. When we make the column in DataGrid_AutoGeneratingColumn, we set the column's SortMemberPath to e.PropertyName (the column's name in the datatable). In the converter, we lookup the object in the DataRowView.Row using the SortMemberPath as the index. We return this as the DataContext for the template.
Here is the implementation with a class A and class B. I added two columns of each class to my data table to show that it works with multiple instances.
MainWindow.xaml:
MainWindow.xaml.cs: