UWP Basics
- 10/11/2018
Using Converters
Data binding provides a convenient mechanism for displaying data and collecting user input. As you just saw, if you data bind values from the source properties, they are automatically presented in the target properties of visual controls. Sometimes, however, you might want to have more control over how your data is presented. For instance, you might want to supplement data with some culture-specific symbols or arbitrarily format your data before presentation. Fortunately, UWP provides a dedicated tool, or converter. You use it to alter data being displayed with data binding.
To create the converter, you begin by implementing a class that conforms to Windows.UI.Xaml.Data.IValueInterface. This interface declares two methods, Convert and ConvertBack, which you implement in your converter class. These methods are invoked whenever your binding needs to be updated. Convert enables you to modify the value before it is displayed in the UI or, more generally, when the target property is updated due to changes in the source. In contrast, ConvertBack is invoked whenever the binding update is triggered by the target property—for example, when you type a string in the text box.
To give you an example, let’s supplement the UWP.Basics project with a Converters folder. Follow these steps:
In Solution Explorer, right-click UWP.Basics and choose Add/New Folder from the menu that appears.
Right-click the Converters folder, choose Add, and select New Class to create new code file.
In the Add New Item window, name the new class ToUpperConverter.cs.
Implement the new file as shown in Listing 4-9, which presents a sample definition of the converter. ToUpperConverter implements the Convert method to modify the source string to capitalize it. Note that the back conversion does not modify the value.
LISTING 4-9 A full definition of ToUpperConverter
public class ToUpperConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { var strValue = value as string; if (!string.IsNullOrEmpty(strValue)) { strValue = strValue.ToUpper(); } return strValue; } public object ConvertBack(object value, Type targetType, object parameter, string language) { return value; } }
To associate a converter with the binding, you first declare that converter in the resource dictionary accessed by the particular view. Hence, you typically declare converters in the application-scoped resource collection defined in the App.xaml file. (See the bolded statements in Listing 4-10.)
LISTING 4-10 Declaring a converter in the application-scoped resources
<Application x:Class="UWP.Basics.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converters="using:UWP.Basics.Converters" RequestedTheme="Light"> <Application.Resources> <converters:ToUpperConverter x:Key="ToUpperConverter" /> </Application.Resources> </Application>
After declaring a converter, you apply it to the binding with the Converter attribute of the {x:Bind} markup extension:
<TextBox Text="{x:Bind ViewModel.LastName, Mode=TwoWay, Converter={StaticResource ToUpperConverter}}" Grid.Row="1" Grid.Column="1" />
If you re-run an app that has been modified in this way, the value from the Last Name text box will be capitalized when the app is executed. (See Figure 4-5.) However, you will quickly see that the text is not capitalized when you modify the text from the Last Name text box. This is because the data-binding mechanism is not notified about changes made to the ViewModel properties. As a result, data binding does not update any properties and thus does not invoke the Convert method of the ToUpperConverter class instance.
FIGURE 4-5 Using a converter to alter the string being displayed in the Last Name text box.
To confirm this behavior, supplement the XAML declaration of the Change button by adding a handler to the Click event (see Listing 4-11). Then implement this handler according to Listing 4-12.
LISTING 4-11 Button declaration
<Button Content="Change" Grid.Row="3" Grid.Column="1" Click="Button_Click" />
LISTING 4-12 Updating a viewmodel
private void Button_Click(object sender, RoutedEventArgs e) { ViewModel.FirstName = "Nick"; ViewModel.LastName = "Wilde"; ViewModel.Age = 27; }
Having introduced these changes, you would expect that the personal data would be modified when the user clicked the Change button, and that these changes would be reflected in the UI. However, although public members of the ViewModel are changed, values displayed in text boxes are not. This is because the data binding does not know about these updates. To solve this problem, you need to notify the binding about underlying changes to the source properties. UWP natively provides a mechanism for such notifications, based on the System.ComponentModel.INotifyPropertyChanged interface.