Udostępnij za pośrednictwem


Quickstart: Data binding to controls (XAML)

This topic shows you how to bind a control to a single item or bind a list control to a collection of items in a Windows Store app using C++, C#, or Visual Basic. In addition, this topic shows you how to customize the display of control items, implement a details view based on a selection, and convert data for display. For more detailed info, see Data binding with XAML.

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

Prerequisites

This topic assumes that you can create a basic Windows Runtime app using Microsoft Visual Basic, Microsoft Visual C#, or Microsoft Visual C++. For instructions on creating your first Windows Runtime app, see Create your first Windows Store app using C# or Visual Basic.

Binding a control to a single item

A data binding consists of a target and a source. The target is usually a property of a control, and the source is usually a property of a data object. For info on the target and source requirements, see Data binding with XAML.

The following shows an example of binding a control to a single item. The target is the Text property of a text box control. The source is a simple music Recording class.

<Grid x:Name="LayoutRoot" Background="#FF0C0C0C">
  <TextBox x:Name="textBox1" Text="{Binding}" FontSize="30"
    Height="120" Width="440" IsReadOnly="True"
    TextWrapping="Wrap" AcceptsReturn="True" />
</Grid>
// Constructor
public MainPage()
{
    InitializeComponent();
    
    // Set the data context to a new Recording.
    textBox1.DataContext = new Recording("Chris Sells", "Chris Sells Live",
        new DateTime(2008, 2, 5));
}

// A simple business object
public class Recording
{
    public Recording() { }

    public Recording(string artistName, string cdName, DateTime release)
    {
        Artist = artistName;
        Name = cdName;
        ReleaseDate = release;
    }

    public string Artist { get; set; }
    public string Name { get; set; }
    public DateTime ReleaseDate { get; set; }

    // Override the ToString method.
    public override string ToString()
    {
        return Name + " by " + Artist + ", Released: " + ReleaseDate.ToString("d");
    }
}
' Constructor
Public Sub New()
    InitializeComponent()

    ' Set the data context to a new recording.
    textBox1.DataContext = New Recording("Chris Sells", "Chris Sells Live", _
        New DateTime(2008, 2, 5))
End Sub

Public Class Recording

    Public Sub New()
    End Sub

    Public Sub New(ByVal artistName As String, ByVal cdName As String, _
        ByVal release As DateTime)

        Artist = artistName
        Name = cdName
        ReleaseDate = release

    End Sub

    Public Property Artist As String
    Public Property Name As String
    Public Property ReleaseDate As DateTime

    ' Override ToString.
    Public Overloads Overrides Function ToString() As String
        Return Name + " by " + Artist + ", Released: " + releaseDate.ToString("d")
    End Function

End Class

The preceding code produces output that is similar to the following illustration.

To display a music recording in a text box, the control's Text property is set to a Binding by using a markup extension. In this example, the Mode is OneWay by default, which means that data is retrieved from the source, but changes are not propagated back to the source.

The Recording class has three public properties and a ToString method override. The properties are Artist, Name, and ReleaseDate. The ToString method is significant, because if no formatting is specified, the ToString method is called on a bound object for display purposes. The Binding.Source property for the binding is not set directly; instead, the DataContext property for the TextBox control is set to a new Recording object.

Binding a control to a collection of objects

The previous example demonstrates the syntax you use to bind data to controls, but it is not very realistic. A more common scenario is to bind to a collection of business objects. In C# and Visual Basic, the generic ObservableCollection<T> class is a good collection choice for data binding, because it implements the INotifyPropertyChanged and INotifyCollectionChanged interfaces. These interfaces provide change notification to bound controls when an item in the list changes or a property of the list itself changes. If you want your bound controls to update with changes to properties of objects in the collection, the business object should also implement INotifyPropertyChanged. For info on binding in C++, see Data binding with XAML.

The following example binds a collection of music Recording objects to a ComboBox. To try this example, click the down arrow in the combo box to see the list of bound recordings.

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <ComboBox x:Name="ComboBox1" ItemsSource="{Binding}"
        Foreground="Black" FontSize="30" Height="50" Width="780"/>
</Grid>
public ObservableCollection<Recording> MyMusic = new ObservableCollection<Recording>();

public Page()
{
    InitializeComponent();

    // Add items to the collection.
    MyMusic.Add(new Recording("Chris Sells", "Chris Sells Live",
        new DateTime(2008, 2, 5)));
    MyMusic.Add(new Recording("Luka Abrus",
        "The Road to Redmond", new DateTime(2007, 4, 3)));
    MyMusic.Add(new Recording("Jim Hance",
        "The Best of Jim Hance", new DateTime(2007, 2, 6)));

    // Set the data context for the combo box.
    ComboBox1.DataContext = MyMusic;
}
Public MyMusic As New ObservableCollection(Of Recording)()

