IValueConverter Interface (System.Windows.Data.IValueConverter)

Probably the most common question I get from people new to WPF is how to bind the Visibility of a control based on a System.Boolean value. WPF provides IValueConverter in System.Windows.Data specifically for converting one type to another and back when binding. Let's setup a very simple example.

/// <summary>
/// ViewModel for MainWindow
/// Assigned to MainWindow.DataContext in its class constructor
/// </summary>
internal class MainWindowDataContext : INotifyPropertyChanged
{
    private bool _visible;

    public bool Visible {
        get {
            return _visible;
        }
        set {
            _visible = value;

            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null) {
                handler(this, new PropertyChangedEventArgs("Visible"));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Visibility="{Binding Visible}" />
    </Grid>
</Window>

You should already know that line 7 doesn't work. There isn't a conversion from System.Boolean to System.Windows.Visibility. This is where IValueConverter comes in, so we will make a new class that implements the interface and call it BoolToVisibilityConverter.

internal class BoolToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        if (!(value is bool)) {
            throw new System.ArgumentException("value is not of type System.Boolean", "value");
        }
        return (bool)value ? Visibility.Visible : Visibility.Hidden;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        if (!(value is Visibility)) {
            throw new System.ArgumentException("value is not of type System.Windows.Visibility", "value");
        }
        switch ((Visibility)value) {
            case Visibility.Visible:
                return true;
            default:
                return false;
        }
    }
}

The implementation is simple. When the binding gets the value from MainWindow.DataContext (eg. MainWindowDataContext.Visible) it is passed to the value parameter of object Convert. Then it's up to the convert method to return the appropriate value based on the parameter. In this case, we do a simple check to make sure the parameter is in fact a System.Boolean value, and if it is we return the appropriate Visibility enumeration value. Obviously, ConvertBack does exactly the opposite when the value of the binding is set, and is propagated down to the data context. It takes a Visibility value and converts it to a System.Boolean value, which is assigned to MainWindowDataContext.Visible.

Now we need to update our Xaml to use the converter. This is done by including it as a resource and specifying the Converter attribute on the binding.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverterResourceKey"/>
        </Grid.Resources>
        <Button Visibility="{Binding Visible, Converter={StaticResource BoolToVisibilityConverterResourceKey}}" />
    </Grid>
</Window>

You can implement IValueConverter any time you need to convert one type to another and back in a binding.

1 Comment

  1. Zack

    Awesome, thanks!

Leave a Comment