Value Conversion

In Example 6-17, we've bound the foreground brush of the Birthday button to whatever the foreground brush is for the age text box, but our text box never changes color, so neither will the Birthday button. However, we might decide that anyone over age 25 is hot, so should be marked in the UI as red.* When someone ages at the click of the Birthday button, we want to keep the UI up-to-date, which means we've got ourselves a perfect candidate for data binding—something along the lines of Example 6-18.

Example 6-18. Binding to a non-Text property

<!-- Windowl.xaml --> <Window ...> <Grid>

<TextBox Text="{Binding Path=Age}" Foreground="{Binding Path=Age, ...}"

In Example 6-18, we've bound the age text box's Text property to the Person object's Age property, as we've already seen, but we're also binding the Foreground property of the text box to the same property on the Person object. As Tom's age changes, we want to update the foreground color of the age text box. However, because the Age is of type Int32 and Foreground is of type Brush, a mapping from Int32 to Brush needs to be applied to the data binding from Age to Foreground. That's the job of a value converter.

A value converter (or just "converter" for short) is an implementation of the IValueConverter interface, which contains two methods: Convert and ConvertBack.

* Or, anyone over 25 is in more danger of dying and red means "danger"—whichever makes you more likely to recommend this book to your friends...

The Convert method is called when converting from the source data to the target UI data (e.g., from Int32 to Brush). The ConvertBack method is called to convert back from the UI data to the source data. In both cases, the current value and the type wanted for the converted data are passed to the method.

To convert an Age Int32 into a Foreground Brush, we can implement whatever mapping in the Convert function we feel comfortable with (see Example 6-19).

Example 6-19. A simple value converter

[ValueConversion(/*sourceType*/ typeof(int), /*targetType*/ typeof(Brush))] public class AgeToForegroundConverter : IValueConverter {

// Called when converting the Age to a Foreground brush public object Convert(object value, Type targetType, ...) {

int age = int.Parse(value.ToString());

return (age > 25 ? Brushes.Red : Brushes.Black);

public object ConvertBack(object value, Type targetType, ...) {

// Should not be called in our example throw new NotImplementedException();

In Example 6-19, in addition to deriving from IValueConverter, we've also applied the optional ValueConversion attribute. The ValueConversion attribute is useful for documenting the expected source and target types for developers and tools, but it is not enforced by WPF, so don't expect it to catch values that don't match the source or target types. The part that is required for our example is the implementation of Convert, where we hand out the brush that's appropriate for the age being displayed. Because we haven't provided any facility to change the Foreground brush being used to display the age, there's no reason to do anything useful in the ConvertBack method—it won't be called.

I chose the name AgeToForegroundConverter because I have specific semantics I'm building into my converter class that go above simply converting an Int32 to a Brush. Even though this converter could be plugged in anywhere that converted an Int32 to a Brush, I might have very different requirements for a HeightToBackgroundConverter, for example.

Once you've got a converter class, it's easy to create an instance of one in the XAML, just like we've been doing with our Person object (see Example 6-20).

Example 6-20. Binding with a value converter <!-- Windowl.xaml -->

<Window ... xmlns:local="clr-namespace:WithBinding"> <Window.Resources> <local:Person x:Key="Tom" ... />

<local:AgeToForegroundConverter x:Key="ageConverter" />

</Window.Resources>

<Grid DataContext="{StaticResource Tom}">

<TextBox Text="{Binding Path=Age}" Foreground=" {Binding Path=Age,

Converter={StaticResource ageConverter}}" ... />

Foreground="{Binding Path=Foreground, ElementName=ageTextBox}"

>Birthday</Button> </Grid> </Window>

In Example 6-20, once we have a named converter object in our XAML, we establish it as the converter between the Age property and the Foreground brush by setting the Converter property of the binding object. Figure 6-10 shows the result of our conversion.

Figure 6-10. A value converter in action (Color Plate 3)

In Figure 6-10, notice that as Tom's age increases past the threshold, the converter switches the foreground brush from black to red. This change happens when the Age property changes. Because WPF detects the change, you do not need any explicit code to force the color change, just as with any other kind of data binding. Notice also that the foreground color of the Birthday button matches the age text box's color, because we're using element binding to keep them in sync.

Value Conversion Versus Type Conversion

You may have noticed that until we decided to bring brushes into the mix, we didn't need value converters at all. For example, with the Person class's Age property in an Int32, we didn't have to use a value converter even though the TextBox class's Text property is of type String. This works because the Binding class uses the type converter support that's been built into .NET since Version 1.0. Type converters work on a type basis (i.e., there's a type converter that knows how to convert from integers to strings and back [and there are many more type converters as well]). This works because there is a reasonable general-purpose way to convert strings to integers (and vice versa). On the other hand, a value converter works on an application-specific basis. Although there is no built-in general-purpose conversion from integers to brushes, we can define an application-specific conversion to handle a certain kind of integer (e.g., ages, in our example) to brushes and apply that on a case-by-case basis.

Was this article helpful?

0 0
Project Management Made Easy

Project Management Made Easy

What you need to know about… Project Management Made Easy! Project management consists of more than just a large building project and can encompass small projects as well. No matter what the size of your project, you need to have some sort of project management. How you manage your project has everything to do with its outcome.

Get My Free Ebook


Post a comment