WPF Simplified Part 13: Value Converters

In WPF, when you data bind an element’s property to a data source, if the source property type and target property type don’t match you’ll need a value converter to hook them up correctly.

Consider the following data bound TextBlock,

    <TextBlock x:Name="MyText" Text="{Binding Name}" Foreground="{Binding DisplayColor}" />

and the code behind,

    this.MyText.DataContext = new { Name = "John", DisplayColor = "BlackSmoke" };

If you try out the code and XAML above you’ll see the following error in VisualStudio’s ‘Output’ window,

System.Windows.Data Error: 6 : ‘TargetDefaultValueConverter’ converter failed to convert value ‘BlackSmoke’ (type ‘String’); fallback value will be used, if available. BindingExpression:Path=DisplayColor; DataItem='<>f__AnonymousType0`2′ (HashCode=-850673272); target element is ‘TextBlock’ (Name=’MyText’); target property is ‘Foreground’ (type ‘Brush’) FormatException:’System.FormatException: Token is not valid.

The error is that TextBlock’s Foreground accepts a Brush type, but we bound the Foreground to a String type, hence the binding failed. What we need is a value converter that will convert a String type into a Brush type.

    [ValueConversion(typeof(string), typeof(Brush))]
    public class StringToBrushConverter : IValueConverter 
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if (value is string) {
                string source = value as string;
                if (source == "BlackSmoke") return new SolidColorBrush(Colors.DimGray);
            }

            // Default color
            return Colors.Black;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            // To keep it simple, no need to convert back 
            return null;
        }
    }

As you can see, we’ve hand coded how a String will convert to a Brush type for our application – when the string is “BlackSmoke” we’d like the Brush to be “DimGray”. Applying this converter in XAML is simple enough,

<Grid>
    <Grid.Resources>
        <local:StringToBrushConverter x:Key="StringToBrushConverter" />
    </Grid.Resources>
       <TextBlock x:Name="MyText" Text="{Binding Name}" 
       Foreground="{Binding DisplayColor, Converter={StaticResource StringToBrushConverter}}" />
</Grid>

Thus, even though the TextBlock’s Foreground is still bound to a String type, our converter will provide the required type (Brush) to the Foreground dependency property.

WPF also has some built-in value converters, in fact, it has a built in String to Brush converter! To see this, try the following XAML,

    <TextBlock x:Name="MyText" Text="{Binding Name}" Foreground="{Binding DisplayColor}" />

with the following code behind,

    this.MyText.DataContext = new { Name = "John", DisplayColor = "Red" }; 

The text displays in red because of WPF’s built in String to Brush converter – it recognized the string ‘Red’ and converted it to the corresponding BrushColors.Red. In fact the built-in converter will recognize any of the colors in System.Windows.Media.Colors as strings, and will convert them to their corresponding Brushes. The code probably does the equivalent of the following,

    if (source == "Red") return new SolidColorBrush(Colors.Red);
    if (source == "Yellow") return new SolidColorBrush(Colors.Yellow);

    // etc.

Instantiating the converter in XAML as a resource can be cumbersome, so there is another way to use value converters. By deriving from MarkupExtension, you can use the converter directly in XAML, without using StaticResource.

    [ValueConversion(typeof(string), typeof(Brush))]
    public class StringToBrushConverter : MarkupExtension, IValueConverter 
    {
        public override object ProvideValue(IServiceProvider serviceProvider) {
            return this;
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if (value is string) {
                string source = value as string;
                if (source == "BlackSmoke") return new SolidColorBrush(Colors.DimGray);
            }

            // Default color
            return Colors.Black;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            // To keep it simple, no need to convert back 
            return null;
        }
    }

and now you can use the converter like this,

    <TextBlock x:Name="MyText" Text="{Binding Name}" 
               Foreground="{Binding DisplayColor, Converter={local:StringToBrushConverter}}" />

Advertisements

About soumya chattopadhyay
I live and work in Seattle, WA. I work with Microsoft technologies, and I'm especially interested in C#.

4 Responses to WPF Simplified Part 13: Value Converters

  1. Pingback: WPF Simplified Series « I.Net

  2. Narendra says:

    Good Tricks which is never found anywhere else…

  3. Mr-H says:

    Thank you SOOO MUCH!!!! I was looking for an explanation on how to do this but i couldnt find any…. till i found this post. ThAnKs!

  4. dongx says:

    Nice simple example. Good enough. PS: I would like to see a example for convertback.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: