WPF: XAML MarkupExtension as a Macro and Object Factory
A Visual Studio 2008 Solution with the complete code listing for this posting is attached.
The MarkupExtension in XAML opens up a world of opportunity to make XAML work the way you want it to. It reminds me somewhat of macros where we think of expanding the macro as substituting the macro for something else. If we consider that the MarkupExtension does nothing more than provide a value that is substituted for the MarkupExtension, it is very much like expanding a Macro.
Parameterised macros are extremely powerful as they do more than just save you typing, they can form a domain specific language. MarkupExtensions are stateful and you can set their state from XAML, leading to the idea that the substitution can be parameterised.
In this article I will demonstrate how to use a custom MarkupExtension as a macro or an object factory. The ideas will be applied to to a simple macro expansion case and the more pertinent case of creating a custom ValueConverter in a manner that is simpler than that provided by raw XAML.
As a simple example of a macro, we might define the following in C++ to add two numbers:
And then we could use it in code like this:
Which expands to:
We can achieve a similar effect in XAML in the following manner. Here we want to set the contents of a TextBlock to be the sum of two numbers:
Where local:Sum maps to our custom MarkupExtension:
There is one problem left to solve - the return type of ProvideValue an integer while the TextBlock.Text property is a string. We can use the target property type and System.Convert.ChangeType here to allow conversion of the return type when such conversion is possible. We have to handle the cases where the target property is either a plain-old property or a DependencyProperty.
Since MarkupExtensions nest (just like macro arguments can be macros), there is a lot in inherent power in our MarkupExtension. For example, we can do the following:
The application of this technique can be extended beyond evaluating and returning simple types. A classic example of where WPF can be a little painful to use is the ValueConverter of the Binding class.
We will be using the following custom ValueConverter. It simply doubles the value when converting forward and halves it in the reverse direction:
To use this value converter, we generally have two options as shown below:
However, there is a more terse and elegant solution using a custom Markup Extension:
Using the DoubleValueConverterExtension we can create a DoubleValueConverter in the following manner - no need for static resources or overly verbose syntax:
I have used this technique to make calls to existing object factory frameworks with great success, but there are many other applications of this technique, so keep in mind that MarkupExtensions can be thought of as macros or object factories and you will find interesting and unusual applications for them that can make your WPF life much easier.
Feel free to contact me regarding this post by email - daniel.paull at thinkbottomup.com.au - or leave comments here after registering with this site.