Data Binding with Value Converters

Keep your code intelligent and efficient

Silverlight 3 provides a flexible way to bind data to controls using a simple yet powerful syntax. Although you can control what data is bound to a control by changing the data before it's bound, there will be times when you need to massage the data at the user interface level so that it displays in a specific format. For example, you may bind a DateTime object to a TextBlock control and require that only the date is shown, as opposed to the date and time. In other situations, you may need to convert a Boolean property value into a Visibility enumeration value to show or hide a control. Silverlight contains several different value converters that can make adjustments, such as convert the name of a color into a SolidColorBrush.

I'll introduce you to the concept of value converters and explain how they can be created, referenced, and used in a Silverlight application. By using value converters properly, you can simplify the data binding process, reduce code, and ease future maintenance of your Silverlight applications.

Why We Need Value Converters

Data comes in all shapes and sizes, and sometimes the data you're working with needs to be changed because it's bound to a control in the user interface. Fortunately, Silverlight provides built-in functionality for modifying data as it goes into a control and even as it goes out of a control, back to the bound object. So why do you need value converters? Let's look at a simple example to get started.

Figure 1 shows several TextBlock controls that are bound to customer data. The birthday TextBlock displays the date, but also shows the default time of midnight since a valid time wasn't originally defined in the source data. While there may be times when you need the time to show, it's obviously not something normally shown for a birthday.

Figure 1: Default TextBlock display

By creating a value converter, you can control how the DateTime value is displayed and even apply different types of formats to the data when needed. Figure 2 shows how the data binding can be changed by adding a value converter into the mix. You can see that the time is no longer shown, as is standard with a birthday value.

Figure 2. TextBlock after using value converters

Creating a Value Converter

Creating a value converter is a surprisingly simple process in Silverlight. In fact, all of the shell code required can be generated automatically using Visual Studio 2008. To get started, you'll first need to create a class within a Silverlight application or class library project. Value converters rely upon an interface called IValueConverter, which is located in the System.Windows.Data namespace, so you'll need to add a reference to that namespace in your code. Once that's done, the value converter class can implement the IValueConverter interface.

IValueConverter defines two members, including Convert and ConvertBack. Convert is used to modify data as it's bound from the source object to the control. ConvertBack works the other way. As a user changes data in a control such as a TextBox, the data can be converted back to the original data type in the source object by using ConvertBack. Once IValueConverter is added to your class, you can right-click it in Visual Studio and select Implement Interface from the menu to automatically fill in the Convert and ConvertBack methods. If you're using Visual Basic, you can simply hit enter after the interface name to accomplish the same thing.

Both Convert and ConvertBack accept the same parameters, including the data being bound, the type of the data being bound, any parameter data passed in that can be used in the data conversion process, and the target culture that the entire process is running under (English, Spanish, French, etc.). Here's what the method signatures look like:

object Convert(object value, Type targetType,

object parameter, CultureInfo culture);
object ConvertBack(object value, Type targetType,

object parameter, CultureInfo culture);

In many situations, you only need to worry about the actual data being bound (the value parameter) and can use built-in .NET data conversion methods to get the job done. Other times, you may need to integrate a parameter into the process to allow more control over how the data is modified by the value converter. Figure 3 shows a simple value converter named DateConverter that can be used to convert DateTime values into various date and time formats.

Looking at the Convert method in Figure 3, you can see that it converts the value passed in into a DateTime object. It then uses the parameter value passed, as well as the language culture, to format the value being bound and return it. By allowing a parameter to be passed into the DateConverter class, it can be used to return several different types of date/time formats.

The ConvertBack method converts the value passed into a string and attempts to convert the string back into a DateTime object using the standard DateTime.TryParse method. If the value can't be converted, a value of DependencyProperty.UnsetValue is returned so that the target property isn't updated. It's important to note that any exceptions raised within custom value converter objects will trigger a runtime exception in Silverlight.

Using a Value Converter

To use a value converter, you'll need to first add a reference to the class's namespace and assembly and then define it within the resources section of either the current page/user control (in App.xaml or in a merged dictionary XAML file). If you'll be using a specific value converter throughout an application, it's recommended that you define it in the App.xaml file or within a merged resource dictionary file.

An example of defining a value converter namespace in a user control is shown next. Note that the value converter class is in the same project as the Silverlight application so no assembly reference is required.

(Note: Some code lines in text wrap to several lines because of space constraints.)

<UserControl x:Class="DataBinding.Page"

xmlns="http://schemas.microsoft.com/winfx/

2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:converter="clr-namespace:DataBinding"

> 

...

</UserControl>

Once the value converter namespace is defined, you can reference the class using XAML:

<UserControl.Resources>

<converter:DateConverter x:Key="DateConverter" />

</UserControl.Resources>

Looking at the previous code, you can see that the syntax is much like what you'd do in ASP.NET when defining user controls, although a key is defined instead of an id. The key can be used in any data binding expression to force data to be routed through the value converter object.
Once the value converter is defined in a resources section within the Silverlight application, you can use it within data binding expressions. This is done by using the Converter and ConverterParameter properties as shown next:

