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.
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}}"
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.
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" />
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.
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.