Как обратиться к универсальному типу в атрибуте DataType HierarchicalDataTemplate? - PullRequest
7 голосов
/ 10 ноября 2009

У меня есть класс MyClass<MyObject> и я хочу установить его в качестве типа данных для иерархического шаблона данных.

Каков синтаксис этого в XAML? (Я знаю, как установить пространства имен, мне нужен только синтаксис для

<HierarchicalDataTemplate DataType="{X:Type .....

Ответы [ 3 ]

16 голосов
/ 10 ноября 2009

Подход Итоулсона хорош, но это только начало.Вот что будет работать в вашем случае (и в большинстве, если не во всех случаях):

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;
    }
}

Затем вы можете создать любой тип с любым уровнем глубины в вашем XAML.Например:

    <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>

Здесь есть несколько ключевых идей:

  • Универсальный тип должен быть указан с использованием стандартной `записи.Итак, System.Collections.Generic.List <> равно System.Collections.Generic.List`1 .Символ `указывает на то, что тип является универсальным, а число после него указывает на число универсальных параметров, которые имеет тип.
  • Расширение разметки x: Type способно довольно легко получить эти базовые универсальные типы.
  • Общие типы параметров передаются в виде массива объектов Type.Этот массив затем передается в вызов MakeGenericType (...).
4 голосов
/ 10 ноября 2009

Это не поддерживается в WPF 3.x из коробки (я думаю, что это может быть в 4.0, но я не уверен); но его легко настроить с помощью расширения разметки.

Сначала необходимо создать класс расширения разметки, который принимает параметр типа в качестве аргумента конструктора:

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);
  }
}

Теперь вы используете это расширение разметки вместо расширения x: Type:

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

Само собой разумеется, это может быть обобщено, чтобы позволить создание экземпляров произвольных универсальных типов; Я не показывал это, потому что это добавляет немного больше сложности.

1 голос
/ 23 марта 2011

В .NET 4.0 используйте код ниже.

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

...