Data binding overview (XAML)

Applies to Windows and Windows Phone

Data binding provides a simple way for Windows Runtime apps using C++, C#, or Visual Basic to display and interact with data. The way data is displayed is separated from the management of the data. A connection, or binding, between the UI and a data object allows data to flow between the two. When a binding is established and the data changes, the UI elements that are bound to the data can display changes automatically. Similarly, changes made by the user in a UI element can be saved in the data object. For example, if the user edits the value in a TextBox, the underlying data value is automatically updated to reflect that change.

Some common binding scenarios include binding a ListBox to a list of headlines or an Image to the current user's photo.

This topic describes data binding features in detail. For a quick introduction to the concepts, see Quickstart: Data binding to controls.

Code samples: This topic uses simple code examples and excerpts from samples to illustrate basic data binding concepts. For complete samples, see:

For an end-to-end sample that uses data binding extensively, see the Reversi sample app. For more info, see Reversi, a Windows Store game in XAML, C#, and C++ and the data binding section of Learn how the Reversi sample uses Windows Store app features.

For additional C++ examples, see Create an app using C++.

Roadmap: How does this topic relate to others? See:

Connecting UI elements with data

Every binding includes:

  • A binding source, which is an object with data that you want to render.
  • A binding target, which is a DependencyProperty of a FrameworkElement for rendering the data.
  • A Binding object, which moves the data between the source and target, and can reformat it using an optional value converter.

The source can be:

  • Any common language runtime (CLR) object, including the target element itself or other UI elements. If the target is in a data template, the source can be the UI element to which the template is applied. Classes that you define in C# and Visual Basic produce CLR objects, so they are bindable by default.
  • Any Windows Runtime object of a type that has a BindableAttribute or implements ICustomPropertyProvider. Classes that you define in C++ produce Windows Runtime objects, so they require one of these approaches to be bindable.

The target can be any DependencyProperty of a FrameworkElement.

The binding engine gets information from the Binding object about the following:

  • The source and target objects.
  • The direction of the data flow. You specify the direction by setting the Binding.Mode property.
  • The value converter, if one is present. You specify a value converter by setting the Converter property to an instance of a class that implements IValueConverter.
  • Other settings, such as FallbackValue and TargetNullValue. See the Binding class for the full list of properties.

For example, the Foreground property of a TextBox can be bound to a SolidColorBrush so that the color of the text can change based on the data. In this scenario, the Foreground property is the target, and the SolidColorBrush object is the source for the binding.

The following example shows how to bind the Foreground color of a TextBox to a SolidColorBrush. The binding source is a property of the MyColors class, which is described later in this topic.



<TextBox x:Name="MyTextBox" Text="Text" Foreground="{Binding Brush1}"/>




// Create an instance of the MyColors class 
// that implements INotifyPropertyChanged.
MyColors textcolor = new MyColors();

// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);

// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;


Note  This example uses the XAML attribute syntax to create the binding. You could also use the object element syntax to create the binding in XAML. For more information, see XAML overview.

The binding is created in XAML by using the {Binding ...} syntax. The source is set in code by setting the DataContext property for the TextBox.

Data context is inherited. If you set the data context on a parent element, its children will use the same data context. A child element can override this behavior by setting the Source property on its binding object, or by setting its DataContext. This override then applies to the children of the child element.

Setting the data context is useful when you want to have multiple bindings that use the same source. To set the source for a single binding, set the Source property on the Binding object.

You can also use the ElementName property or the RelativeSource property to specify the binding source. The ElementName property is useful when you are binding to other elements in your app, such as when you are using a slider to adjust the width of a button. The RelativeSource property is useful when the binding is specified in a ControlTemplate. For more information, see Binding markup extension and RelativeSource markup extension.

You can bind to a property of the source object by setting the Binding.Path property. The Path property supports a variety of syntax options for binding to nested properties, attached properties, and integer and string indexers. For more info, see Property-path syntax. Binding to string indexers gives you the effect of binding to dynamic properties without having to implement ICustomPropertyProvider.

