WPF Quick Tip: Converters as MarkupExtensions


Everybody’s gotta love their IValueConverters, right? And not forgetting IMultiValueConverters too.

However, they’re a bit of a pain when it comes to Xaml. I hate having to wonder all the way up to the resources section(!), create my converter, think of a name for the key and finally reference the converter through a StaticResource markup extension.

Another thing I hate is the parsing of Converter Parameters back into the appropriate type. Boo.

Not anymore with this quick tip. Hooray.

Take this MultiplyConverter (we’ve all written one of these):

public class MultiplyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double val = System.Convert.ToDouble(value);
        double factor = System.Convert.ToDouble(parameter);
        return val * factor;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // left as an exercise for the reader
        // don’t be a wimp, it’s not hard
    }
}

Which might be used something like…
    
<!– somewhere in the resources –>
<local:MultiplyConverter x:Key=”BarryTheConverter” />    
    
<Rectangle Width=”{Binding ElementName=otherElement, Path=(Canvas.Left), Converter={StaticResource BarryTheConverter}, ConverterParameter=-0.5}” />

Sort of yuck.

V2

I think it’s a big improvement to forego the ConverterParameter and use a property on the Value Converter itself:

public class MultiplyConverter : IValueConverter
{
    public double Factor { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double val = System.Convert.ToDouble(value);
        return val * Factor;
    }
    
Which would be used like so…
    
<!– somewhere in the resources –>
<local:MultiplyConverter Factor=”-0.5″ x:Key=”BarryTheConverter” />    
    
<Rectangle Width=”{Binding ElementName=otherElement, Path=(Canvas.Left), Converter={StaticResource BarryTheConverter}}” />

A minor improvement IMO. But better nonetheless, provided we don’t need to create lots of converters for all the different ‘Factors’ we might use… unless… we implement the Converter as a markup extension.

V3


public class MultiplyConverter : MarkupExtension, IValueConverter
{
    public double Factor { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double val = System.Convert.ToDouble(value);
        return val * Factor;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // left as an exercise for the reader
        // don’t be a wimp, it’s not hard
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}
    
Which might be used like so

<!– no need for any resources in this case! –>

<Rectangle Width=”{Binding ElementName=otherElement, Path=(Canvas.Left), Converter={local:MultiplyConverter Factor=-0.5}}” />

Much better and reads easier. Hooray!


Originally posted by Josh Twist on 17th April 2009 here.

Comments (0)