How to reference a generic type in the DataType attribute of a DataTemplate?
Late and not exactly the answer to the question (CollinE and Bas already sayed the it is actually not possible)... However, maybe the alternativ solution may be helpful for others:
It is possible to resolve generic types by using a TemplateSelector like that:
TemplateSelector
public class MyTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var genericType = typeof(MyGenericType<>);
var isMyGeneric = item?.GetType().GetGenericTypeDefinition() == genericType;
return isMyGeneric ? MyTemplate : OtherTemplate;
}
public DataTemplate MyTemplate { get; set; }
public DataTemplate OtherTemplate { get; set; }
}
XAML
<UserControl.Resources>
<DataTemplate x:Key="MyTemplate">
<!-- Set Up MyTemplate -->
</DataTemplate>
<DataTemplate x:Key="OtherTemplate">
<!-- Set Up OtherTemplate -->
</DataTemplate>
<local:MyTemplateSelector x:Key="MyTemplateSelector"
MyTemplate="{StaticResource MyTemplate}"
OtherTemplate="{StaticResource MyTemplate}" />
</UserControl.Resources>
...
<ContentControl ContentTemplateSelector="{StaticResource MyTemplateSelector}"
Content="{Binding ViewModel}" />
No, you cannot express a generics type in XAML. You will have to create a concrete type that extends your generic one ...
public class FooLocationTreeViewModel : LocationTreeViewModel<Foo>
{
}
I know, that I'm a little late to the party, but I want post an answer for all those who may see this question in the future:
It is possible.
You can see the whole code in the answer to this question: DataTemplates and Generics. But since it is quite long, I will just copy the important bits. If you want more details, then look into the referenced question.
You need to write a
MarkupExtension
which can provide a closed generic type.public class GenericType : MarkupExtension { public GenericType() { } public GenericType(Type baseType, params Type[] innerTypes) { BaseType = baseType; InnerTypes = innerTypes; } public Type BaseType { get; set; } public Type[] InnerTypes { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) { Type result = BaseType.MakeGenericType(InnerTypes); return result; } }
Now you can define your type which closes your generic type in xaml, and then use the closed generic type as
DataType
of anDataTemplate
.<Window.Resources> <x:Array Type="{x:Type System:Type}" x:Key="ListWithTwoStringTypes"> <x:Type TypeName="System:String" /> <x:Type TypeName="System:String" /> </x:Array> <WpfApp1:GenericType BaseType="{x:Type TypeName=Generic:Dictionary`2}" InnerTypes="{StaticResource ListWithTwoStringTypes}" x:Key="DictionaryStringString" /> <DataTemplate DataType="{StaticResource DictionaryStringString}"> <TextBlock Text="Hi Dictionary" FontSize="40" Foreground="Cyan"/> </DataTemplate> </Window.Resources>
Be happy that the defined
DataTemplate
gets automatically selected by WPF.
In XAML 2006 this is not supported. You can, however, roll your own if you want to have this functionality.
This link has a nice tutorial on creating markup extensions.
Usage would be like this:
<Grid xmlns:ext="clr-namespace:CustomMarkupExtensions">
<TextBlock Text="{ext:GenericType FooLocationTreeViewModel(Of Foo)}" />
</Grid>
You have to choose and implement the syntax though. I suggest the VB notation since it won't interfere like the C# notation does with < and >.