Tuesday, November 1, 2011

Silverlight: Control visibility based on several properties' values

Hi there.

During last few months I've noticed that many people are struggling with problems like object visibility based on parameters.
And here I will try to make this more easy for some of them.
So, let's begin. First of all let me make a not about the IValueConverter interface, introduced in silverlight framework. That's really a very usefull contract, especially when you get used to converters. You now ask about converters ? Sure: A converter is there to help you to convert a value to match the expected result and vice-versa. That's a mechanism, which adopts the input to output, assuming that the output is fully depending on input.
So, how does it work ? Let's assume we have the following XAML:

    <TextBlock Text="Dummy text" Visibility="{Binding Path=DummyTextVisibility}" />

Most of the developers will go this way - trying to match the properties to the UI expectations. But this is NOT CORRECT ! Just think - You're trying to bend your logic to match the View ? Everywhere, in every study about UI development you read that separation is something everyone is trying to achieve (I mean presentation and logic separation). And here you try to adopt the logic based on presentation.
So which is correct ? The correct way to handle this is to not think about the presentation layer at all, when you're developing the business layer. And as soon as you think this way, you see, that it would be much natural to have something like this:

    <TextBlock Text="Dummy text" Visibility="{Binding Path=IsDummyTextVisible}" />

But wait... will this work ? Sure not, cause the Visibility property expecting something of type System.Windows.Visibility, and you've just passed in a bool.
Here the Converter comes in: it lets you to bind to anything logical, and then get what you want to get from it, so it will let us write the following, assuming that we have defined BoolToVisibilityConverter:

  <cnv:BoolToVisibilityConverter x:Key="boolToVisibility" />
   <TextBlock Text="Dummy text" Visibility="{Binding Path=IsDummyTextVisible,Converter={StaticResource boolToVisibility}}" />

We assume here also that the xmlns:cnv was imported in the root tag, and that the <cnb:BoolToVisibilityConverer ... was defined in the resources section.
And here is the code for the BoolToVisibilityConverter:

public class BoolToVisibilityConverter:IValueConverter
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            return (bool)value ? Visibility.Visible : Visibility.Collapsed;
        catch (Exception ex)
            return Visibility.Collapsed;

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        /// some logic here if you're going to use this

Great. Now we have everything in place except the thing, that in some cases you will need to make an object visible depending on two parameters - control is going to be visible if both those parameters are visible. Don't waste your time looking for some complex solutions, just wrap your control in a Panel control, and bind its visibility to the other parameter you'd like to:

<Grid Visibility="{Binding Path=SecondParameter, Converter={StaticResource boolToVisibility}}">
    <TextBlock Text="Dummy text" Visibility="{Binding Path=IsDummyTextVisible,Converter={StaticResource boolToVisibility}}" />

So, that's it. Enjoy :)

No comments: