Simplify your WPF Converters with the ConvertibleMarkupExtension

Tags: WPF, MarkupExtensions, IValueConverters

You can't get away with coding in XAML without using IValueConverters. If by some miracle you've figured out how, then please, do share :). In the meantime, there is a way to keep you from having to declare each converter you use as a named resource, through MarkupExtensions. Some great examples of this technique can be found here and here.

This technique originated from Robert Sonnino, but I refactored it a teeny bit. What he wrote is a fantasic piece of code, and I'm not sure why it isn't used more often. It should be the basis for every BindingConverter that anyone ships. It uses Generics to keep you from having to write the same MarkupExtension implementation over and over again. I wish I had thought of it :).

    /// 
    /// A base class used to make awesome Converters with.
    /// 
    /// 
    /// The type implementing IValueConverter to make awesome.
    /// 
    [MarkupExtensionReturnType(typeof(IValueConverter))]
    public abstract class ConvertibleMarkupExtension<T> : MarkupExtension
        where T : class, IValueConverter, new()
    {

        #region Private Members

        private static T _converter;

        #endregion

        #region MarkupExtension Implementation

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return _converter ?? (_converter = new T());
        }

        #endregion

    }

Then you have your converters inherit from it, like this:

    /// 
    /// Converts an Integer Value into a Visibility Enumeration based on the passed-in parameter. 
    /// 
    public class IntEqualToVisibilityConverter : 
        ConvertibleMarkupExtension<IntEqualToVisibilityConverter>, IValueConverter
    {

        #region IValueConverter Implementation

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null || parameter == null) return Visibility.Collapsed;
            if (value == DependencyProperty.UnsetValue) return Visibility.Collapsed;

            int valueToCompare = (int)value;
            int referenceValue = int.Parse((string)parameter);

            return valueToCompare == referenceValue ? Visibility.Visible : Visibility.Collapsed;

        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return ((value is Visibility) && (((Visibility)value) == Visibility.Visible));
        }

        #endregion

    }

Which will let you craft your XAML code like this:

    <Label Content="Served As" Visibility="{Binding Path=GeneralInfoState, 
        Converter={converters:IntGreaterOrEqualToVisibilityConverter}, ConverterParameter=2}" />

You can even use it to make the built in converters even more awesome:

    public class BooleanToVisibilityConverter : 
        ConvertibleMarkupExtension<System.Windows.Controls.BooleanToVisibilityConverter>

So thanks a bunch, Robert Sonnino, you're the man. The ConvertibleMarkupExtension, as well as all of the Converters I've written, will be posted to a new NuGet package I'm working on in a few days. Until then, happy coding!

Add a Comment