<TextBlock x:Name="tbBirthday"
Text="{Binding Birthday,Mode=OneWay,
Converter={StaticResource DateConverter},
ConverterParameter=d}"
/>

Notice that the Converter property references the DateConverter key defined earlier by using the StaticResource keyword. The type of date format to use when converting and formatting the data that's being bound is passed using the ConverterParameter property. In this case, the "d" parameter value tells the Convert method within the value converter object to only return a date string without the time. Other date/time format codes can be passed in using ConverterParameter as needed.

When a TwoWay binding is set up, both the Convert and ConvertBack methods will be called in the value converter object. Here's an example of using DateConverter with a TwoWay binding:

<TextBox x:Name="txtBirthday"
Text="{Binding Birthday, Mode=TwoWay,
Converter={StaticResource DateConverter},
ConverterParameter=d}" />

Examples of Value Converters

I find myself using value converters quite often in Silverlight applications, given that they can minimize the amount of custom code that has to be written and simplify maintenance down the road. Here are a few of the converters I use in projects.

BoolToVisibilityConverter. The BoolToVisibilityConverter is a value converter that's used to show and hide different objects within a page or user control. The object that UI controls are bound to (oftentimes referred to as the ViewModel class) can define Boolean properties such as IsButtonVisible. The BoolToVisibilityConverter handles converting true and false property values into Visibility.Visible and Visibility.Collapsed, as appropriate. Figure 4 shows an example of this converter.

NullToVisibilityConverter. The NullToVisibilityConverter handles converting null values into Visibility enumeration members. It's useful when you bind a property to a control and the property can be null. Figure 5 shows the NullToVisibilityConverter.

ListCountVisibilityConverter. The ListCountVisibilityConverter handles showing or hiding item controls such as ListBox when a specific number of items are bound to the ItemsSource property. For example, if only one item is available in a collection you may not want a ListBox to show while two or more items should cause the control to be shown. This value converter allows you to pass in the cut-off number that determines when to show or hide a control and the Covert method handles returning the proper Visibility enumeration member. Figure 6 shows the code for the ListCountVisibilityConverter.

Code Intelligently and Efficiently

You've seen how value converters can manipulate data as it goes in and out of controls. By using value converters, you can minimize the amount of custom code that would normally have to be written to change your data. They're an important addition to your arsenal as a Silverlight developer.

Code accompanying this article is available for download.

Figure 3: DateConverter value converter

using System;

using System.Windows.Data;

namespace DataBinding

{

public class DateConverter : IValueConverter

{

#region IValueConverter Members

//Called when binding from an object property to a control property

public object Convert(object value, Type targetType,

object parameter, System.Globalization.CultureInfo culture)

{

DateTime dt = (DateTime)value;

return dt.ToString((string)parameter, culture);

}

//Called with two-way data binding as value is pulled out of control

//and put back into the property

public object ConvertBack(object value, Type targetType,

object parameter, System.Globalization.CultureInfo culture)

{

string val = (string)value;

DateTime outDate;

if (DateTime.TryParse(val, culture, DateTimeStyles.None,

out outDate))

{

return outDate;

}

return DependencyProperty.UnsetValue;

}

#endregion

}

}

Figure 4: BoolToVisibilityConverter value converter

public class BoolToVisibilityConverter : IValueConverter

{

#region IValueConverter Members

public object Convert(object value, Type targetType,

object parameter, System.Globalization.CultureInfo culture)

{

if (parameter == null)

{

return ((bool)value == true) ? Visibility.Visible :

Visibility.Collapsed;

}

else if (parameter.ToString() == "Inverse")

{

return ((bool)value == true) ? Visibility.Collapsed :

Visibility.Visible;

}

return false;

}

public object ConvertBack(object value, Type targetType,

object parameter, System.Globalization.CultureInfo culture)

{

throw new NotImplementedException();

}

#endregion

}

Figure 5: NullToVisibilityConverter value converter

public class NullToVisibilityConverter : IValueConverter

{

#region IValueConverter Members

public object Convert(object value, Type targetType,

object parameter, System.Globalization.CultureInfo culture)

{

if (parameter == null) //Not invert parameter passed

{

return (value == null) ? Visibility.Collapsed :

Visibility.Visible;

}

else if (parameter.ToString() == "Inverse")

{

return (value == null) ? Visibility.Visible :

Visibility.Collapsed;

}

return Visibility.Collapsed;

}

public object ConvertBack(object value, Type targetType,

object parameter, System.Globalization.CultureInfo culture)

{

throw new NotImplementedException();

}

#endregion

}

Figure 6: ListCountVisibilityConverter value converter

public class ListCountVisibilityConverter : IValueConverter

{

#region IValueConverter Members

public object Convert(object value, Type targetType,

object parameter, System.Globalization.CultureInfo culture)

{

if (value != null)

{

IList list = value as IList;

if (list != null)

{

int minCount = int.Parse(parameter.ToString());

return (list.Count > minCount) ? Visibility.Visible :

Visibility.Collapsed;

}

}

return Visibility.Collapsed;

}

public object ConvertBack(object value, Type targetType,

object parameter, System.Globalization.CultureInfo culture)

{

throw new NotImplementedException();

}

#endregion

}

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish