MSDN Library
信息
您所需的主题如下所示。但此主题未包含在此库中。

Windows Phone 8 的数据绑定

2014/6/18

适用于:Windows Phone 8 和 Windows Phone Silverlight 8.1 | Windows Phone OS 7.1

数据绑定为 Windows Phone 应用提供了一种显示数据并与数据进行交互的简便方法。数据的显示方式独立于数据的管理。UI 和数据对象之间的连接或绑定使数据得以在这二者之间传输。绑定建立后,如果数据更改,则绑定到该数据的 UI 元素可以自动反映更改。同样,用户对 UI 元素所做的更改也可以在数据对象中反映出来。例如,如果用户编辑 TextBox 中的值,则基础数据值会自动更新以反映该更改。

常用的一些绑定方案包括将 ListBox 绑定到标题列表,将输入窗体的 TextBox 绑定到客户数据对象,或者将 Image 绑定到当前用户的照片。

本主题使用简单代码示例阐释数据绑定概念。还可以使用 Visual Studio 实现许多数据绑定任务。

本主题包括以下部分。

必须为每个绑定都指定源和目标。下图演示绑定的基本概念。

Explain Binding Details

源可以是任意 CLR 对象,包括目标元素自身或其他 UI 元素。如果目标处于某一数据模板中,则源可以是该模板应用于的 UI 元素。

目标可以是 FrameworkElement 的任一 DependencyProperty

在以下情况下目标还可以是 DependencyObjectDependencyProperty

从 Windows Phone 8 开始,目标还可以是 StyleSetterValue 属性。有关示例,请参见 Style 类的概述。

绑定引擎从 Binding 对象获取以下方面的信息:

例如,可以将 TextBoxForeground 属性绑定到 SolidColorBrush,以便文本的颜色可以基于数据发生变化。在此方案中,Foreground 属性为绑定目标,而 SolidColorBrush 对象为绑定源。

下例演示如何通过代码和 XAML 将 TextBoxForeground 颜色绑定到 SolidColorBrush。绑定源是 MyColors 类的属性,该类将在本主题的后面介绍。


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



// 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;


说明注意:

该示例使用 XAML 属性语法来创建绑定。也可以在 XAML 中使用对象元素语法来创建绑定。有关更多信息,请参见 Windows Phone 8 的 XAML

该绑定是在 XAML 中使用 {Binding ...} 语法创建的。绑定源是通过在代码中为 TextBox 设置 DataContext 属性而设置的。

数据上下文是可继承的。如果对父元素设置了数据上下文,则其所有子元素都将使用这一数据上下文。子元素可以通过以下方式来重写此行为:对其绑定对象设置 Source 属性或者设置其 DataContext(之后将应用于其所有子级)。

如果希望拥有多个绑定且所有这些绑定使用同一个源,则设置数据上下文会很有用。若要设置单个绑定的源,请对 Binding 对象设置 Source 属性。有关更多信息,请参见如何为 Windows Phone 创建数据绑定

还可以使用 ElementName 属性或 RelativeSource 属性指定绑定源。当绑定到应用中的其他元素时(例如在使用滑块调整按钮的宽度时),ElementName 属性是很有用的。当在 ControlTemplateStyle 中指定绑定时,RelativeSource 属性是很有用的。

您可以通过设置 Binding.Path 属性,绑定到源对象的某一属性。Path 属性支持用于绑定到嵌套属性、附加属性、字符串索引器的多种语法选项。

总之,上述示例使绑定引擎创建一个绑定(默认为 OneWay),将 TextBoxForeground 属性连接到 TextColor 对象的 brush1 属性。

每个绑定都有一个 Mode 属性,该属性决定数据流动的方式和时间。在 Windows Phone 中,您可以使用三种类型的绑定:

  • 创建 OneTime 绑定时,该绑定使用源数据更新目标。

  • 创建 OneWay 绑定时以及每当源数据发生变化时,该绑定使用源数据更新目标。这是默认模式。

  • 当目标和源有一个发生变化时,TwoWay 绑定既更新目标也更新源。或者,您可以禁用自动源更新,只在您选择的时间对源进行更新。

为了能够发生自动目标更新,源对象必须实现 INotifyPropertyChanged 接口,如下一部分所述。

为了使源对象的更改能够传播到目标,源必须实现 INotifyPropertyChanged 接口。INotifyPropertyChanged 具有 PropertyChanged 事件,该事件通知绑定引擎源已更改,以便绑定引擎可以更新目标值。

在下面的示例中,MyColors 类为 OneWay 绑定实现 INotifyPropertyChanged 接口。


// 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 raise the PropertyChanged event, 
    // passing the source property that is being updated.
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, 
                new PropertyChangedEventArgs(propertyName));
        }
    }
}


若要获取绑定到 ItemsControl 的集合的更改通知,除了实现 INotifyPropertyChanged 外,还要实现 INotifyCollectionChanged。如果实现 INotifyCollectionChanged,对集合的更改(例如添加或移除对象)将传播到目标。若要获取集合中对象的属性更改通知,这些对象必须实现 INotifyPropertyChanged

在实现您自己的集合之前,应考虑使用 ObservableCollection<T> 类,该类具有 INotifyCollectionChangedINotifyPropertyChanged 的内置实现。

TwoWay 绑定中,对目标的更改会自动更新源,但绑定到 TextBoxText 属性时除外。这种情况下,更新仅在 TextBox 失去焦点时发生。

您可以禁用自动源更新,只在您选择的时间对源进行更新。例如,您可以这样做,以便在更新绑定数据源之前验证来自多个控件的用户输入。

若要禁用自动源更新,请将 UpdateSourceTrigger 属性设置为 Explicit。此设置影响使用相同 Binding 对象的所有绑定(例如,在使用继承的数据上下文时)。但是,您必须为每个绑定单独更新源。若要更新某一绑定,请首先调用目标元素的 FrameworkElement.GetBindingExpression 方法,并且传递到目标 DependencyProperty 中。然后,可以使用返回值调用 BindingExpression.UpdateSource 方法。下面的示例代码演示了此过程。


<TextBox x:Name="textBox1" Text="{Binding Test, Mode=TwoWay, UpdateSourceTrigger=Explicit}" />
<Button Content="Update" Click="Button_Click" />



public class TestData
{
    public String Test { get; set; }
}

TestData data;

public MainPage()
{
    InitializeComponent();
    data = new TestData { Test = "one" };
    textBox1.DataContext = data;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    BindingExpression expression = textBox1.GetBindingExpression(TextBox.TextProperty);
    MessageBox.Show("Before UpdateSource, Test = " + data.Test);
    expression.UpdateSource();
    MessageBox.Show("After UpdateSource, Test = " + data.Test);
}


可以将绑定源对象视为一个对象(其属性包含数据),也可以将它视为一个对象集合。例如,您可能希望显示项的列表,如每月的信用卡帐单。为此,请使用 ItemsControl 并使用 DataTemplate 以显示集合中的每一项。


<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}"/>


可以枚举实现 IEnumerable 的任何集合。如果希望目标在集合更改时更新 ItemsSource,请实现 INotifyCollectionChanged。有关更改通知的更多信息,请参见本主题前面介绍的"更改通知"部分。

还可以绑定到 CollectionViewSource 类的实例,该类提供对其他数据源的排序、分组、筛选和货币支持。CollectionViewSource 使您可以显示多个数据视图,这些视图保持与用户选择更改同步。

您还可以使用 CollectionViewSource 将多个控件绑定到在层次结构上相关的数据。

有关在对象中封装泛型列表以便您可以将控件绑定到它的信息,请参见 List<T>Dictionary<TKey, TValue> 的第一个代码示例。

Windows Phone 支持在 TwoWay 绑定中对从目标到源的更新进行简单数据验证。

只要绑定的 Validation.Errors 附加属性包含错误,Windows Phone 就会报告验证错误。在以下情况下,将向此集合中添加错误:

  • 从绑定引擎的类型转换器中引发了异常。

  • 在绑定对象的 set 访问器中引发了异常。

  • 在应用到数据对象或成员的验证属性中引发了异常。

  • 此绑定对象实现 IDataErrorInfo,并且其 Item 属性返回不是 nullEmpty 的值。

  • 此绑定对象实现 INotifyDataErrorInfo,并且其 GetErrors 方法返回不是 null 的值。GetErrors 返回值可能会因为完成了异步验证操作而发生变化。

在发生以下情况时,Windows Phone 会为验证错误提供直观的反馈:

该可视反馈指示包含错误的控件并显示附近的错误消息。

