Mobile Corner

Data Binding 101: Expression Syntax

Data-binding parameters that you can use when wiring up the contents of your Windows Phone application.

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.

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube