Markup extensions! A very important aspect of XAML - but while you are using them all the time, you probably pay very little attention to the fact that they are markup extensions. Every time you are using those curly braces in XAML, you are dealing with a markup extension. Probably the most common one is StaticResource, but Binding is probably up there too.
But so what? So Microsoft came up with a funny syntax for enabling programmers to set complicated values on XML attributes easily. That by itself isn't particularly interesting. What is interesting, however, is that you can write and use your own markup extensions. In fact, if you didn't know you could do this, you should start getting quite excited - because really this is the best tool at your disposal for extending XAML to meet your own specialized needs.
We are going to make a pretty simple markup extension here today, but it should go a long way to showing you what you can do with them. The purpose of our example extension is to resolve an appropriate image path given a size and an image name:
public class ImgPathExtension : MarkupExtension
{
public double ImageSize { get; set; }
public string SubPath { get; set; }
public ImgPathExtension() { }
public ImgPathExtension(string path)
{
SubPath = path;
ImageSize = 0;
}
public ImgPathExtension(string path, double size)
{
SubPath = path;
ImageSize = size;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var target = serviceProvider.GetService(typeof(IProvideValueTarget))
as IProvideValueTarget;
var host = target.TargetObject as FrameworkElement;
if ((ImageSize <= 0 || double.IsNaN(ImageSize)) && host != null)
{ ImageSize = host.Width; }
string folder = ImageSize > 32 ? "256x256" : "32x32";
var source = new BitmapImage(new Uri(
"pack://application:,,,/MarkupExtensionExample;Component/Images/"
+ folder + "/" + SubPath));
var prop = target.TargetProperty as DependencyProperty;
//If we aren't sure they want a ImageSource, lets give a
//full blown image.
if (prop == null || prop.PropertyType != typeof(ImageSource))
{
var img = new Image();
img.Stretch = Stretch.None;
img.Source = source;
return img;
}
return source;
}
}
So the first thing to note is that our markup extension is based on the class MarkupExtension. Doing that is what makes this class a markup extension. There is only one thing that you are required to do when deriving from that class - implement the ProvideValue however you see fit.
The ProvideValue function on a markup extension will be called once
per use of the extension at run time (and it will be a different
instance of the markup extension every time). So this is very much not
like a binding where the value can change over time - a markup extension
only sets the value of a property once, when an element is being loaded.
So let's walk through the ProvideValue function of our markup
extension above. The first thing we do is use the
IServiceProvider
passed in to get the
IProvideValueTarget
instance for this use of the markup extension. This interface allows us
to get to all sorts of information about who we are providing the value
for - the
TargetObject
and the
TargetProperty.

