1

In WPF one has the possibility to use a converter in binding, so that one can bind for instance a Visibility property of a control to a Boolean property in the view model.

For this specific pairing (Visibility and Boolean) WPF does offer an out-of-the-box converter called BooleanToVisibilityConverter.

But let's say I'd like to bind a Boolean property of a control to a Visibility property in the view model. Is there any way to use the standard BooleanToVisibilityConverter and tell the binding to invert it (to use ConvertBack instead on Convert and vice versa)?

Or do I have to write another converter for that case?

Nostromo
  • 1,177
  • 10
  • 28
  • 4
    You would have to write another converter, obviously. Besides that, having a property of type Visibility in a view model seems pretty odd. – Clemens Oct 23 '19 at 09:18
  • 1
    You could of course think of writing a general-purpose InverseConverter, which always inversely delegates to another converter that you can set by a property. – Clemens Oct 23 '19 at 09:22
  • https://stackoverflow.com/questions/534575/how-do-i-invert-booleantovisibilityconverter please take a look – Alfred Manoj Oct 23 '19 at 11:44
  • 1
    Do you realize that the accepted post doesn't answer your question? – Clemens Oct 23 '19 at 14:10

2 Answers2

2

So, there is no built-in way of inverting the converter. We can, however, work around that by introducing a "shim" converter like this one:

public class InverterConverter : IValueConverter
{
    public IValueConverter Converter { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Converter.ConvertBack(value, targetType, parameter, culture);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Converter.Convert(value, targetType, parameter, culture);
    }
}

With the usage as follows:

<ContentControl>
    <ContentControl.Content>
        <Binding>
            <Binding.Converter>
                <InverterConverter Converter="{StaticResource YourConverter}" />
            </Binding.Converter>
        </Binding>
    </ContentControl.Content>
</ContentControl> 

This, obviously, is some heavy syntax but we can simplify it with this little markup extension:

public class InvertedExtension : MarkupExtension
{
    public IValueConverter Converter { get; set; }

    public InvertedExtension(IValueConverter converter)
    {
        Converter = new InverterConverter() { Converter = converter };
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return Converter;
    }
}
<ContentControl Content="{Binding Converter={Inverted {StaticResource MyConverter}}}" />
TripleAccretion
  • 312
  • 3
  • 10
  • does it really work? `InvertedConverter.Convert(true)` will mean `BooleanToVisibilityConverter.ConvertBack(true)` - but BooleanToVisibilityConverter expects Visibility value in ConvertBack – ASh Oct 23 '19 at 18:33
  • But we do not need to convert from `Boolean` in that case, do we? The expected source property is of type `Visibility` (else we would just use regular `BooleanToVisibilityConverter`). Am I missing something obvious? – TripleAccretion Oct 23 '19 at 18:47
  • sorry, I misunderstood the question and posted a confusing comment. You are correct. Btw, why tag syntax for ``? ` ` should work, and `Content="{StaticResource inverter}"` – ASh Oct 23 '19 at 18:54
  • Yes, you are right indeed. Not going to lie, the markup bloat is a little bit (I didn't think really hard on how to optimize it) intentional, so that the extension looks cool. That said, polluting resources with essentially duplicate converters is also kind of meh. – TripleAccretion Oct 23 '19 at 18:58
1

Is there any way to use the standard BooleanToVisibilityConverter and tell the binding to invert it (to use ConvertBack instead on Convert and vice versa)?

No.

Or do I have to write another converter for that case?

Yes.

You could implement a generic converter that accepts "true" and a "false" values of any type:

public class BooleanConverter<T> : IValueConverter
{
    public T True { get; set; }
    public T False { get; set; }

    public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
        value is bool && ((bool)value) ? True : False;

    public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
        value is T && EqualityComparer<T>.Default.Equals((T)value, True);
}

...and derive from this for each type that you want to handle:

public class BooleanToVisibilityNegationConverter : BooleanConverter<Visibility>
{
    public BooleanToVisibilityNegationConverter()
        : base()
    {
        True = Visibility.Hidden;
        False = Visibility.Visible;
    }
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • This doesn't answer the question. How would you use it to bind a boolean property to a view model property of type Visibility? Configuring the target property values for a boolean source property is not the same as exchanging source and target type, i.e. forward and back conversions. – Clemens Oct 23 '19 at 14:25
  • @Clemens: No and Yes should answer the two questions asked by the OP. The sample converter can only be used when binding to a `bool` source property though. – mm8 Oct 23 '19 at 15:09
  • "*Is there any way to use the standard BooleanToVisibilityConverter and tell the binding to invert it (to use ConvertBack instead on Convert and vice versa?*" - that's the core question, and obviously not at all covered by your post. See the other answer for the difference. – Clemens Oct 23 '19 at 15:48
  • @Clemens: The answer to that question is no and this is covered in my post. – mm8 Oct 24 '19 at 12:59
  • Not at all, sorry. While it is correct to say that a new converter has to be written, the one you are showing doesn't do what OP asked for. Isn't that totally obvious? – Clemens Oct 24 '19 at 13:31