Custom Markup Extension To Replace IValueConverter

Something that’s been around in WPF for a long time but is just seeing the light of day in the upcoming Silverlight 5 release is the concept of a custom MarkupExtension. For those unfamiliar with the concept, a MarkupExtension is anything within the curly braces “{}” of your xaml.

Some examples include, Binding, Static- and DynamicResource, Type, Static, etc. You can look at the code below and see some examples:

<Grid x:Name="LayoutRoot" > 
    <ContentControl Style="{StaticResource BgBlueTop}"/> 
        <Border > 
            <ItemsControl ItemsSource="{Binding Messages}"> ... </ItemsControl> 
        </Border> 
</Grid>

Basically, the xaml parser can interpret an attribute as a string literal value or convert it to an object through some means. Markup extensions allow you to do the deciding about how the value you’re setting should be interpreted by the xaml parser. For a much more in depth look at how this all works, a decent place to start is this link on MSDN:

http://msdn.microsoft.com/en-us/library/ms747254.aspx

One interesting use of MarkupExtensions I’ve been playing with is a reimplementation of the Binding markup extension to provide an alternative to the IValueConverter interface. Sometimes you really only need to do a conversion once or a couple times on a specific screen. When you implement a value converter it feels like you are taking a tiny bit of view or business logic and stuffing it in an unrelated portion of your application. That being said, a standardized library of value converters like boolean-to-visibility and so on can make developing on a project much easier to use. But for the one off scenarios, it’d be nice to keep all that logic contained in your ViewModel and not have to worry about spinning up a new class for such a simple thing.

I used the post here as a starting point for my custom binding because working with Binding or BindingBase was not going so well. From there I created my own Binding class and added a ConverterDelegate property. This property looks for a method on the same DataContext of the binding and uses a generic IValueConverter behind the scenes to call that method of the DataContext. This helps get rid of all those little one-off classes that you have to create for specific conversion scenarios.

The code is far from production ready but the gist of it is that a custom MarkupExtension overrides the ProvideValue method of the abstract MarkupExtension class. In the background I look up the method on my DataContext and use a IValueConverter that calls that method to do the conversion. So to wire up my converter I can simply do this:

<Window x:Class="CustomMarkup.Window1" 
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
	xmlns:local="clr-namespace:CustomMarkup" Title="Window1" Height="300" Width="300"> 
	<Grid> 
           <Button Content="{local:ExBinding Path=ButtonText, ConverterDelegate=ToUpper}" Height="25" Width="100"/> 
	</Grid> 
</Window>

You can see I have a converter delegate called ToUpper and in my code behind or ViewModel I can simply write whatever methods I need to do conversions like this:

public partial class Window1 : Window
{
	public Window1()
	{
		DataContext = this;
		InitializeComponent();
	}

	// our converter method
	public object ToUpper(object value)
	{
		return (object)value.ToString().ToUpper();
	}

	public string ButtonText { get; set;}
}

I can post the sample project if I get interest but the real point is to give a small showing of what’s possible with custom MarkupExtensions in WPF and SL5.

4 thoughts on “Custom Markup Extension To Replace IValueConverter

  1. Nick Post author

    I’ll try to dig it up, that’s the one problem I have is I prove out a concept satisfactorily to myself and then just move on with any cleanup or followup.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>