If you bind a text control to a value that is not a string, the data binding engine will convert the value to a string. If the value is a reference type, the data binding engine will retrieve the string value by calling ICustomPropertyProvider.GetStringRepresentation or IStringable.ToString if available, and will otherwise call Object.ToString. Note, however, that the binding engine will ignore any ToString implementation that hides the base-class implementation. Subclass implementations should override the base class ToString method instead. Similarly, in unmanaged languages, all managed objects appear to implement ICustomPropertyProvider and IStringable. However, all calls to GetStringRepresentation and IStringable.ToString are routed to Object.ToString or an override of that method, and never to a new ToString implementation that hides the base-class implementation.

Altogether, the preceding example causes the binding engine to create a binding, which is a one-way binding by default. It connects the Foreground property of the TextBox to the Brush1 property of the textcolor object.

Creating bindings in code

You can also connect UI elements to data using procedural code instead of XAML. To do this, create a new Binding object, set the appropriate properties, then call FrameworkElement.SetBinding or BindingOperations.SetBinding. Creating bindings programmatically is useful when you want to choose the binding property values at run time or share a single binding among multiple controls. Note, however, that you cannot change the binding property values after you call SetBinding.

The following example shows how to implement the previous binding in code.



<TextBox x:Name="MyTextBox" Text="Text"/>




// Create an instance of the MyColors class 
// that implements INotifyPropertyChanged.
MyColors textcolor = new MyColors();

// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);

// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;

// Create the binding and associate it with the text box.
Binding binding = new Binding() { Path = new PropertyPath("Brush1") };
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding);


Direction of the data flow

Each binding has a Mode property, which determines how and when the data flows. Windows Runtime apps using C++, C#, or Visual Basic can use three types of bindings:

  • OneTime bindings update the target with the source data when the binding is created.
  • OneWay bindings update the target with the source data when the binding is created, and any time the data changes. This is the default mode.
  • TwoWay bindings update both the target and the source when either changes. One exception to this behavior is that changes to TextBox.Text are not sent to a bound source after every user keystroke unless Binding.UpdateSourceTrigger is set to PropertyChanged. By default, the changes are sent only when the TextBox loses focus.

You can change the behavior of TwoWay bindings so that values are not copied to the source automatically, but only at times of your choosing. To do this, set the Binding.UpdateSourceTrigger property to Explicit. You can then call GetBindingExpression on the target to get a BindingExpression object, and then call BindingExpression.UpdateSource to programmatically update the data source.

Change notification

For changes to the source object to propagate to the target, the source must implement the INotifyPropertyChanged interface. INotifyPropertyChanged has the PropertyChanged event. This event tells the binding engine that the source has changed so that the binding engine can update the target value. For C# or Microsoft Visual Basic, you implement System.ComponentModel.INotifyPropertyChanged. For Visual C++ component extensions (C++/CX), you implement Windows::UI::Xaml::Data::INotifyPropertyChanged.

In this example, the MyColors class implements the INotifyPropertyChanged interface for OneWay binding.



// Create a class that implements INotifyPropertyChanged.
public class MyColors : INotifyPropertyChanged
{
    private SolidColorBrush _Brush1;

    // Declare the PropertyChanged event.
    public event PropertyChangedEventHandler PropertyChanged;

    // Create the property that will be the source of the binding.
    public SolidColorBrush Brush1
    {
        get { return _Brush1; }
        set
        {
            _Brush1 = value;
            // Call NotifyPropertyChanged when the source property 
            // is updated.
            NotifyPropertyChanged("Brush1");
        }
    }

    // NotifyPropertyChanged will fire the PropertyChanged event, 
    // passing the source property that is being updated.
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, 
                new PropertyChangedEventArgs(propertyName));
        }
    }
}


You can fire the PropertyChanged event to indicate that all non-indexer properties on the object have changed by using a PropertyChangedEventArgs.PropertyName value of String.Empty. Note that you cannot use null (Nothing in Visual Basic) for this, like you can in Windows Presentation Foundation (WPF) and Microsoft Silverlight.

