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

Go To StackoverFlow.com

14

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?

2012-04-04 05:00
by Gypsy
possible duplicate of Can I specify a generic type in XAML?franssu 2014-04-03 09:54


-3

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}">
2013-12-12 12:42
by Gypsy
It's a poor solution since it's coupled to the LocationTreeViewModel class. - franssu 2014-04-03 09:51
@franssu:Thanks for your comment,but i don't understand what you mean?i didnt want to use this for every generic classes,i don't think its even possible! Do you have a better solution - Gypsy 2014-10-13 08:31
-1: Unfortunately this triggers a MC error; DataTemplate's DataType can only accept a predefined set of extensions [such as x:Type]. Suck up @ColinE's answer was my conclusio - Ruben Bartelink 2015-11-20 11:54


9

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>
{
}
2012-04-04 05:38
by ColinE
I used this technique with success but ultimately built a generic wrapper, see my answer expounding on thisRuben Bartelink 2015-11-20 13:11


3

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

2012-04-04 05:46
by Bas
wont work as the DataType bit of a DataTemplate doesnt permit markup extension - Ruben Bartelink 2015-11-20 13:12


0

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.

2018-06-06 02:17
by Daniel Crowe
This does not compile, at least not with framework 4.7.2 in VS2017. And I only found mention of a comma separated list in parentheses in the x:TypeArguments documentation, but not for x:Type - Clemens 2018-09-08 21:09


-3

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

  }
2015-01-22 10:27
by Mayur Shah
This does not answer the OP - no use for datatemplate - Ruben Bartelink 2015-11-20 13:13
Actually, this kind of does. You then use the markup extension in the DataType field of the DataTemplate - MarqueIV 2018-12-12 07:41
Ads