How to reference a generic type in the DataType at

2019-01-26 05:08发布

I have a ViewModel defined like this:

 public class LocationTreeViewModel<TTree> : 
               ObservableCollection<TTree>, INotifyPropertyChanged
                                                    where TTree : TreeBase<TTree>

I want to reference it in the DataType attribute of a DataTemplate in XAML. How can I do that?

5条回答
戒情不戒烟
2楼-- · 2019-01-26 05:24

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

查看更多
一夜七次
3楼-- · 2019-01-26 05:30

Slightly improved version of MarkupExtension, work for classes upto 3 generic parameters.

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

  }
查看更多
相关推荐>>
4楼-- · 2019-01-26 05:32

The only way i could do this is to use 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);
     }
}

And to use it i just need to do this:

<DataTemplate DataType="{app:GenericType app:TreeBaseClass}">
查看更多
The star\"
5楼-- · 2019-01-26 05:45

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>
{
}
查看更多
Luminary・发光体
6楼-- · 2019-01-26 05:49

The {x:Type} markup extension supports allows generic type arguments to be specified as a comma separated list in parentheses.

Here's an example:

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

I am using .Net 4.5 on VS 2015, so your mileage may vary.

查看更多
登录 后发表回答