Note  For C# or Visual Basic, you use System.ComponentModel.PropertyChangedEventArgs. For C++/CX, you use Windows::UI::Xaml::Data::PropertyChangedEventArgs.

You can also use change notification with indexer properties. You can fire the PropertyChanged event to indicate that indexer properties on the object have changed by using a PropertyChangedEventArgs.PropertyName value of "Item[indexer]" for specific indexers (where indexer is the index value), or a value of "Item[]" for all indexers.

Binding to collections

A binding source object can be treated either as a single object whose properties contain data, or as a collection of objects. For example, you might want to display a list of items, such as monthly credit card bills. To do this, use an ItemsControl and use a DataTemplate to display each item in a collection.



<Grid.Resources>

  <DataTemplate x:Name="dataTemplate">
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <TextBlock Grid.Column="0" 
        Text="{Binding Month, Converter={StaticResource Converter1}}"/>
      <TextBlock Grid.Column="1" Text="{Binding Total}"/>    
    </Grid>
  </DataTemplate>

</Grid.Resources>

<ItemsControl x:Name="IC1" ItemsSource="{Binding}" 
  ItemTemplate="{StaticResource dataTemplate}"/>


In C# and Visual Basic code, you can populate and bind to a List(Of T) to display an unchanging collection. If items are added to and removed from the collection at run time, and you want the target to update the ItemsSource when that happens, use ObservableCollection(Of T) instead. In C++ code, you can populate and bind to Vector<T> instances for both changing and unchanging collections. To bind to your own collection classes, use the guidance in the following table.

The data binding system supports the following binding scenarios.

ScenarioC# and VB (CLR)C++
Bind to an object.Can be any object.Object must have BindableAttribute or implement ICustomPropertyProvider.
Get property change updates from a bound object.Object must implement System.ComponentModel.INotifyPropertyChanged.Object must implement Windows.UI.Xaml.Data.INotifyPropertyChanged.
Bind to a collection. List(Of T) Platform::Collections::Vector<T>
Get collection change updates from a bound collection. ObservableCollection(Of T) Platform::Collections::Vector<T>
Implement a collection that supports binding.Extend List(Of T) or implement IList, IList(Of Object), IEnumerable, or IEnumerable(Of Object). Binding to generic IList(Of T) and IEnumerable(Of T) is not supported.Implement IBindableVector, IBindableIterable, IVector<Object^>, IIterable<Object^>, IVector<IInspectable*>, or IIterable<IInspectable*>. Binding to generic IVector<T> and IIterable<T> is not supported.
Implement a collection that supports collection change updates.Extend ObservableCollection(Of T) or implement (non-generic) IList and INotifyCollectionChanged.Implement IBindableVector and IBindableObservableVector.
Implement a collection that supports incremental loading.Extend ObservableCollection(Of T) or implement (non-generic) IList and INotifyCollectionChanged. Additionally, implement ISupportIncrementalLoading. Implement IBindableVector, IBindableObservableVector, and ISupportIncrementalLoading.

 

Loading data incrementally

You can bind list controls to arbitrarily large data sources, and still achieve high performance, by using incremental loading. For example, you can bind list controls to Bing image query results without having to load all the results at once. Instead, you load only some results immediately, and load additional results as needed. To support incremental loading, you must implement ISupportIncrementalLoading on a data source that supports collection change notification. When the data binding engine requests more data, your data source must make the appropriate requests, integrate the results, and then send the appropriate notifications in order to update the UI. For more info, see the XAML data binding sample.

Binding to folder and file lists

  • Applies to Windows

You can use the APIs in the Windows.Storage namespace to retrieve folder and file data. However, the various GetFilesAsync, GetFoldersAsync, and GetItemsAsync methods do not return values that are suitable for binding to list controls. Instead, you must bind to the return values of the GetVirtualizedFilesVector, GetVirtualizedFoldersVector, and GetVirtualizedItemsVector methods of the FileInformationFactory class. The following code example from the StorageDataSource and GetVirtualizedFilesVector sample shows the typical usage pattern.


protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var library = Windows.Storage.KnownFolders.PicturesLibrary;
    var queryOptions = new Windows.Storage.Search.QueryOptions();
    queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
    queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;

    var fileQuery = library.CreateFileQueryWithOptions(queryOptions);

    var fif = new Windows.Storage.BulkAccess.FileInformationFactory(
        fileQuery,
        Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
        190,
        Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
        false
        );

    var dataSource = fif.GetVirtualizedFilesVector();
    PicturesGrid.ItemsSource = dataSource;
}


  • Applies to Windows

You will typically use this approach to create a read-only view of file and folder info. You can create two-way bindings to the file and folder properties, for example to let users rate a song in a music view. However, any changes are not persisted until you call the appropriate SavePropertiesAsync method (for example, MusicProperties.SavePropertiesAsync). You should commit changes when the item loses focus because this triggers a selection reset.

Note that two-way binding using this technique works only with indexed locations, such as Music. You can determine whether a location is indexed by calling the FolderInformation.GetIndexedStateAsync method.

Note also that a virtualized vector can return null for some items before it populates their value. For example, you should check for null before you use the SelectedItem value of a list control bound to a virtualized vector, or use SelectedIndex instead.

Grouping data and tracking the current item

You can also bind to instances of the CollectionViewSource class to display collections of collections, and to keep track of the current item in multiple views. You typically define a CollectionViewSource as a XAML resource and bind to it by using the StaticResource markup extension. You can then set its Source property in code-behind to a supported collection type.

Any controls that you bind to the same CollectionViewSource will always have the same current item, and any bindings with Path settings will automatically bind to properties of the current item. You can access the current item programmatically through the ICollectionView.CurrentItem property of the CollectionViewSource.View property value.

If the items in the collection are collections themselves, or are objects that contain collections, you can display the collections as groups within the larger collection. To do this, set the IsSourceGrouped property to true. If the items contain collections but are not collections themselves, you must also set the ItemsPath property to the name of the collection property. For example, if you bind to a CustomerList collection of Customer objects, and the Customer class has an Orders property that is a collection of Order objects, you can group orders by customer by using the following XAML.


<local:CustomerList x:Key="CustomerData"/>
<CollectionViewSource x:Name="Customers"
  Source="{StaticResource CustomerData}"
  IsSourceGrouped="True" ItemsPath="Orders"/>


You can then create a group header template that binds to properties of the Customer class, and an item template that binds to properties of the Order class. You can also access the groups programmatically through the CollectionViewSource.CollectionGroups property.

The following code example demonstrates how to bind a ListBox control to the results of a grouping LINQ query. In this example, a collection of teams is grouped by city and displayed with the city name in the group headers. This is indicated by the "Key" property path in reference to the group Key value. For the complete code listing, see the data binding sample. For similar example code that shows grouping, see the grouped GridView sample.


<Grid>

  <Grid.Resources>
    <CollectionViewSource x:Name="groupInfoCVS" IsSourceGrouped="true"/>
  </Grid.Resources>

  <ListBox x:Name="lbGroupInfoCVS" 
    ItemsSource="{Binding Source={StaticResource groupInfoCVS}}">

    <ListBox.GroupStyle>
      <GroupStyle>
        <GroupStyle.HeaderTemplate>
          <DataTemplate>

            <TextBlock Text="{Binding Key}" />

          </DataTemplate>
        </GroupStyle.HeaderTemplate>
      </GroupStyle>
    </ListBox.GroupStyle>

    <ListBox.ItemTemplate>
      <DataTemplate>

        <Border Background="{Binding Color}" 
          Width="200" CornerRadius="10" HorizontalAlignment="Left">

          <TextBlock Text="{Binding Name}" 
            Style="{StaticResource DescriptionTextStyle}" 
            HorizontalAlignment="Center" FontWeight="Bold"/>

        </Border>
      </DataTemplate>
    </ListBox.ItemTemplate>

  </ListBox>

</Grid>



Teams teams = new Teams();
var result = 
    from t in teams 
    group t by t.City into g 
    orderby g.Key 
    select g;