Public Sub New()

    InitializeComponent()

    ' Add items to the collection.
    MyMusic.Add(New Recording("Chris Sells", "Chris Sells Live", _
        New DateTime(2008, 2, 5)))
    MyMusic.Add(New Recording("Luka Abrus", "The Road to Redmond", _
        New DateTime(2007, 4, 3)))
    MyMusic.Add(New Recording("Jim Hance", "The Best of Jim Hance", _
        New DateTime(2007, 2, 6)))

    ' Set the data context for the combo box.
    ComboBox1.DataContext = MyMusic

End Sub

The preceding code produces output that is similar to the following illustration.

To display the music recordings in the ComboBox, the control's ItemsSource property is set to a Binding, and the DataContext property for the ComboBox control is set to the collection of Recording objects, which provides the source for the binding. A ComboBoxItem is created for each item in the collection. ToString is automatically called on each Recording object to display it in the combo box item.

Displaying items in a control by using a data template

You can display items in a list by using the item's ToString method. However, a more common scenario is to provide a customized display of data bound items by using a DataTemplate. A DataTemplate enables you to customize how list items are displayed in a control. Typically, you set the data template by using the ContentTemplate property of a content control or the ItemTemplate property of an items control.

The following example shows the same list of recordings bound to a combo box by using a data template. A combo box is an ItemsControl, which means that you establish a data template for each item by setting its ItemTemplate property to a data template. To try this example, click the down arrow to see the list of recordings. Notice how the recordings look different from the previous example. The artist and CD name are displayed in a custom format.

<ComboBox x:Name="ComboBox1" ItemsSource="{Binding}"
  Foreground="Black" FontSize="30" Height="50" Width="450">
  <ComboBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal" Margin="2">
        <TextBlock Text="Artist:" Margin="2" />
        <TextBlock Text="{Binding Artist}" Margin="2" />
        <TextBlock Text="CD:" Margin="10,2,0,2" />
        <TextBlock Text="{Binding Name}" Margin="2" />
      </StackPanel>
    </DataTemplate>
  </ComboBox.ItemTemplate>
</ComboBox>

The preceding code produces output that is similar to the following illustration.

In the XAML, you can see the data template definition. The data template contains a StackPanel with four TextBlock controls. The stack panel has a horizontal orientation so that the four text block controls appear side by side. Two of the TextBlock controls are bound to the Artist and Name properties of a Recording object. The other two TextBlock controls display static text. For each bound item, the binding provides the path to the property on the Recording object. As in the previous example, this binding relies on the data context to be set to the list of recordings.

This XAML uses the property element syntax. For more information about XAML syntax, see Quickstart: Creating a user interface with XAML. For more information about control layout, see Quickstart: Defining layouts.

Adding a details view

To display the details of an item when it is selected from a collection, you have to create the appropriate UI and bind the UI to the data that you want it to display. Additionally, you must use a CollectionViewSource as the data context to enable the details view to bind to the current item.

The following example shows the same list of recordings, but this time the list is the data source of a CollectionViewSource instance. The data context of the entire page or user control is set to the collection view source, and the combo box and details view inherit the data context. This enables the combo box to bind to the collection and display the same list of items while the details view automatically binds to the current item. The details view does not need to explicitly bind to the current item because the collection view source automatically provides the appropriate level of data.

To try this example, click the down arrow and select different recordings. Notice that the artist, CD name, and release date appear in a details view below the combo box.

<!--The UI for the details view-->
<StackPanel x:Name="RecordingDetails">
  <TextBlock Text="{Binding Artist}" FontWeight="Bold" FontSize="30" />
  <TextBlock Text="{Binding Name}" FontStyle="Italic" FontSize="30" />
  <TextBlock Text="{Binding ReleaseDate}" FontSize="30" />
</StackPanel>
// Set the DataContext on the parent object instead of the ComboBox
// so that both the ComboBox and details view can inherit it.  
// ComboBox1.DataContext = MyMusic;
this.DataContext = new CollectionViewSource { Source = MyMusic };
' Set the DataContext on the parent object instead of the ComboBox
' so that both the ComboBox and details view can inherit it.  
' ComboBox1.DataContext = MyMusic
Me.DataContext = New CollectionViewSource With { .Source = MyMusic }

The preceding code produces output that is similar to the following illustration.