On the very next line of code, we use that TargetObject property - we
try and pull out a width. This is because we are trying to be smart, and
if no desired image size was passed into the markup extension, we are
going to use the size of the element we are providing the value for.
Next, we take the image size, and resolve it to one of two available
image sizes (behind the example application here, we have two sets of
the same images - one set 32x32 pixels in size, and the other 256x256).
We then use that size (now a folder name) and the image name to construct a URI that resolves to the image. Since we are specifying the URI in code (instead of in XAML), we have to specify the entire ugly thing (according to the specs of the Pack URI Scheme). The first chuck ("pack://application:,,,/MarkupExtensionExample;Component") just specifies that the resources are located in the DLL MarkupExtensionExample (this application), and the rest of the path is the resource location in that DLL.
Ok, now we have a BitmapImage that we can return. But say we wanted to
be able to use this extension for more than just the source of an
Image? That's where the rest of the code comes in. We poke at the
TargetProperty, to try and find out the type it wants. If it does want
an image source (say, if it is the Source property of an Image) then
all is good and we return the BitmapImage we already made. If not,
however, we make an Image, set our BitmapImage as the source, and
return that.
So we have gone through the code behind this markup extension - let's take a look at how we can use it:
<Window x:Class="MarkupExtensionExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:MarkupExtensionExample"
Title="Window1" Height="300" Width="300">
<ScrollViewer>
<WrapPanel>
<Image Source="{m:ImgPath AutumnLeaves.jpg}" Width="32" />
<Image Source="{m:ImgPath SubPath=Creek.jpg, ImageSize=256}"
Stretch="None" />
<Image Source="{m:ImgPath Dock.jpg, 256}"
Stretch="None" />
<Image Source="{m:ImgPath DesertLandscape.jpg}"
Stretch="None" />
<Image Source="{m:ImgPath DesertLandscape.jpg, 32}"
Width="100" />
<Image Source="{m:ImgPath Creek.jpg, ImageSize=256}"
Stretch="None" />
<Image Source="{m:ImgPath Dock.jpg, 256}" Stretch="None" />
<Image Source="{m:ImgPath SubPath=AutumnLeaves.jpg}"
Stretch="None" />
<Image Stretch="None">
<Image.Source>
<m:ImgPath SubPath="AutumnLeaves.jpg" />
</Image.Source>
</Image>
<m:ImgPathExtension SubPath="Dock.jpg" />
</WrapPanel>
</ScrollViewer>
</Window>
All these different image instances cover all the different ways you can declare and use this extension. WPF allows us to leave off the "Extension" part of the class name (but you can still put it there if you want to. After saying the type of markup extension to be used, we get the choice of using the constructors or setting properties explicitly.
As you can see in the C# code above, our markup extension has two constructors - one that takes just the image path, and one that takes an image path and a size. If you are going to use the constructor, you just declare the values in a comma separated list, like so:
Source="{m:ImgPath DesertLandscape.jpg, 32}"
WPF chooses the constructor to use based on the number of arguments provided. It does not try and do any type matching or checking - so don't have two constructors for a markup extension that have the same number of arguments. The behavior of such a situation is undefined - you will never know which constructor is going to get called.
If you want to set the properties explicitly, you can use the following syntax (a comma separated list of property/value pairs):
Source="{m:ImgPath SubPath=Creek.jpg, ImageSize=256}"
Or, if you want, you can mix and match constructor and property setting, like so:
Source="{m:ImgPath Creek.jpg, ImageSize=256}"
In addition to the curly brace syntax, you can declare markup extensions like any other element in xaml:
<Image Stretch="None">
<Image.Source>
<m:ImgPath SubPath="AutumnLeaves.jpg" />
</Image.Source>
</Image>
You lose the constructor ability here (you have to set properties, just
like every other XAML element), but ProvideValue will get called on
this instance just like the curly brace use.
Finally, if you look at the last use of the markup extension in the XAML
example, you can see where the special case of returning an full Image
out of ProvideValue will get hit. The use of the markup extension
there just adds another image to the wrap panel. Pretty cool, eh?
Oh, one quick note - using custom markup extensions can sometimes cause weird issues with the Visual Studio designer. Your code will compile and work just fine, but the designer will throw weird errors like "No constructor for type 'foo' has 2 parameters". There is a currently open issue on this here - hopefully Microsoft gets around to fixing it (and the many, many other issues with the Visual Studio XAML designer) at some point.
Well, that about wraps it up for this intro to markup extensions. You can grab the studio project with all the code below.
Markup Extension Example Zip (193kb)
Source Files:
Cool Article, Explains Markup Extensions really well!
Good article. This is one of the clearest explanation of the markup extension concept that I've seen. It's really a simple concept when it's explained properly. Now that I understand it, I'm not sure why everyone has such a hard time describing it. Anyway, thanks for the article.
Thank you for your good sample
I am using an application that has a content file and site of origin file linked in the mainwidow.xaml file. When I change the either file and run the application the changes in either file is not displaye in the application. Can someone tell me why. The source code and project can be downloaded at http://windowsclient.net/downloads/folders/wpfsamples/entry5115.aspx
You can email me at steve_44@inbox.com with any solutions
Very good article. Clear written and easy to understand