Saturday, 6 August 2011

MultiBinding with inner converter

To do:

Change the visibility of a control based on two boolean properties, one of which I needed to negate.

If a pseudo-code would help:

visibilityCondition = !firstBoolValue && secondBoolValue

if (visibilityCondition)
   control.Visibility = Visible
else
   control.Visibility = Collapsed

And I need to do this using bindings (because I'm a MVVM obsessed person).

Intuitive solution (also the wrong solution) :
<MultiBinding Converter="{StaticResource MultiBoolToVisibilityConverter}">
    <Binding Path="FirstBoolValue" Converter="{StaticResource InvertBoolConverter}" />
    <Binding Path="SecondBoolValue" />
</MultiBinding>

The reason why this will not work, is because the first element in the "values" parameter of MultiBoolToVisibilityConverter, will always be DependencyProperty.UnsetValue.

Now, this issue aggravated me for a while. It seems that if a inner converter is used (in our case InvertBoolConverter), then the return type of that converter should be of the same type like the target property. ( in our case Visibility).

Why this was designed like this, I have no idea. Because the value is passed fine to the top converter, if no inner converter is used.

Once I duplicated the problem in a separate project, I found this post which explained it:

Converter in other multibinding converter - input value is UnSetValue.
"I ran into the same problem, almost with the same setup of booleans, nots and "and"s... weird, how much duplicate code is written around the world."
Weird indeed sir.

Correct solution: 

a) Don't use an inner converter, and use a less generic top converter (I used this one because I got pissed off by the problem)

b) Use inner converts on both inner bindings, which return a Visibility value. And in the top converter, join the two Visibility values.

I made a small app that demonstrates this issue. You can download it here.

No comments:

Post a Comment