Converters

When binding an entity object source to Silverlight 2 controls, it is often desirable to present the values in the target in a different format from the source. For example, when a date value is stored in a database, you almost always must format the value when you’re displaying it in a user interface. You might need to convert this value to an MM/DD/YYYY format to be displayed in a Silverlight user control. Another example might be a string property of an entity that represents a color, such as blue. You might intend to use this value as a Brush for a Silverlight 2 control. You must convert these types of values from their native format into a format that is appropriate. Type conversions are common and you can tackle them by creating a class that implements the IValueConverter interface.

IValueConverter

The IValueConverter interface exposes two methods that must be implemented. The Convert and ConvertBack methods handle converting a value to and from the target and source of a binding. The Convert method morphs the data on its way from the source to the target. The ConvertBack method morphs the data from the target and back to the source.

Using a converter requires the following steps. First, you must create a converter class that implements the IValueConverter interface. Next, you must implement both the Convert and ConvertBack methods. The Convert method converts the value from the source to the target. This conversion is required for all binding modes. The ConvertBack method is called in TwoWay binding when the value in the target is sent back to the source. If the binding mode is OneWay or OneTime, the value is never sent from the target back to the source, so the ConvertBack method is not used.

Once you have created the converter class and implemented the IValueConverter methods, you can apply the converter in an appropriate binding scenario. You must declare an instance of the converter as a resource in the XAML page in order to do this. Then you can set the Converter property in the binding syntax to use the converter class instance. For example, the following code snippet declares a converter class instance as a UserControl resource:

    <UserControl.Resources>
        <ListBindings:DateTimeConverter x:Key="myDateTimeConverter" />
    </UserControl.Resources>

The following applies this converter in a binding operation:

Text="{Binding Mode=OneWay, Path=DiscontinuedDate,
        Converter={StaticResource myDateTimeConverter}}"

Conversions

Figure 4-6 shows the ProductView Silverlight control with its Discontinued Date using the default DateTime format. You could convert this value to use a different format to display in the Silverlight control if it applies a class that implements the IValueConverter interface. The Product class also has a UnitPrice property, which is not displayed on the Silverlight control. The UnitPrice is stored as a decimal value, but it should be displayed as a currency value with exactly two decimal places. Once you have added the UnitPrice to the Silverlight control, along with the conversions, the data will be formatted properly for the user. Example 4-13, which appears in the following section, will build on the ProductView control by adding the UnitPrice property and using the converters for the DateTime and the Decimal values. You can find the code for this control, named ProductViewWithConverter.xaml, in the code for this chapter.

DateTime conversions

Example 4-13 shows the DateTimeConverter class that converts a DateTime value to a string value using a specific date format of MM/DD/YYYY. The Convert method is implemented and grabs the value parameter which represents the DateTime value that is being sent from the source to the target. The Convert method intercepts the DateTime value and converts it to a formatted string. The ConvertBack method is not implemented, because the date value will not be involved in a TwoWay binding operation in this example.

You can use the targetType parameter to make sure the binding is operating on the appropriate target type. For example, in this case the target should be a property that is looking for a string value. The targetType is especially valuable when converting a value to a specific property type, such as a Brush or an enumeration.

Example 4-13. DateTimeConverter

C#
public class DateTimeConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        DateTime theDate = (DateTime)value;
        string formattedDate = string.Empty;

        if (parameter == null)
            formattedDate = theDate.ToString(culture);
        else
            formattedDate = theDate.ToString(parameter as string, culture);

        return formattedDate;
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}
VB
Public Class DateTimeConverter
    Implements IValueConverter
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, _
            ByVal parameter As Object, ByVal culture As CultureInfo) As Object
        Dim theDate As DateTime = CDate(value)
        Dim formattedDate As String = String.Empty

        If parameter Is Nothing Then
            formattedDate = theDate.ToString(culture)
        Else
            formattedDate = theDate.ToString(TryCast(parameter, String), culture)
        End If

        Return formattedDate
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, _
            ByVal parameter As Object, ByVal culture As CultureInfo) As Object
        Throw New System.NotImplementedException()
    End Function
End Class

The following line adds an instance of the converter to the UserControl’s resource section:

<ListBindings:DateTimeConverter x:Key="myDateTimeConverter" />

The XAML for the lbDiscontinuedDate TextBlock is modified to include the converter in the binding operation. The resultant XAML for this TextBlock will look like the XAML snippet in Example 4-14.

Example 4-14. Using a converter in XAML

<TextBlock x:Name="lbDiscontinuedDate" Grid.Column="1" Grid.Row="8"
    Margin="10,5,10,5" HorizontalAlignment="Left" Height="13" Width="240"
    Style="{StaticResource TextBlockReadOnlyStyle}"
    Text="{Binding Mode=OneWay, Path=DiscontinuedDate,
        Converter={StaticResource myDateTimeConverter}}"
        VerticalAlignment="Center" />

Currency conversions

The Grid panel in Example 4-13 is adjusted to contain the new tbUnitPrice TextBox. The value must be converted from a decimal to a guaranteed two-decimal value string. The Convert method intercepts the decimal value on its way from the source to the target TextBox’s Text property. Because this TextBox is involved in a TwoWay binding operation, the ConvertBack method intercepts the value on its way back from the target to the source. The XAML snippet in Example 4-15 shows the tbUnitPrice TextBox code.

Example 4-15. Setting a ConverterParameter

<TextBox x:Name="tbUnitPrice" Grid.Column="1" Grid.Row="2"
    Margin="10,5,10,5" HorizontalAlignment="Left" Height="30" Width="240"
    Style="{StaticResource TextBoxStyle}"
    Text="{Binding Mode=TwoWay, Path=UnitPrice,
        Converter={StaticResource myCurrencyConverter}},
        ConverterParameter=C}"/>

Notice that a parameter is passed to the converter through the ConverterParameter property in the XAML. The ConverterParameter property allows XAML to influence how the converter class handles the conversion. In this case, the currency format is passed to the converter.

The following XAML snippet creates the instance of the CurrencyConverter class in the resource section of the UserControl:

<ListBindings:CurrencyConverter x:Key="myCurrencyConverter" />

The CurrencyConverter class code in Example 4-16 shows the simple conversion from the decimal value to the formatted string value in the Convert method. Once these changes are made, the ProductViewWithConverter control will display the values, as shown in Figure 4-7.

ProductViewWithConverter—using converters

Figure 4-7. ProductViewWithConverter—using converters

Example 4-16. CurrencyConverter

C#
public class CurrencyConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        decimal amount = System.Convert.ToDecimal(value);
        string c = amount.ToString(parameter as string, culture);
        return c;
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}
VB
Public Class CurrencyConverter
    Implements IValueConverter
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, _
            ByVal parameter As Object, ByVal culture As CultureInfo) As Object
        Dim amount As Decimal = System.Convert.ToDecimal(value)
        Dim c As String = amount.ToString(TryCast(parameter, String), culture)
        Return c
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, _
        ByVal parameter As Object, ByVal culture As CultureInfo) As Object
        Throw New System.NotImplementedException()
    End Function
End Class

This example shows how you can use converters to intercept and morph values on their way from a source to a target and vice versa. You can use converters to convert from any type of source value to any type of target value, as long as the conversion follows common-sense rules. For example, it would make sense in some cases to convert an enumeration value that represents a color to a Brush. However, it would not make sense to convert a DateTime value to a slider control’s value property. If you use converters appropriately, though, you can use them throughout an application to achieve consistent data conversion to and from bindings.

Get Data-Driven Services with Silverlight 2 now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.