in my WPF there is a DataGrid which columns are auto-generated. The data is loaded from extern, so the column names are known at runtime. For certain columns, i display a button inside the column. Only when clicked onto the button, i load other data and display it inside the RowDetails of the outer DataGrid. Then, the inner DataGrid is loaded again – maybe with other buttons. This is repeated for ever.
I want to do this with a DataTemplateSelector
. This is my current .xaml code:
<Window.Resources>
<local:DynamicDataTemplateSelector x:Key="dynamicTemplateSelector" />
</Window.Resources>
<DataGrid ItemsSource="{Binding DataTable1.DefaultView}" AutoGenerateColumns="True"
AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" CanUserAddRows="False>
<DataGrid.RowDetailsVisibilityMode>Collapsed</DataGrid.RowDetailsVisibilityMode>
<DataGrid.RowDetailsTemplateSelector>
<StaticResource ResourceKey="dynamicTemplateSelector"/>
</DataGrid.RowDetailsTemplateSelector>
</DataGrid>
DataGrid_AutoGeneratingColumn(sender, e)
calls HandlerDgAutoGeneratingColumn(sender, e)
In this method i declare an event when the button inside the cell is clicked. DataTable1
is a DataTable
with geter/seter, i added the RaisePropertyChanged
Event for MVVM.
In my DataTemplateSelector
i build a new DataGrid if there is one column that contains a button. The inner DataGrid is fully loaded and correctly bound. I build the DataGrid visually in the correct style. But: The AutoGeneratedEvent
is never fired. The breakpoints in DataGrid_AutoGeneratingColumnTempl
are never reached. I cannot figure out, why.
This is my current class DataTemplateSelector
:
public class DynamicDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is DataRowView dataRowView)
{
foreach (var column in dataRowView.DataView.Table.Columns.Cast<DataColumn>())
{
if (column.DataType == typeof(DataTable))
{
var template = new DataTemplate();
var dataGridFactory = new FrameworkElementFactory(typeof(DataGrid));
// Binding ItemsSource to the inner DataTable's DefaultView
dataGridFactory.SetBinding(DataGrid.ItemsSourceProperty, new Binding($"{column.ColumnName}.DefaultView"));
dataGridFactory.SetValue(DataGrid.AutoGenerateColumnsProperty, true);
// Setting CanUserAddRows to False
dataGridFactory.SetValue(DataGrid.CanUserAddRowsProperty, false);
// Setting RowDetailsVisibilityMode to Collapsed
dataGridFactory.SetValue(DataGrid.RowDetailsVisibilityModeProperty, DataGridRowDetailsVisibilityMode.Collapsed);
// Adding the AutoGeneratingColumn event
dataGridFactory.AddHandler(DataGrid.LoadedEvent, new RoutedEventHandler((sender, args) =>
{
var dataGrid = sender as DataGrid;
if (dataGrid != null)
{
// This code is executed
dataGrid.AutoGeneratingColumn += DataGrid_AutoGeneratingColumnTempl;
}
}));
// Setting up RowDetailsTemplateSelector for recursive templates
dataGridFactory.SetValue(DataGrid.RowDetailsTemplateSelectorProperty,
new DynamicResourceExtension("dynamicTemplateSelector"));
template.VisualTree = dataGridFactory;
return template;
}
}
}
return base.SelectTemplate(item, container);
}
private void DataGrid_AutoGeneratingColumnTempl(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
//This code is never reached.
// Handle the AutoGeneratingColumn event to customize columns
MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
if (mainWindow != null)
{
mainWindow.HandlerDgAutoGeneratingColumn(sender, e);
}
}
}
I tried asking this question to ChatGPT with no success. I expect DataGrid_AutoGeneratingColumnTempl
to be called. I should be able to see 3 inner DataGrids. But i only see one where the buttons in the third columns are not displayed: Status Quo. There should be buttons in the “InnerDataTable” column.