Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a class of MyClass<MyObject> and want to set it as the DataType for a HierarchicalDataTemplate.

What is the syntax for this in XAML? (I know how to set namespaces, I need just the syntax for

<HierarchicalDataTemplate DataType="{X:Type .....
like image 320
Dabblernl Avatar asked Nov 10 '09 07:11

Dabblernl


3 Answers

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.
like image 111
Szymon Rozga Avatar answered Nov 08 '22 16:11

Szymon Rozga


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.

like image 31
itowlson Avatar answered Nov 08 '22 16:11

itowlson


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

like image 40
illef Avatar answered Nov 08 '22 17:11

illef