Udostępnij za pośrednictwem


IValueConverter in WPF data binding

One of the handy things that you can do with data binding in WPF is that you convert the data as you pull it from the data source. The mechanism for this is the IValueConverter interface.
 
Let's say that you have a list of numbers representing positions in a race, and you want to display this list with the appropriate positional text (for example, 1 is 1st, 2 is 2nd, 3 is 3rd, etc). Rather than save your data in this form (which would not be convenient at all) you could leave the data as an int in the data source, and write a value converter to convert the integer into the appropriate string. This has many benefits - for example, if the UI is being virtualized, then only the items that have been created will be converted. And if the position changes WPF takes care of updating the string.
 
The first step is to make a class deriving from IValueConverter. We will call our class PositionConverter. There are two interface members - one of them to convert to the target type, and one of them to convert back. We don't need to convert back, so we just need to implement ConvertTo:

public class PositionConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            if (value != null)

            {

                int number = (int)value;

                string numberText = number.ToString();

                string positionText;

                if (number >= 10 && numberText[numberText.Length - 2] == '1')

                {

                    // teen numbers always end in 'th'

                    positionText = "th";

                }

                else

                {

                    switch (numberText[numberText.Length - 1])

                    {

                        case '1':

                            positionText = "st";

                            break;

                        case '2':

                            positionText = "nd";

                            break;

                        case '3':

                            positionText = "rd";

                            break;

                        default:

                            positionText = "th";

                            break;

                    }

                }

                return (numberText + positionText);

            }

            return string.Empty;

        }

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

        {

            throw new Exception("The method or operation is not implemented.");

        }

    }

To use the converter we can create one in the resources section of the window, and refer to it as a static resource in the binding statement:

<Window x:Class="ValueConverterDemo.Window1"

  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

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

  xmlns:local="clr-namespace:ValueConverterDemo"

  Title="ValueConverterDemo"

  Height="300"

  Width="300">

  <Window.Resources>

    <local:PositionConverter x:Key="PositionConverter" />

  </Window.Resources>

  <ListBox Name="numberBox">

    <ListBox.ItemTemplate>

      <DataTemplate>

        <TextBlock Text="{Binding Converter={StaticResource PositionConverter}}" />

      </DataTemplate>

    </ListBox.ItemTemplate>

  </ListBox>

</Window>

Now the numbers show up with positional text in them (45 becomes 45th, for example).

Value converters are very useful tools for letting you use the power of data binding. You can even pass parameters to them, so that you can combine data in the value converter.

Next up I show what ConvertBack is used for.

Comments

  • Anonymous
    February 02, 2007
    The comment has been removed
  • Anonymous
    September 09, 2007
    PingBack from http://wangmo.wordpress.com/2007/09/09/how-to-use-valueconverter-in-listbox/
  • Anonymous
    May 03, 2008
    PingBack from http://www.redmountainsw.com/wordpress/archives/rich-metadata-mediated-ui-development
  • Anonymous
    May 29, 2008
    This is great, I'm trying to add something like this to generic.xaml in Themes subdirectory as I am working on a custom control.Only problem is: how do I add the Windows.Resources section to that? Or do I add it to the window(s) hosting the control?
  • Anonymous
    July 14, 2008
    ZiggyShort -You don't need to add the converter to the Window.Resources. You just need the converter to be in a place visible to the binding expression that you use it in.
  • Anonymous
    September 01, 2008
    Is there an easier way of doing this for trivial cases?For example, if you had a Label binding to a string property and all you wanted to do was perform a .ToLower().Can we do this through fancy binding syntax or markup extensions? It seems creating a new Converter class for trivial cases is a bit overkill.