Before you answer: This question is about WPF's ListView
control (with GridView
). It is not about WPF's DataGrid
control, ASP.NET's DataGrid
or ListView
controls, or WinForm's DataGridView
or ListView
controls. They all sound very similar and are often confused, but an answer for the wrong type of control is both unhelpful to me and more importantly a waste of the time you took to write the answer, which I believe should not be squandered.
I have a ListView
control with GridView
that has several columns bound to my view-model's properties. I can easily customize the visual appearance of the GridViewColumn
's cells by specifying a CellTemplate
(either inline or via a resource).
Now I have a particular property on my view-model; its type is an abstract base class and its value can be one of several derived types. Each derived type should have a different DataTemplate
in the cell. Luckily, GridViewColumn
has a CellTemplateSelector
which does exactly what I want, but requires writing some plumbing code. But looking at the page for DataTemplateSelector
it says:
Note that if you have objects of different types you can set the DataType property on the DataTemplate. If you do that then there is no need to create a DataTemplateSelector. [...] For more information, see Data Templating Overview.
Hurray! No need to write plumbing code. My types are different so this seems like a perfect fit. But alas, even after I defined a DataTemplate
with a DataType
that matches a specific derived type of one of the databound columns (bound using GridViewColumn
's DisplayMemberBinding
), it had no effect.
I simply want to display a different DataTemplate
according to the runtime type of a certain column in my GridView
. Are DataType
-targeted DataTemplates
simply incompatible with GridView
? Is there a way to use them, or must I resort to specifying a CellTemplateSelector
? Perhaps there is a way to specify multiple DataTemplate
s inside GridViewColumn
's CellTemplate
, so that the DataType
property will have an effect?
The implementation of
DisplayMember*
properties is crap, i have no idea why they thought that binding aTextBlock
instead of aContentPresenter
would be a good idea.I would recommend an attached property or a subclass with a respective property to override this. You just need to make it create a
DataTemplate
containing aContentPresenter
whoseContent
is bound to the targeted property, that will allow for implicitDataTemplating
. This deferringDataTemplate
then should be assigned as theCellTemplate
of the column.WPF allows you to insert objects such as
ViewModels
in the Logical Tree, while aDataTemplate
can be used to tell WPF how to draw the specified object when drawing the Visual Tree.An implicit
DataTemplate
is aDataTemplate
that only has aDataType
defined (nox:Key
), and it will be used automatically whenever WPF tries to render an object of the specified type in the VisualTree.So, you can use
to tell WPF to draw ViewModelA with ViewA, ViewModelB with ViewB, and ViewModelC with ViewC.
If you only want this applied to your GridView instead of to the entire Window, you can specify
<GridView.Resources>
(or<ListView.Resources>
, I can't remember which one)It should be noted that if you are binding your column using the
DisplayMemberBinding
, it will render as aTextBox
with theText
value bound to your property, which means it will renderYourViewModel.ToString()
instead of trying to draw the ViewModel in the VisualTree using yourDataTemplate
.To avoid that, simply set the
CellTemplate
to something like aContentPresenter
with theContent
property bound to yourViewModel
, and it will render your ViewModel using your implicitDataTemplates