Mobile Corner
Data Binding 101: Expression Syntax
Data-binding parameters that you can use when wiring up the contents of your Windows Phone application.
- By Nick Randolph
- 10/29/2012
In the first and second articles in this series, I covered the basics of data binding and the use of value converters . In Part 3, I'm going to highlight a couple of other aspects you should be aware of related to binding syntax.
Source
First up is the Source parameter. Most data-binding expressions are relative to the DataContext of the current element. If there is no DataContext explicitly set on an element, it's inherited from its parent element (and so forth, up the hierarchy). However, in some cases, you don’t want to data bind to the current DataContext; instead, the Source property allows you to change the source object for the data-binding expression. In the following XAML, the DataContext attribute on the page is being data bound to the Main property on an application static resource, Locator.
<Application x:Class="DataBinding101.App"
...
xmlns:local="clr-namespace:DataBinding101">
<Application.Resources>
<local:ViewModelLocator x:Key="Locator" />
</Application.Resources>
...
</Application>
<phone:PhoneApplicationPage
x:Class="DataBinding101.MainPage"
...
DataContext="{Binding Main, Source={StaticResource Locator}}">
This example is a form of service locator pattern where by the page reaches out to the static resource, Locator, whose sole purpose is the creation and management of view models. The Main property will retrieve an instance of the view model appropriate for this page, illustrated in the following code snippet:
public class ViewModelLocator
{
public MainViewModel Main
{
get
{
return new MainViewModel();
}
}
}
ElementName
The ElementName attribute can be used in a similar fashion to the Source attribute to change the source of the data-binding expression. However, the ElementName attribute is used to reference another visual element. For example, in the following code, the Background attribute of the Border is data bound to the Foreground attribute of the element with name TB_Name:
<TextBlock x:Name="TB_Name" Text="{Binding Name}" />
<Border Background="{Binding Foreground,ElementName=TB_Name}" Width="50" Height="50" />
This can be particularly useful when you’re working in the context of an item template for a list. In this case, your data-binding expressions are typically in relation to the item within the list. You can use the ElementName attribute to escape out to data bind to an attribute on an element elsewhere on the page.
StringFormat
Occasionally, when you want to display a value, you may wish to append a prefix, suffix or both. In the following XAML, the prefix "My Name is" has been inserted before the data bound value, and a full stop afterwards.
<TextBlock Text="{Binding Name,StringFormat='My Name is \{0\}.'}" />
The alternative is to use a number of Run elements, which gets quite messy.
<TextBlock> <Run Text="My Name is "/><Run Text="{Binding Name}"/><Run Text="."/></TextBlock>
ValidatesOnDataErrors
The ValidatesOnDataErrors attribute is useful in order to report validation errors when collecting data (i.e. with two-way data binding). In the following XAML, the Text attribute of the TextBox is data bound to the Name property using two-way data binding:
<TextBox Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True}"
Style="{StaticResource DataErrorStyle}" />
By enabling the ValidatesOnDataErrors attribute, the data entered into the TextBox is validated when it's applied to the underlying data source, and any errors are reported to the user. Well, that’s the theory anyhow! Unfortunately, you have to do a couple of extra steps in order to get this to work.
First, the underlying data source has to implement the IDataError interface, which includes two properties for reporting validation errors. A basic implementation to the Person class is shown in Listing 1.
If you were to run this example and set a break point, if there was no text in the TextBlock, the message "Need to specify name" would be returned as an error. However, you wouldn’t see this displayed on the page because the default TextBox style doesn’t alter its appearance if there are validation errors. This can be fixed by adjusting the TextBox template. (In Microsoft Expression Blend, right-click on the TextBox and select Edit Template > Edit a Copy.) In the XAML in Listing 2, you’ll notice that an extra border has been added around the content, which is colored red for both the InvalidUnfocused and InvalidFocused states. (Note that this Style was referenced in the XAML for the TextBox earlier in this section.)
With this modified TextBox Style, and the IDataError implementation, if the user doesn’t enter a value into the TextBox, he will see a red border around the TextBox indicating a validation error. This is illustrated in Figure 1.
|
Figure 1. Validation States |
One limitation of this implementation is that the validation doesn’t occur until the user taps away from the TextBox. At this point, the new value is applied to the underlying data source and the validation occurs. If you want to provide immediate feedback to the user, you can intercept the TextChanged event on the TextBox and force an update to the data binding.
<TextBox
Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=Explicit}"
Style="{StaticResource DataErrorStyle}"
TextChanged="NameTextChanged" />
private void NameTextChanged(object sender, TextChangedEventArgs e)
{
var binding = (sender as FrameworkElement).GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();
}
Note that you’ve added the UpdateSourceTrigger parameter to the data-binding expression. You're explicitly calling the UpdateSource method on the data-binding expression for each change to the text in the TextBox, so it's unnecessary for the binding engine to update the source as well. Hence, you’ve set this parameter to Explicit.
I've covered a number of the data-binding parameters that you can use when wiring up the contents of your application. It’s important to remember that the more complex you make your data binding, the slower your application may perform. Of course, it’s always a trade off between the convenience offered by the data-binding expression—particularly, the support Expression Blend offers—and the speed and performance of the application.
About the Author
Nick Randolph runs Built to Roam, a consulting company that specializes in training, mentoring and assisting other companies build mobile applications. With a heritage in rich client applications for both the desktop and a variety of mobile platforms, Nick currently presents, writes and educates on the Windows Phone platform.