Injecting Xaml with Unity Application Block using Markup Extensions. Part 2.


Notes: This article assumes that you are familiar or started playing with a Unity Application Block. I won’t dwell on describing it’s architecture or manuals so please refer to the link mentioned for more details.

Introduction

In the previous article I’ve described how user custom controls can be injected into Xaml markup without code behind operations using custom Markup Extensions. I’ve mentioned that there might be more easy way of introducing common WPF controls without any need for subclassing. So my second article will cover this very situation.

Aliases and Type Mapping

Similar to declaring contract interfaces and mapping all the required types to single content you can have no predefined contract. Dealing with UI controls common UIElement class may serve perfectly well as a contract. Especially if you noticed that my UnityReference markup extension was dealing with UIElement objects mainly.

So UIElement alias declaration within our "App.config" file can be the following

<typeAlias alias="UIElement" type="System.Windows.UIElement, PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

Similar to the line above you are able to declare aliases for any set of controls required for your use in the Unity Container. Here’s what I’ll be playing with later on:

<typeAlias alias="Button" type="System.Windows.Controls.Button, PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<typeAlias alias="TabControl" type="System.Windows.Controls.TabControl, PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<typeAlias alias="TextBox" type="System.Windows.Controls.TextBox, PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<typeAlias alias="ListBox" type="System.Windows.Controls.ListBox, PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

As you can see I’ve just declared four standard controls.

Container definition is extremely simple

<container name="containerOne">
        <types>
          <type type="UIElement" mapTo="Button" name="UnityButton"/>
          <type type="UIElement" mapTo="TabControl" name="UnityTabControl"/>
          <type type="UIElement" mapTo="TextBox" name="UnityTextBox"/>
          <type type="UIElement" mapTo="ListBox" name="UnityListBox"/>
        </types>
      </container>

All the controls are mapped under base UIElement type. Each control name is prefixed with a "Unity*" to bring more clearance in the markup (this is just for testing purposes and you can provide any name you want).

Container Provider and ConfigurationĀ  Markup Extension

Both Container Provider and Configuration extension remains unchanged so you can refer to the previous post or source code for more detailed information.

UnityControl Markup Extension

Here comes the most important part. UnityControl markup extension is based on the previous "UnityReference" one though extended with a set of more efficient facilities.

Support for property setters

As this extension is being transformed into UIElement it is obvious that we might want defining some properties not covered with initialization phase or whatever. For this very purpose I’ve introduced dedicated collection of my custom "PropertySetter" classes. PropertySetter contains only two properties: "Property(string)" and "Value(object)"

Here’s the basic example what I’m talking about

<this:UnityControl Container="defaultProvider" Dependency="UnityListBox">                
    <this:UnityControl.Properties>
        <this:PropertySetter Property="Background" Value="Wheat"/>
        <this:PropertySetter Property="Height" Value="100"/>
        <this:PropertySetter Property="ItemsSource">
            <this:PropertySetter.Value>
                <x:Array Type="sys:String">
                    <sys:String>Hello</sys:String>
                    <sys:String>World</sys:String>
                </x:Array>
            </this:PropertySetter.Value>
        </this:PropertySetter>
    </this:UnityControl.Properties>
</this:UnityControl>

Here I’ve injected some UI control named "UnityListBox", specified Background and Height. Also I’ve provided a list of strings to be applied as an ItemsSource.

<this:UnityControl Container="defaultProvider" Dependency="UnityTabControl">
    <this:UnityControl.Properties>
        <this:PropertySetter Property="Height" Value="100"/>
        <this:PropertySetter Property="ItemsSource">
            <this:PropertySetter.Value>
                <x:Array Type="TabItem">
                    <TabItem Header="Page1"/>
                    <TabItem Header="Page2"/>
                </x:Array>
            </this:PropertySetter.Value>
        </this:PropertySetter>
    </this:UnityControl.Properties>
</this:UnityControl>

Here I’ve injected a "UnityTabControl" element and predefined two pages of TabItem type.

The property/value conversion procedure is rather dummy and the subject to change but you are able configuring some properties and getting the basic idea. Note that I’ve supported only Dependency Properties.

Default Content Property Support

Next thing I wanted a lot is specifying the Content of UIElement in the common WPF manner without declaring any additional tags. Most of the standard controls have some properties marked with the ContentPropertyAttribute pointing to the property that will be defined when specific declaration is omitted.

For this case I’ve also implemented additional property "Content" for my markup extension and delegated it’s value to the control being injected with the container.

Here’s the sample:

<this:UnityControl Container="defaultProvider" Dependency="UnityButton">
    <this:UnityControl.Properties>                    
        <this:PropertySetter Property="Height" Value="50"/>
    </this:UnityControl.Properties>                
    <Image Source="Images/data.png" Width="32" Height="32" Stretch="Uniform"/>                
</this:UnityControl>

In this sample I’m injecting "UnityButton" element defining it’s Height property value. Also pay attention to the Image control declaration as a default content. This will be delegated to the button’s content after injection. Omitting the properties you can use the following declaration either:

<this:UnityControl Container="defaultProvider" Dependency="UnityButton">
    <Image Source="Images/data.png" Width="32" Height="32" Stretch="Uniform"/>                
</this:UnityControl>

The content can be also defined using the following markup

<this:UnityControl Container="defaultProvider" Dependency="UnityTextBox" Content="Default text"/>

In this sample I’m injecting the "UnityTextBox" control providing the Content as "Default text" string. As TextBox defines "TextProperty" dependency property as a default content I’ve defined the TextBox text here.

image

Conclusion

This approach may help you dynamically configuring your UI without rebuilding main application. Changing the type mapping or introducing new aliases you bring more power and extensibility. Any time any control can be patched or changed to completely new implementation.

Note: I’ve rebuild Unity targeting .net 3.5 framework. Binaries can be found in the "binaries" folder of the project.

Source code for the article

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s