groupInfoCVS.Source = result;


Another option when you bind to multi-level data, such as categories with subcategories, is to display the levels as a series of lists. Then, a selection in one list affects the contents of the subsequent lists. You can keep the lists synchronized by binding each list to its own CollectionViewSource and binding the CollectionViewSource instances together in a chain. For more info, see How to bind to hierarchical data and create a master/details view.

Data conversions

You may need to display data in a format that differs from how it is stored. Some examples are the following:

  • Storing a color as an RGBA value, but displaying it as a string name.
  • Storing a number as a floating-point value, but displaying it as a currency value.
  • Storing a date as DateTime, but displaying it in a calendar.
  • Storing a null value, but displaying a friendly default value.

Starting in Windows 8.1, you can display a friendly default value for null backing values by setting the TargetNullValue property.

You can set a converter on any binding. To customize the converter for each scenario, create a class and implement the IValueConverter interface. The following example shows how to implement IValueConverter.



// Custom class implements the IValueConverter interface.
public class DateToStringConverter : IValueConverter
{

    #region IValueConverter Members

    // Define the Convert method to change a DateTime object to 
    // a month string.
    public object Convert(object value, Type targetType, 
        object parameter, string language)
    {
        // value is the data from the source object.
        DateTime thisdate = (DateTime)value;
        int monthnum = thisdate.Month;
        string month;
        switch (monthnum)
        {
            case 1:
                month = "January";
                break;
            case 2:
                month = "February";
                break;
            default:
                month = "Month not found";
                break;
        }
        // Return the value to pass to the target.
        return month;

    }

    // ConvertBack is not implemented for a OneWay binding.
    public object ConvertBack(object value, Type targetType, 
        object parameter, string language)
    {
        throw new NotImplementedException();
    }

    #endregion
}


The binding engine calls the Convert and ConvertBack methods if the Converter parameter is defined for the binding. When data is passed from the source, the binding engine calls Convert and passes the returned data to the target. When data is passed from the target, the binding engine calls ConvertBack and passes the returned data to the source. The following example shows how to set the Converter parameter.



<UserControl.Resources>
  <local:DateToStringConverter x:Key="Converter1"/>
</UserControl.Resources>

...

<TextBlock Grid.Column="0" 
  Text="{Binding Month, Converter={StaticResource Converter1}}"/>


The converter also has optional parameters: ConverterLanguage, which allows specifying the language to be used in the conversion, and ConverterParameter, which allows passing a parameter for the conversion logic. For an example that uses a converter parameter, see IValueConverter.

If there is an error in the conversion, do not throw an exception. Instead, return DependencyProperty.UnsetValue, which will stop the data transfer.

To display a default value that appears whenever the binding source cannot be resolved, set the FallbackValue property. This is useful to handle conversion and formatting errors. It is also useful to bind to source properties that might not exist on all objects in a bound collection.

Debugging data bindings

You can debug data bindings in Microsoft Visual Studio. When you run your app with the debugger attached, any binding errors appear in the Output window in Visual Studio. This is useful, for example, when you rename properties in your data classes but forget to update your XAML binding expressions.

Displaying data in the designer

When you use the designer to create a data-bound UI, you can display sample data to view layout sizes accurately and see realistic results for automatic sizing.

To display data in the designer, you must declare it in XAML instead of just setting the DataContext property programmatically in code-behind. This is necessary because when you open a page or user control in the designer, it is not instantiated. The designer parses its XAML, but does not run its code-behind. (The designer will instantiate any child user controls that it encounters when it parses the XAML content, however.)

You can define data in XAML by using one of several different techniques, depending on whether you want to display the same data at run time and design time.

Displaying the same data at design time and run time

Displaying real data at design time is useful when your app uses only local data, or when you are prototyping your app. For example, you can declare a data object as a resource, then refer to it from other elements, as shown in the following code from How to bind to hierarchical data and create a master/details view:



<local:LeagueList x:Key="LeagueData"/>
<CollectionViewSource x:Name="Leagues"
    Source="{StaticResource LeagueData}"/>


