WPF: How to use converters without creating static resources

To avoid creating a static resource every time you want to use a converter, you can create converters that are also markup extensions.

Normally you would declare a converter like this:

<UserControl.Resources>
    <my:BoolVisibilityConverter x:Key="visibilityConverter" />
</UserControl.Resources>

And then you would call it like this:

<Label
    Content="Please wait!"
    Visibility="{Binding IsBusy, Converter={StaticResource visibilityConverter}}" />

I don’t know about you, but I don’t find any fun in having to declare a converter each time I want to use one. To avoid this, we can create a hybrid markup extension/converter. I first saw this approach in Dr. WPF blog.

First we create a generic template class which will be the base of all our converters.

public abstract class ConverterMarkupExtension<T> : MarkupExtension, IValueConverter where T: class, new()
{
    private static T _converter = null;
    
    public ConverterMarkupExtension()
    {
    }
    
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return _converter ?? (_converter = new T());
    }
    
    public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
    public abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}

Then we subclass it when creating a converter:

[ValueConversion(typeof(bool), typeof(Visibility))]
public class BoolVisibilityConverter : ConverterMarkupExtension<BoolVisibilityConverter>
{
    public BoolVisibilityConverter()
    {
    }
    
    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null && value is bool)
        {
            if ((bool)value)
            {
                return Visibility.Visible;
            }
        }
        
        return Visibility.Collapsed;
    }
    
    public override object ConvertBack(object value, Type targetType, object parameter,  CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Now when we want to use the converter we don’t need to explicitly declare it. We just do the following:

<Label
    Content="Please wait!"
    Visibility="{Binding IsBusy, Converter={my:BoolVisibilityConverter}}" />

Now you may be asking, why do we need a generic template class? Why not remove the template and singleton instance from the abstract class and just return this; in the ProvideValue method?

You could certainly do that and it would work correctly as it is, but by using the singleton you separate the markup extension from the converter which have different life times.

Imagine that at some point in the future markup extensions are changed so that they are disposed after ProvideValue is called. In this scenario, having the converter persist separately avoids the issue.

Share this

Did you like this article? Share it!

Keep up to date

Our monthly newsletter. See previous editions.

Related articles