为了收到发生了验证错误或者错误已解决这一通知,还必须在绑定对象上将 NotifyOnValidationError 属性设置为 true。这指示绑定引擎在验证错误添加到 Validation.Errors 集合或者从该集合中删除时引发 BindingValidationError 事件。例如,您可以处理错误事件,以便记录错误或提供其他可视反馈。

若要处理 BindingValidationError 事件,请在目标对象或其任一父级上创建一个事件处理程序。BindingValidationError 事件为路由事件,因此如果不在引发该事件的元素上予以处理,它将不断向上冒泡,直到得到处理。有关路由事件的更多信息,请参见Windows Phone 8 的事件

下面的示例显示如何提供自定义绑定验证。

该绑定是在 XAML 中创建的。


<StackPanel BindingValidationError="StackPanel_BindingValidationError" >
    <StackPanel.Resources>
        <my:Bills x:Name="MyBills"/>
    </StackPanel.Resources>

    <TextBlock 
        TextWrapping="Wrap"
        Text="To generate a validation error, input a negative number or a non-number and then tap the button."
    />

    <TextBox x:Name="MyTextBox" Width="50" Margin="10">
        <TextBox.Text>
            <Binding Mode="TwoWay" Source="{StaticResource MyBills}" 
                 Path="Amount" NotifyOnValidationError="true" 
                 ValidatesOnExceptions="true"/>
        </TextBox.Text>
    </TextBox>
    <Button Content="Tap to Update"/>
</StackPanel>


如果值为负,源对象将在 set 访问器中引发异常。


public class Bills
{
    private double _Amount;
    public double Amount
    {
        get { return _Amount; }
        set
        {
            if (value < 0)
                throw new Exception("Amount must be greater than zero.");
            _Amount = value;
        }
    }

}


StackPanel 实现 BindingValidationError 事件的处理程序。


private void StackPanel_BindingValidationError(object sender, 
    ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
    {
        MyTextBox.Background = new SolidColorBrush(Colors.Red);

    }
    else if (e.Action == ValidationErrorEventAction.Removed)
    {
        MyTextBox.Background = new SolidColorBrush(Colors.White);
    }
}


在此代码示例中,键入字母(而不是数字)可以获得由类型转换器引起的错误。键入一个负值可以获得来自源对象的 set 访问器的错误。键入一个正值可以解决此验证错误。仅当 TextBox 丢失焦点时才会发生 TextBox 从目标到源的更新。所提供的按钮用于更改焦点。如果愿意,您可以手动更新源以便响应按钮单击,如前面的“更新数据源”一节中所述。

可能需要以不同于数据存储方式的格式来显示数据。下面是一些示例:

  • 将某种颜色存储为一个 RGBA 值,但将它显示为一个字符串名称。

  • 将某个数字存储为一个浮点值,但将它显示为一个货币值。

  • 将某个日期存储为 DateTime,但将它显示在日历中。

  • 存储一个 null 值,但显示一个友好的默认值。

可以通过设置 StringFormat 属性来格式化用于显示的任何 String 值。

还可以通过设置 TargetNullValue 属性显示用于 null 后备值的友好默认值。

还可以对任何绑定设置转换器。通过创建一个类和实现 IValueConverter 接口来针对每个具体的应用场景自定义该转换器。下面的示例演示如何实现 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, 
System.Globalization.CultureInfo culture)
    {
        // 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, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}


如果为绑定定义了 Converter 参数,则绑定引擎会调用 ConvertConvertBack 方法。从源传递数据时,绑定引擎调用 Convert 并将返回的数据传递给目标。从目标传递数据时,绑定引擎调用 ConvertBack 并将返回的数据传递给源。下面的示例演示如何设置 Converter 参数。


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


...


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


此外,转换器还具有可选参数:ConverterCultureConverterParameter,通过前者可以指定转换中使用的区域性,通过后者可以为转换逻辑传递一个参数。有关使用这些参数的示例,请参见 IValueConverter

如果转换时发生错误,将不会引发异常,而是返回 DependencyProperty.UnsetValue,它将停止数据传输。

若要显示当无法解析绑定源时就会出现的默认值,请设置 FallbackValue 属性。这用于处理转换和格式化错误。还可用于绑定到可能在绑定集合中的所有对象上都不存在的源属性。

显示:
© 2016 Microsoft