In this case, the XAML parser instantiates the LeagueList collection class at both design time and at run time, and the LeagueList constructor populates itself with sample data.

Displaying different data at design time and run time

If you want to display sample data at design time and real data at run time, you have a few options. The simplest option is to declare your data in XAML as shown previously, and also include code in your data class to detect whether it is being called at design time or at run time. For example, you could define GetSampleData and GetRealData methods in the data class, and then use the following code in its constructor.


if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
    GetSampleData();
}
else GetRealData();


Using design-time attributes

Another option for displaying sample data at design time is to declare it in XAML by using various data attributes from the designer XML namespace. This XML namespace is typically declared with a d: prefix as follows:


xmlns:d="http://schemas.microsoft.com/expression/blend/2008"


With this declaration, attributes with d: prefixes are interpreted only at design time and are ignored at run time. For example, in the following XAML, the d:Source attribute is used for design-time-only sample data, and the Source attribute is used for run-time-only real data.


<CollectionViewSource
  x:Name="groupedItemsViewSource"
  Source="{Binding Groups}"
  IsSourceGrouped="true"
  ItemsPath="Items"
  d:Source="{Binding ItemGroups, 
    Source={d:DesignInstance Type=data:SampleDataSource, 
      IsDesignTimeCreatable=True}}"/>


This code comes from the Grid Application and Split Application project templates, which you can examine for details about the sample data source, and for the procedural code used to establish the run time data source. The d:Source property applies only to the CollectionViewSource class, but for other classes, you can use d:DataContext the same way you use DataContext.

The d:DesignInstance markup extension indicates that the design-time source is a designer-created instance based on the SampleDataSource type, as indicated by the Type setting. The IsDesignTimeCreatable setting indicates that the designer will instantiate that type directly, which is necessary to display the sample data generated by the type constructor. If you don't set this attribute (or you set it to False), the designer instead generates and instantiates a lightweight class with the same bindable properties. This is useful if you just want the properties to appear as potential binding targets in the data binding designer, but you don't care about displaying sample data.

Using file-based sample data

An alternative to d:DesignInstance is the d:DesignData markup extension. This enables you to use sample data defined in XAML or JSON files, instead of data generated programmatically in your data classes. You can refer to the sample data by using markup like the following:


<Grid d:DataContext="{Binding Source={d:DesignData Source=/Data/SampleData.xaml}}">
  <TextBlock FontSize="50" Text="{Binding Name}"/>
</Grid>


In this case, the SampleData.xaml file contains markup like the following:


<Customer xmlns="using:DemoProject.Data" Name="Customer One"/>


The xmlns declaration indicates that the markup refers to a class in the DemoProject.Data project. If you use JSON data files instead of XAML files, you must include a Type setting in the d:DesignData markup as shown here:


<Grid 
  xmlns:data="using:DemoProject.Data"
  d:DataContext="{Binding Source={d:DesignData 
    Source=/Data/SampleData.json, Type=data:SampleDataSource}}">
  <TextBlock FontSize="50" Text="{Binding Name}"/>
</Grid>


Related topics

Roadmaps
Roadmap for Windows Runtime apps using C# or Visual Basic
Roadmap for Windows Runtime apps using C++
Samples
XAML data binding sample
XAML GridView grouping and SemanticZoom sample
StorageDataSource and GetVirtualizedFilesVector sample
Reversi sample app
Reversi sample feature scenarios: data binding
Reference
Binding
DataContext
DependencyProperty
CollectionViewSource
ObservableCollection(Of T)
DataTemplate
ControlTemplate
INotifyPropertyChanged
INotifyCollectionChanged
IValueConverter
ICustomPropertyProvider
ISupportIncrementalLoading
Concepts
Quickstart: Data binding to controls
How to bind to hierarchical data and create a master/details view
Design-time attributes
XAML Overview
Binding markup extension
Property-path syntax
RelativeSource markup extension
Dependency properties overview
Custom dependency properties
Attached properties overview
ResourceDictionary and XAML resource references

 

 

Show:
© 2014 Microsoft