Mobile Corner

Data Binding 101: The Converter Attribute

The Converter attribute can be added to the binding syntax to augment the data at the point it's data bound.

In the first article in this series, we covered the basic syntax for data binding an onscreen element attribute with a data object property. Now, we're going to look at some of the additional attributes of the data binding syntax.

We'll begin by looking at the Converter attribute, which can be added to the binding syntax to augment the data at the point it's data bound. This sounds awfully complex, but in actual fact is easier than it sounds.

Let's take the example where you want to hide or show an element on the screen based on a value on your data object. In this case, we'll add an additional field, Title, to the Person class we introduced in the previous article. However, the layout of the page should only display the Title if the Person being displayed has a Title.

Rather than leave a blank space in the layout, we need to set the Visibility attribute of the TextBlock to Collapsed. There are a couple of ways to achieve this. One option would be to simply expose another property -- TitleVisibility -- which can be directly bound to the Visibility attribute. For example:

<TextBlock Text="{Binding Title}" Visibility="{Binding TitleVisibility}"/>

Another alternative would be to data bind the Visibility attribute to the Title property and to use a converter to transform the Title (i.e., a String) into a Visibility. For example, the following XAML references a static resource called StringToVisibility; it's an instance of such a StringToVisibilityConverter, declared as a page resource.

<phone:PhoneApplicationPage.Resources>
    <local:StringToVisibilityConverter
        x:Key="StringToVisibility" />
</phone:PhoneApplicationPage.Resources>

<TextBlock Text="{Binding Title}" Visibility="{Binding Title, 
                  Converter={StaticResource StringToVisibility}}"/>

The StringToVisibilityConverter only has two methods; they're required to implement the IValueConverter interface needed for the converter to be used as part of a data binding expression.

In the following code, the Convert method has been implemented to transform input data (the value argument) into the corresponding targetType. The ConvertBack method hasn't been implemented for two reasons: 1) We're currently only using this to data bind to the Visibility property of the TextBlock, so it's unlikely we need it to respond to changes in the TextBlock (i.e., two-way data binding with a mode of TwoWay), and 2) In most cases, it wouldn't make sense to return a string based on whether the input data is Visibile or Collapsed.

public class StringToVisibilityConverter:IValueConverter
{
    public object Convert(object value, Type targetType, 
                          object parameter, CultureInfo culture)
    {
        var stringValue = value as string;
        return string.IsNullOrWhiteSpace(stringValue) ? 
                                         Visibility.Collapsed : Visibility.Visible;
    }

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

You might also have noticed that there are additional arguments to both the Convert and ConvertBack methods we haven't used. The targetType argument can be useful if you want to make your converter more dynamic and cater to more scenarios. If we wanted to use the StringToVisibilityConverter with a bool attribute (e.g., the IsEnabled attribute or the IsIndeterminate attribute of the ProgressBar), the converter can query the targetType in order to determine the return type. This is illustrated in the following code.

public object Convert(object value, Type targetType, 
                      object parameter, CultureInfo culture)
{
    var stringValue = value as string;
    var isVisible = !string.IsNullOrWhiteSpace(stringValue);
    if (targetType ==typeof(Visibility))
    {
        return isVisible ? Visibility.Visible : Visibility.Collapsed;
    }
    return isVisible;
}

As you develop your converter, you may want to vary the way it behaves according to where, or how, it's used within the layout. This is where the parameter argument can be used to customize the behavior of the converter. In the case of the StringToVisibilityConverter, there may be scenarios where you want to show an element, instead of hide it, when there's no property value. To do this, we can add a ConverterParameter attribute to the data binding expression in the XAML, as follows:

Visibility="{Binding Title, Converter={StaticResource StringToVisibility}, 
            ConverterParameter=invert}"

This attribute is passed into the Convert method as the parameter argument. It goes without saying that the StringToVisibilityConverter needs to be modified in order to react to different parameter values.

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    var stringValue = value as string;
    var isVisible = !string.IsNullOrWhiteSpace(stringValue);
    if((parameter as string)=="invert")
    {
        isVisible = !isVisible;
    }
    if (targetType ==typeof(Visibility))
    {
        return isVisible ? Visibility.Visible : Visibility.Collapsed;
    }
    return isVisible;
}

The final parameter in the Convert method is a reference to a CultureInfo instance, which can be used to tailor the conversion to be specific to the current locale.

Before wrapping up, it's important to note that there is a small performance overhead for using a converter, rather than simply exposing a property with the correct data type. For simple display-only pages with a dozen or so read-only elements, this overhead will be insignificant.

But for more complex pages, which may include a list of items, you'll be looking for every ounce of performance out of the application. An application with 1,000-plus rows, for instance, won't want the application to call the Convert method for every single row. In this case, exposing a TitleVisibility property on the Person might be a quicker alternative.

In this article you've seen an introduction into the use of value converter to transform the data binding value into the correct data type. Another example of a value converter you may want to build is the BoolToVisibilityConverter. As the name suggests, this converts a bool value into the corresponding Visibility enumeration value; this is particularly good for showing or hiding elements on the page based on some predicate in the object to which you're data binding.

About the Author

Nick Randolph runs Built to Roam, a consulting company that specializes in training, mentoring and assisting other companies build mobile applications. With a heritage in rich client applications for both the desktop and a variety of mobile platforms, Nick currently presents, writes and educates on the Windows Phone platform.

comments powered by Disqus

Featured

Subscribe on YouTube