Как ссылаться на общий тип в атрибуте DataType DataTemplate?
У меня есть ViewModel, как это:
public class LocationTreeViewModel<TTree> :
ObservableCollection<TTree>, INotifyPropertyChanged
where TTree : TreeBase<TTree>
Я хочу ссылаться на него в атрибуте DataType DataTemplate в XAML. Как я могу это сделать?
Ответы
Ответ 1
Единственный способ сделать это - использовать MarkupExtensions
.
public class GenericType : MarkupExtension
{
private readonly Type _of;
public GenericType(Type of)
{
_of = of;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return typeof(LocationTreeViewModel<>).MakeGenericType(_of);
}
}
И для его использования мне просто нужно это сделать:
<DataTemplate DataType="{app:GenericType app:TreeBaseClass}">
Ответ 2
Нет, вы не можете выразить тип генериков в XAML. Вам нужно будет создать конкретный тип, который расширяет ваш общий...
public class FooLocationTreeViewModel : LocationTreeViewModel<Foo>
{
}
Ответ 3
В XAML 2006 это не поддерживается. Однако, если вы хотите иметь эту функциональность, вы можете свернуть самостоятельно.
Эта ссылка содержит хорошее руководство по созданию расширений разметки.
Использование будет таким:
<Grid xmlns:ext="clr-namespace:CustomMarkupExtensions">
<TextBlock Text="{ext:GenericType FooLocationTreeViewModel(Of Foo)}" />
</Grid>
Однако вы должны выбрать и реализовать синтаксис. Я предлагаю обозначение VB, так как оно не будет мешать, как обозначение С# с < и > .
Ответ 4
Расширение разметки {x: Тип} позволяет разрешать общие аргументы типа в виде списка, разделенного запятой, в круглых скобках.
Вот пример:
<UserControl x:Class="Test"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:generic="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<UserControl.Resources>
<DataTemplate DataType="{x:Type generic:List(sys:Int64)}">
<TextBlock Text="{Binding Count}"/>
</DataTemplate>
</UserControl.Resources>
</UserControl>
Я использую.Net 4.5 на VS 2015, поэтому ваш пробег может отличаться.
Ответ 5
Немного улучшенная версия MarkupExtension, работайте для классов до 3 общих параметров.
public class GenericTypeExtension : MarkupExtension
{
public GenericTypeExtension()
{
}
public GenericTypeExtension(string baseTypeName_, Type genericType1_, Type genericType2_, Type genericType3_)
{
BaseTypeName = baseTypeName_;
GenericType1 = genericType1_;
GenericType2 = genericType2_;
GenericType3 = genericType3_;
}
public string BaseTypeName { get; set; }
public string BaseTypeAssemblyName { get; set; }
public Type GenericType1 { get; set; }
public Type GenericType2 { get; set; }
public Type GenericType3 { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider_)
{
var list = new List<Type>();
if (GenericType1 != null)
{
list.Add(GenericType1);
}
if (GenericType2 != null)
{
list.Add(GenericType2);
}
if (GenericType3 != null)
{
list.Add(GenericType3);
}
var type = Type.GetType(string.Format("{0}`{1}, {2}", BaseTypeName, list.Count, BaseTypeAssemblyName));
if (type != null)
{
return type.MakeGenericType(list.ToArray());
}
return null;
}
}