Write more generic WPF Converters

With XAML we often use Converters during a Binding to adapt the source data to the destination type. For example, the BooleanToVisibilityConverter converts a Boolean value into a value in the Visibility enumeration.

This mechanism is very convenient but we can find ourselves quickly with many converters of the type:

  • BooleanToVisibilityConverter
  • InverseBooleanConverter
  • EnumerableToBooleanConverter
  • etc.

Instead of creating Converters specific to each case it is better to try to make them generic in order to reuse them in a maximum of cases and thus avoid their multiplication. For example, the above converters can be summarized as a single Converter: BooleanToValueConverter. Each time the source is a Boolean expression (true equals, is null, is empty), only the output value differs. So just make it editable. For this it is possible to define properties in Converters:

public class BooleanToValueConverter : IValueConverter
    public object TrueValue { get; set; }
    public object FalseValue { get; set; }
    public object DefaultValue { get; set; }

    private object GetValue(bool value)
        return value ? TrueValue : FalseValue;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        if (value == null)
            return GetValue(false);

        if (value is bool)
            return GetValue((bool)value);

        // Install-Package CodeFluentRuntimeClient (http://www.softfluent.com/products/codefluent-runtime-client)
        // Ou replace with Boolean.TryParse(string.Format("{0}", value), out boolean)
        bool boolean;
        if (ConvertUtilities.TryChangeType(value, culture, out boolean))
            return GetValue(boolean);

        var str = value as string;
        if (str != null)
            return GetValue(!string.IsNullOrEmpty(str));

        var enumerable = value as IEnumerable;
        if (enumerable != null)
            var enumerator = enumerable.GetEnumerator();
            bool any = enumerator.MoveNext();
            return GetValue(any);

        return DefaultValue;

You can now use this Converter in different cases:

    <system:Boolean x:Key="TrueValue">True</system:Boolean>
    <system:Boolean x:Key="FalseValue">False</system:Boolean>

    <utilities:BooleanToValueConverter x:Key="ValueToBooleanConverter" TrueValue="{StaticResource TrueValue}" FalseValue="{StaticResource FalseValue}" DefaultValue="{StaticResource FalseValue}" />
    <utilities:BooleanToValueConverter x:Key="ReverseValueToBooleanConverter" TrueValue="{StaticResource FalseValue}" FalseValue="{StaticResource TrueValue}" DefaultValue="{StaticResource TrueValue}" />
    <utilities:BooleanToValueConverter x:Key="ValueToVisibilityConverter" TrueValue="{x:Static Visibility.Visible}" FalseValue="{x:Static Visibility.Collapsed}" DefaultValue="{x:Static Visibility.Visible}" />

We now have only one converter but this one is no longer limited to a single use case.

The complete code: https://gist.github.com/meziantou/04ea08a9897755ba0b06

Leave a reply