There is no support for that out of the box. But you can make it work by creating your own DataTemplateSelector
that supports generics:
public class OpenGenericTypeDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item,
DependencyObject container)
{
var element = container as FrameworkElement;
if (item != null && element != null)
{
if (item.GetType().IsGenericType)
{
var genericTypeDefinition = item.GetType()
.GetGenericTypeDefinition();
var key = new DataTemplateKey(genericTypeDefinition);
return element.TryFindResource(key) as DataTemplate;
}
}
return null;
}
}
You than can use it like this:
<UserControl.Resources>
<OpenGenericTypeDataTemplateSelector x:Key="GenericTemplateSelector" />
</UserControl.Resources>
...
<TreeView ItemTemplateSelector="{StaticResource GenericTemplateSelector}" ...>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:SimpleNode`1}"
ItemsSource="{Binding Children}">
...
</HierarchicalDataTemplate>
</TreeView.Resources>
What that does is actually very simple:
When you create a DataTemplate
for a certain type, that type's name will automatically become the key of that template.
The default DataTemplateSelector
uses the type of the item as lookup value. But the type of a an instance of a generic class is a closed generic type, i.e. one that has the generic type parameter specified.
Problem is: The template has been registered for the open generic type, i.e. without the generic type parameter specified. That's why the default DataTemplateSelector
doesn't pick up DataTemplate
s registered for an open generic type.
The implementation I provided adds support for open generic types by simply checking the type of the item. If it is generic, we get ourselves the open generic type (via GetGenericTypeDefinition
) and use that as the key.
To actually make use of this selector, we have to tell the TreeView
that it should use it. We are doing that by specifying the ItemTemplateSelector
.