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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…