BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Windows Presentation Foundation
.NET 4.0+

WPF Data Binding - Custom Value Converters

The ninety-eighth part of the Windows Presentation Foundation Fundamentals tutorial continues to look at value converters and their use in data binding. This article explains how to create custom value converters.

Value Converters

In the previous article in the WPF tutorial series we started to look at value converters and their use in data binding. A value converter allows a target property to be bound to a source of a different and incompatible type. We used the built-in BooleanToVisibilityConverter class, which converts between Boolean and Visibility values, to allow a control to be shown and hidden according to the IsChecked property of a CheckBox.

In many cases there won't be a standard converter to translate between the types that you require. In such situations you must create a custom value converter. In this article we'll see how to accomplish this. We'll create a simple converter and a more complex one, which accepts a parameter.

To demonstrate, create a new WPF application project in Visual Studio. Name the new solution, "CustomValueConverterDemo". Once the project is prepared, replace the XAML in the main window with the following code:

<Window x:Class="CustomValueConverterDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Custom Value Converter Demo" Height="200" Width="200">
    <StackPanel>
        <CheckBox Name="Circle" IsChecked="True">Show Circle</CheckBox>
        <Ellipse Width="50" Height="50" Fill="Red" 
                 HorizontalAlignment="Left" Margin="0 10 0 0"/>
        <Rectangle Width="50" Height="50"
                   HorizontalAlignment="Left" Fill="Blue" Margin="0 10 0 0"/>
    </StackPanel>
</Window>

The design for the window is shown below. We'll shortly add data bindings that show and hide the circle and the square according to the status of the check box.

WPF custom value converter demo window

Basic Custom Value Converter

We can make the circle be visible or collapsed using the standard BooleanToVisibilityConverter within a data binding linked to the CheckBox. Firstly, we need to add a resource for the converter. To do so, add the following code immediately after the opening Window tag and above the StackPanel:

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="B2VConverter"/>
</Window.Resources>

Modify the Ellipse to define the binding expression:

<Ellipse Width="50" Height="50" Fill="Red" 
        HorizontalAlignment="Left" Margin="0 10 0 0"
        Visibility="{Binding ElementName=Circle,Path=IsChecked,
                             Converter={StaticResource B2VConverter}}"/>

If you run the program you'll see that toggling the check box shows and hides the circle. However, as the standard value converter is quite limited, we can't apply it to the square. We need to create a custom value converter that converts from Boolean to Visibility but with the opposite results.

IValueConverter

Value converters are classes that implement the IValueConverter interface. This interface includes two methods. Convert is used to transform a source value to a type suitable for the targeted dependency property. ConvertBack reverses the process. Usually you will implement both. However, if a converter is exclusively used for read-only or write-only properties, you may elect to throw a NotImplementedException from one of the methods.

Let's create a new class for an inverse Boolean to Visibility converter. This will convert true to Collapsed and false to Visible. Begin by creating a new class file named, "InverseBooleanToVisibilityConverter". Add the following using directives, as IValueConverter is found in the System.Windows.Data namespace and we'll also be using System.Windows and System.Globalization.

using System.Windows.Data;
using System.Windows;
using System.Globalization;

Modify the class to implement the IValueConverter interface, as follows:

public class InverseBooleanToVisibilityConverter : IValueConverter
{
    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public object ConvertBack(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Both methods have the same four parameters. The first, named value, is the value to be converted. It is provided as a System.Object instance. The targetType is used to specify the expected type after conversion. In most cases the target type is known and the parameter is unused.

The parameter argument allows your value converter to receive additional information from the data binding. In our first converter we won't need any extra configuration so this will be ignored. The final parameter, culture, can be used when your converter returns different results for different culture options. The culture can be specified in the data binding if needed.

Let's implement the Convert method first. This needs to convert a Boolean value into a constant from the Visibility enumeration. False maps to Visible and true to Collapsed, reversing the behaviour of the standard converter. Modify the code for the Convert method, as follows:

public object Convert(
    object value, Type targetType, object parameter, CultureInfo culture)
{
    bool booleanValue = (bool)value;
    return booleanValue ? Visibility.Collapsed : Visibility.Visible;
}

To reverse the conversion we'll change Collapsed to true and Visible to false. As there are other possible source values for Visibility, we'll use an approach that means that Hidden will also convert to true.

public object ConvertBack(
    object value, Type targetType, object parameter, CultureInfo culture)
{
    Visibility visibility = (Visibility)value;
    return visibility != Visibility.Visible;
}
23 September 2014