The question:
Is there a way to define a DataTemplate
in XAML and instantiate it in code (rather than retrieve singleton by FindResource
) and modify its VisualTree
before sending to where a DataTemplate
is required such as DataGridTemplateColumn.CellTemplate
?
Background:
I am displaying a 2-dimensional array data[][]
in a DataGrid
by adding DataGridTemplateColumn
columns on my own and there is a DataTemplate
defined in XAML that knows how to present each element in the array. However the default DataContext
for each cell is the row, i.e. data[x]
. So I need to "parameterize" the DataTemplate
for each column by setting the root visual element's DataContext
to binding "[y]"
where y
is the column index. Currently the DataTemplate
is defined as in DataGrid.Resources
and retrieved by FindResource()
which is returning the same instance every time. Besides calling LoadContent()
gives me the UIElement
tree rather than loading the VisualTree
on the DataTemplate
itself. I am looking for a way to instantiate the DataTemplate
in code, do the desired modification and set to DataGridTemplateColumn.CellTemplate
.
You should see
DataTemplate
in WPF as a Factory. Thus I think that you don't really need a new instance of theDataTemplate
, you just want it to be applied differently based on your context.If I understand correctly your issue, the problem is that the
DataContext
of yourDataGrid
Cells is not correct : it's the Row ViewModel whereas you want it to be the Cell ViewModel (which makes perfect sense). This is however the basic behavior of the DataGrid and is probably tied to the fact that Cells in each rows are hold by a DataGridCellsPresenter (which is basically anItemsControl
) whoseItemsSource
dependency property has not been set (thus explaining the badDataContext
).I've run into this problem and found two way to fix this (but I only managed to make one work).
First one is to subclass DataGridCellsPresenter and override
OnItemChanged
method to set the ItemsSource manually.where rowViewModel.Items should point to something like data[x] in your case. However I ran into some troubles using this fix and couldnt make it work correctly.
Second solution is to subclass
DataGridCell
and update the dataContext on change of theColumnProperty
. You also have to subclassDataGridCellsPresenter
to make it create the right cell controlsFinally you will also have to override the DataGridRow default ControlTemplate to make it use your custom
DataGridCellsPresenter
in place of the originalDataGridCellsPresenter
.Inspired by Sisyphe's answer, I found this more portable solution:
Usage:
Hope this helps someone who has the same requirement as the one in my question.
Description: When you call
LoadContent
, theUIElement
objects in theDataTemplate
are created, and you can add them to the visual tree of anotherUIElement
.