The Value of Converters

December 1, 2009 at 5:55 AMmgordon

Over time, I’ve discovered more and more uses for value converters in my Silverlight and WPF applications.  In this post, we’ll look at what they are and some scenarios where they are useful.

What are value converters

If you’ve done any development in Silverlight or WPF, you know that when using these technologies, the user interface is specified in XAML, a dialect of XML.  Since we are using XML, or essentially strings, to defined our GUI the XAML parser needs to know how to turn the strings we specify into types.  For example, when we specify at attribute on a control such as IsEnabled=”True”, there needs to be away for the string “True” to be understood as a Boolean value.  When we say Background=”Black”, the string “Black” needs to be understood as Brush of color #FF000000. 

Both of these examples are common occurrences so there are built in converters that take care of these.  However, in our applications, there are likely going to be cases where we need to specify a value that the XAML parser has no idea how to interpret.  For these cases, we can create our own value converter to specify what type a string needs to be converted to.

An Example

Suppose you have a DataGrid in your UI that contains orders.  Each of these orders has a status property and you want to display an icon in each row that depicts the status of the order.  The grid is bound to a collection in the ViewModel.  How do you achieve this?

 

First, you’d need to define the column for the icon.  Perhaps, something like below.

<data:DataGridTemplateColumn Header="Status" CellTemplate="{StaticResource statusTemplate}" 
                                            IsReadOnly="True" Width="50" 
                                            CanUserSort="False"/>

 

Here, we specify the column’s layout in a template, statusTemplate.

<DataTemplate x:Key="stausTemplate">
    <Image Height="32" Width="32" Source="{Binding StatusCode, Converter={StaticResource statusToImage}, 
        Mode=OneWay}"/>
</DataTemplate>

 

In our template, we’re specifying an Image element, but binding its Source property to the status code.  Somehow, that status code has to be converted into a reference to an image file.  To handle that conversion, we specify a converter in our binding.  Let’s look at how to implement that converter.

To start, we need to create a new class and have it implement the interface IValueConverter.  Our class would look like this.

public class StatusToImageConverter : IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

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

        #endregion
    }

 

Implementing the IValueConverter interface requires us to implement two methods, Convert and ConvertBack.  The Convert method will be called to convert the original value to the desired value.  In our example, this method will be responsible for converting the status code to and image reference.  The ConvertBack method, does just the opposite.  If the converter is used in a TwoWay binding, the ConvertBack method will be called to convert a value specified back into a value of the original type.  In other words, if in our example the user were able to select an image, that image would be converted back into a status code before being pushed back into the order.

In our case, we’re only interested in using the converter in a OneWay binding, so we can leave the ConvertBack method un-implemented.  The finished class might look like the below.

public class StatusToImageConverter : IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture)
        {
            char statusCode = value.ToString()[0];

            switch (statusCode)
            {
                case 'A':
                    return "/Images/active.png";
                case 'W':
                    return "/images/working.png";
                case 'F':
                    return "/images/filled.png";
                case 'P':
                    return "/Images/paid.png";
            }

            return null;
        }

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

        #endregion
    }

 

With the converter built, we just need to reference it in our XAML as a resource.

<converters:StatusToImageConverter x:Key="statusToImage"/>

 

Other Uses

What if in our grid, we also have a column that contains a dropdown containing the shipper that we will be using to ship our order.  The ItemsSource for the dropdown is bound to a collection of Shipper objects and its SelectedValue property is bound to a ShipperId.  That shipperId needs to be converted into a Shipper object in order for the binding to work.  Using what we know about value converters, we can create a converter that takes the id and looks up the corresponding object in a list.

Converters are incredibly flexible and powerful allowing you to inject logic into your UI easily.     

Posted in: Silverlight | WPF

Tags: ,