Activator 2: XAML and Generics Day

First of all, you didn’t miss part one. Just thought it was a funny reference.

I’m currently working on a new release of WPF Contrib. In my TaskDialog class, I used a few classes I derived from ItemsControl (which I’m considering deleting in this version, but that’s another debate). The reason I created them was so that you could add any item to the ItemsControl and it would be wrapped in some specific ContentControl, such as a Button. But if you added a Button, it would know that it doesn’t need wrapping (this is what the IsItemItsOwnContainerOverride() and GetContainerForItemOverride() methods do).

I had three classes which were exactly the same, aside from the type of the ContentControl. Generics would very much fit here, but unfortunately, XAML has a very limited support for it (it seems the new .NET 4.0 XAML stack will improve this, and much more). As an exercise I decided to try and extend XAML so it will support generics – on a basic level.

XAML can be extended using MarkupExtensions. These are classes that have a single method, ProvideValue(), that when XAML (or BAML) is loaded, create objects according to some custom logic. You’re surely familiar with the TypeExtension (x:Type), which returns a System.Type from the specified qualified string. What I’ve done is create two new extensions:

{t:Type gen:List, {t:Type gen:List, {t:Type gen:KeyValuePair, sys:String, sys:Int32}}}

Note that you don’t have to (but can) specify gen:List`1. The number of type arguments will be inferred. The constructors support up to 4 type arguments. In the unlikely case that you need more than that, you can use the unabbreviated form and specify the arguments as sub-elements.

<t:ActivatorExtension x:Name="ic" Type="{t:Type t:ItemsControl, {t:Type CheckBox}}">
    <t:Setter Name="Name" Value="ic" />
    <t:Setter Name="Background" Value="{Binding ElementName=tb, Path=Text}" />
    <t:Setter Name="ItemsSource">
        <x:ArrayExtension Type="{x:Type sys:String}">
            <sys:String>one</sys:String>
            <sys:String>two</sys:String>
            <sys:String>three</sys:String>
            <sys:String>four</sys:String>
        </x:ArrayExtension>
    </t:Setter>
</t:ActivatorExtension>

There are, however, a few severe limitations:

As I said in the beginning, this was just an experiment I wanted to share, and in no way should be viewed as a production-quality solution. I will, however, be adding the TypeExtension to the upcoming drop of WPF Contrib. It can be used to specify DataTemplate resource keys for generic types.

Attachment: ActivatorDemo.zip