How to reference a generic type in the DataType attribute of a HierarchicalDataTemplate? How to reference a generic type in the DataType attribute of a HierarchicalDataTemplate? wpf wpf

How to reference a generic type in the DataType attribute of a HierarchicalDataTemplate?


itowlson's approach is a good one but it is just a start. Here's something that will work for your case (and most, if not all, cases):

public class GenericType : MarkupExtension{    public Type BaseType { get; set; }    public Type[] InnerTypes { get; set; }    public GenericType() { }    public GenericType(Type baseType, params Type[] innerTypes)    {        BaseType = baseType;        InnerTypes = innerTypes;    }    public override object ProvideValue(IServiceProvider serviceProvider)    {        Type result = BaseType.MakeGenericType(InnerTypes);        return result;    }}

Then, you are able to create any type with any level of depth in your XAML. For example:

    <Grid.Resources>        <x:Array Type="{x:Type sys:Type}"                  x:Key="TypeParams">            <x:Type TypeName="sys:Int32" />        </x:Array>        <local:GenericType BaseType="{x:Type TypeName=coll:List`1}"                            InnerTypes="{StaticResource TypeParams}"                           x:Key="ListOfInts" />        <x:Array Type="{x:Type sys:Type}"                  x:Key="DictionaryParams">            <x:Type TypeName="sys:Int32" />            <local:GenericType BaseType="{x:Type TypeName=coll:List`1}"                                InnerTypes="{StaticResource TypeParams}" />        </x:Array>        <local:GenericType BaseType="{x:Type TypeName=coll:Dictionary`2}"                           InnerTypes="{StaticResource DictionaryParams}"                           x:Key="DictionaryOfIntsToListOfInts" />    </Grid.Resources>

There's a few key ideas here:

  • A generic type has to be specified using the standard ` notation. So, System.Collections.Generic.List<> is System.Collections.Generic.List`1. The character ` indicates that the type is generic and the number after it indicates the number of generic parameters the type has.
  • The x:Type markup extension is able to retrieve these base generic types quite easily.
  • The generic parameter types are passed as an array of Type objects. This array is then passed into the MakeGenericType(...) call.


This is not supported in WPF 3.x out of the box (I think it may be in 4.0, but I'm not sure); but it's easy to set up with a markup extension.

First, you need to create a markup extension class that takes the type parameter as a constructor argument:

public class MyClassOf : MarkupExtension{  private readonly Type _of;  public MyClassOf(Type of)  {    _of = of;  }  public override object ProvideValue(IServiceProvider serviceProvider)  {    return typeof(MyClass<>).MakeGenericType(_of);  }}

Now you use this markup extension in place of the x:Type extension:

<HierarchicalDataTemplate DataType="{local:MyClassOf {x:Type MyObject}}" />

Needless to say, this can be generalised to allow instantiation of arbitrary generic types; I haven't shown this because it adds a wee bit more complexity.


In .NET 4.0, use below code.

XamlNamespaceResolver nameResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlNamespaceResolver;IXamlSchemaContextProvider schemeContextProvider = serviceProvider.GetService(typeof(IXamlSchemaContextProvider)) as IXamlSchemaContextProvider;XamlTypeName xamlTypeName = new XamlTypeName(nameResolver.GetNamespace("generic"), "List`1");Type genericType = schemeContextProvider.SchemaContext.GetXamlType(xamlTypeName).UnderlyingType;

http://illef.tistory.com/115