I liked this approach to the solution, except that it will not work with virtualization.
Here's the relevant code from that post, abbreviated:
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
DataRowView dataRow = (dataItem as DataRowView);
object cellData = dataRow[cell.Column.DisplayIndex];
var contentHost = new ContentControl() { Content = cellData };
contentHost.ContentTemplate = (DataTemplate)SomeResourceDictionary["SomeResourceKey"];
return contentHost;
}
This method is called by the DataGrid
for every cell created/rendered. If virtualization is enabled, then the FrameworkElement
created here may be recycled, i.e. used again.
The problem: using the information stored in cell
and dataItem
the content is determined and a direct reference is passed to the created ContentControl
. If this FrameworkElement
is reused, it will reference the same content - regardlesss of which row it is being rendered for.
Result: during (quick) scrolling the content displayed in the grid rows will randomly be mixed up.
My question: using cell.Column.DisplayIndex
can the ContentControl.Content
binding be set without including a direct reference to the desired content? Maybe, as if I defined it in Xaml something like this: "{Binding Path=dataRow[0]}"
- but that also doesn't seem quite right.
Any suggestions greatly appreciated!
@BionicCode:
There are two challenges addressed here:
- Binding a
DataGrid
to a source with dynamic columns. - Allow a
DataTemplate
to be defined for each dynamically generated column.
The first issue is covered quite well in the post linked above: create a DataTable
from the original source and bind the DataGrid
to that. The difficult part of the second issue - and why DataGridTemplateColumns
cannot simply be used - is that DataGridTemplateColumns
receive the entire row item as data context, i.e. to access the correct data, the template would have to know which column it is being used in.
This is where the code solution shown above comes in, by manually generating the FrameworkElement
and "statically" assigning the desired content.
Luckily, the fix is rather simple, see my answer below.