In this example, a StackPanel is added to the user control that contains the existing combo box. Next is a stack panel that contains three text blocks to display the recording details. The Text property of each text block is bound to a property on the Recording object.

Converting data for display in controls

If you want to format and display a non-string type in a control, such as a TextBox, you can use a converter. For example, you could display a label and a formatted date instead of displaying just the date.

The following example shows a converter implementation for the release date in the list of recordings. To try this example, click the down arrow and select different recordings. Notice that the release date in the drop-down list and details view is displayed in a custom format.

<UserControl x:Class="TestDataBindingQS.Page2"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:local="using:TestDataBindingQS"
  mc:Ignorable="d"
  d:DesignHeight="768" d:DesignWidth="1366">

  <UserControl.Resources>
    <local:StringFormatter x:Key="StringConverter"/>
  </UserControl.Resources>

  <Grid x:Name="LayoutRoot" Background="#FF0C0C0C">

    <StackPanel Width="750" Height="200"
      VerticalAlignment="Center" HorizontalAlignment="Center">
    
      <ComboBox x:Name="ComboBox1" ItemsSource="{Binding}" 
        Foreground="Black" FontSize="30" Height="50" Width="750">
        <ComboBox.ItemTemplate>
          <DataTemplate>
            <StackPanel Orientation="Horizontal" Margin="2">
              <TextBlock Text="Artist:" Margin="2" />
              <TextBlock Text="{Binding Artist}" Margin="2" />
              <TextBlock Text="CD:" Margin="10,2,0,2" />
              <TextBlock Text="{Binding Name}" Margin="2" />
            </StackPanel>
          </DataTemplate>
        </ComboBox.ItemTemplate>
      </ComboBox>

      <!--The UI for the details view-->
      <StackPanel x:Name="RecordingDetails">
        <TextBlock Text="{Binding Artist}" FontSize="30" FontWeight="Bold" />
        <TextBlock Text="{Binding Name}" FontSize="30" FontStyle="Italic" />
        <TextBlock Text="{Binding ReleaseDate,
          Converter={StaticResource StringConverter},
          ConverterParameter=Released: \{0:d\}}" FontSize="30"  />
      </StackPanel>

    </StackPanel>
  
  </Grid>

</UserControl>
public class StringFormatter : IValueConverter
{
    // This converts the value object to the string to display.
    // This will work with most simple types.
    public object Convert(object value, Type targetType,
        object parameter, System.Globalization.CultureInfo culture)
    {
        // Retrieve the format string and use it to format the value.
        string formatString = parameter as string;
        if (!string.IsNullOrEmpty(formatString))
        {
            return string.Format(culture, formatString, value);
        }

        // If the format string is null or empty, simply
        // call ToString() on the value.
        return value.ToString();
    }

    // No need to implement converting back on a one-way binding
    public object ConvertBack(object value, Type targetType,
        object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Public Class StringFormatter
    Implements IValueConverter

    ' This converts the DateTime object to the string to display.
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, _
        ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) _
        As Object Implements IValueConverter.Convert

        ' Retrieve the format string and use it to format the value.
        Dim formatString As String = TryCast(parameter, String)
        If Not String.IsNullOrEmpty(formatString) Then
            Return String.Format(culture, formatString, value)
        End If

        ' If the format string is null or empty, simply call ToString()
        ' on the value.
        Return value.ToString()

    End Function

    ' No need to implement converting back on a one-way binding
    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, _
        ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) _
        As Object Implements IValueConverter.ConvertBack

        Throw New NotImplementedException()

    End Function

End Class

The preceding code produces output that is similar to the following illustration.

A converter is a class that derives from the IValueConverter interface. IValueConverter has two methods: Convert and ConvertBack. For a one-way binding from the data source to the binding target, you only have to implement the Convert method. The converter in this example is fairly generic. You can pass the desired string format as a parameter, and the converter uses the String.Format method to perform the conversion. If no format string is passed, the converter returns the result of calling ToString on the object.

Once you implement the converter, you create an instance of the converter class and tell the bindings to use this instance. In this example, this is performed in XAML. An instance of the converter is created as a static resource and assigned a key. The key is used when the converter property is set on the binding.

For more information about how to convert data for display in controls, see IValueConverter.

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

Reference

Binding

DataContext

DependencyProperty

CollectionViewSource

IValueConverter

INotifyPropertyChanged

INotifyCollectionChanged

DataTemplate

Concepts

Data binding with XAML

How to bind to hierarchical data and create a master/details view

Binding markup extension

Property-path syntax

RelativeSource markup extension

Dependency properties overview

Custom dependency properties

Attached properties overview

Create your first Windows Store app using C# or Visual Basic