什么是绑定声明? (WPF .NET)

通常,开发人员直接在要将数据绑定到的 UI 元素的 XAML 标记中声明绑定。 不过,也可以在代码中声明绑定。 本文介绍如何在 XAML 和代码中声明绑定。

先决条件

在阅读本文之前,请务必熟悉标记扩展的概念和使用。 有关标记扩展的详细信息,请参阅标记扩展和 WPF XAML

本文不介绍数据绑定概念。 有关数据绑定概念的讨论,请参阅数据绑定概述

在 XAML 中声明绑定

Binding 是标记扩展。 使用绑定扩展声明绑定时,声明包含一系列子句,这些子句跟在 Binding 关键字后面,并由逗号 (,) 分隔。 绑定声明中的子句可以按任意顺序排列,有多种可能的组合。 这些子句是 Name=Value 对,其中 Name 是 Binding 属性的名称,Value 是为该属性设置的值

在标记中创建绑定声明字符串时,必须将这些字符串附加到目标对象的特定依赖属性。 下面的示例演示如何使用绑定扩展并指定 SourcePath 属性来绑定 TextBox.Text 属性。

<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=Name}"/>

上一个示例使用 Person 的简单数据对象类型。 以下代码片段是该对象的代码:

class Person
{
    public string Name { get; set; }
    public DateTime Birthdate { get; set; }
}
Public Class Person

    Public Property Name As String
    Public Property Birthdate As DateTime
    
End Class

可以通过这种方式指定 Binding 类的大多数属性。 有关绑定扩展以及使用绑定扩展无法设置的 Binding 属性列表的详细信息,请参阅绑定标记扩展 (.NET Framework)概述。

有关在 XAML 中创建绑定的示例,请参阅如何创建数据绑定

对象元素语法

对象元素语法是创建绑定声明的替代方法。 在大多数情况下,使用标记扩展或对象元素语法没有特定的优势。 不过,如果标记扩展不支持你的方案,例如,当属性值是不存在任何类型转换的非字符串类型时,需要使用对象元素语法。

上一部分演示了如何使用 XAML 扩展进行绑定。 以下示例演示如何使用对象元素语法执行相同的绑定:

<TextBlock>
    <TextBlock.Text>
        <Binding Source="{StaticResource myDataSource}" Path="Name"/>
    </TextBlock.Text>
</TextBlock>

有关其他术语的详细信息,请参阅 XAML 语法详述 (.NET Framework)

MultiBinding 和 PriorityBinding

MultiBindingPriorityBinding 不支持 XAML 扩展语法。 因此,在 XAML 中声明 MultiBindingPriorityBinding 时必须使用对象元素语法。

在代码中创建绑定

指定绑定的另一种方法是直接在代码中的 Binding 对象上设置属性,然后将绑定分配给属性。 下面的示例演示如何在代码中创建 Binding 对象。

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    // Make a new data source object
    var personDetails = new Person()
    {
        Name = "John",
        Birthdate = DateTime.Parse("2001-02-03")
    };

    // New binding object using the path of 'Name' for whatever source object is used
    var nameBindingObject = new Binding("Name");

    // Configure the binding
    nameBindingObject.Mode = BindingMode.OneWay;
    nameBindingObject.Source = personDetails;
    nameBindingObject.Converter = NameConverter.Instance;
    nameBindingObject.ConverterCulture = new CultureInfo("en-US");

    // Set the binding to a target object. The TextBlock.Name property on the NameBlock UI element
    BindingOperations.SetBinding(NameBlock, TextBlock.TextProperty, nameBindingObject);
}
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)

    ' Make a new data source object
    Dim personDetails As New Person() With {
        .Name = "John",
        .Birthdate = Date.Parse("2001-02-03")
    }

    ' New binding object using the path of 'Name' for whatever source object is used
    Dim nameBindingObject As New Binding("Name")

    ' Configure the binding
    nameBindingObject.Mode = BindingMode.OneWay
    nameBindingObject.Source = personDetails
    nameBindingObject.Converter = NameConverter.Instance
    nameBindingObject.ConverterCulture = New CultureInfo("en-US")

    ' Set the binding to a target object. The TextBlock.Name property on the NameBlock UI element
    BindingOperations.SetBinding(NameBlock, TextBlock.TextProperty, nameBindingObject)

End Sub

前面的代码在绑定上设置了以下内容:

  • 数据源对象上属性的路径。
  • 绑定的模式。
  • 在本例中,数据源是表示人的简单对象实例。
  • 一个可选转换器,该转换器在将数据源对象传入的值分配给目标属性之前对其进行处理。

如果要绑定的对象是 FrameworkElementFrameworkContentElement,可以直接在对象上调用 SetBinding 方法,而不是使用 BindingOperations.SetBinding。 有关示例,请参阅如何:在代码中创建绑定

上一个示例使用 Person 的简单数据对象类型。 下面是该对象的代码:

class Person
{
    public string Name { get; set; }
    public DateTime Birthdate { get; set; }
}
Public Class Person

    Public Property Name As String
    Public Property Birthdate As DateTime
    
End Class

绑定路径语法

使用 Path 属性指定要绑定到的源值:

  • 在最简单的情况下,Path 属性值是要用于绑定的源对象的属性名称,如 Path=PropertyName

  • 在 C# 中,可以通过类似语法指定属性的子属性。 例如,子句 Path=ShoppingCart.Order 设置与对象或属性 ShoppingCart 的子属性 Order 的绑定。

  • 若要绑定到附加属性,请将附加属性置于括号中。 例如,若要绑定到附加属性 DockPanel.Dock,则语法为 Path=(DockPanel.Dock)

  • 可以在已应用索引器的属性名后面的方括号内指定属性的索引器。 例如,子句 Path=ShoppingCart[0] 将绑定设置为与属性的内部索引处理文本字符串“0”的方式对应的索引。 还支持嵌套索引器。

  • 可以在 Path 子句中混用索引器和子属性,例如 Path=ShoppingCart.ShippingInfo[MailingAddress,Street].

  • 索引器内部。 可以使用多个由逗号 (,) 分隔的索引器参数。 可以使用括号指定每个参数的类型。 例如,可以使用 Path="[(sys:Int32)42,(sys:Int32)24]",其中 sys 将映射到 System 命名空间。

  • 如果源是集合视图,则可以使用斜杠 (/) 指定当前项。 例如,子句 Path=/ 设置与视图中当前项的绑定。 如果源是集合,则此语法指定默认集合视图的当前项。

  • 可以组合使用属性名和斜杠,以遍历作为集合的属性。 例如,Path=/Offices/ManagerName 指定源集合的当前项,源集合中包含的 Offices 属性也是一个集合。 它的当前项是一个包含 ManagerName 属性的对象。

  • 句点 (.) 路径也可以用于绑定到当前源。 例如,Text="{Binding}" 等效于 Text="{Binding Path=.}"

转义机制

  • 在索引器 ([ ]) 内部,脱字符号 (^) 用于对下一个字符进行转义。

  • 如果在 XAML 中设置 Path,还需要(使用 XML 实体)对 XML 语言定义专用的某些字符进行转义:

    • 使用 &amp; 对字符“&”进行转义。

    • 使用 &gt; 对结束标记“>”进行转义。

  • 此外,如果在属性中使用标记扩展语法描述整个绑定,需要(使用反斜杠 \)对 WPF 标记扩展分析器专用的字符进行转义:

    • 反斜杠 (\) 本身是转义字符。

    • 等号 (=) 将属性名与属性值分隔开。

    • 逗号 (,) 用于分隔属性。

    • 右大括号 (}) 是标记扩展的结尾。

绑定方向

使用 Binding.Mode 属性指定绑定的方向。 以下模式是可供绑定更新的选项:

绑定模式 说明
BindingMode.TwoWay 无论是目标属性还是源属性,只要发生了更改,就会更新目标属性或属性。
BindingMode.OneWay 仅当源属性发生更改时更新目标属性。
BindingMode.OneTime 仅当应用程序启动或 DataContext 进行更改时更新目标属性。
BindingMode.OneWayToSource 在目标属性更改时,更新源属性。
BindingMode.Default 导致使用目标属性的默认值 Mode

有关详细信息,请参见 BindingMode 枚举。

下面的示例演示如何设置 Mode 属性:

<TextBlock Name="IncomeText" Text="{Binding Path=TotalIncome, Mode=OneTime}" />

若要检测源更改(适用于 OneWayTwoWay 绑定),则源必须实现合适的属性更改通知机制,例如 INotifyPropertyChanged。 有关详细信息,请参阅提供更改通知

对于 TwoWayOneWayToSource 绑定,可以通过设置 UpdateSourceTrigger 属性来控制源更新执行时间。 有关详细信息,请参阅 UpdateSourceTrigger

默认行为

如果未在声明中指定默认行为,则默认行为如下所示:

  • 创建一个默认转换器,尝试在绑定源值和绑定目标值之间执行类型转换。 如果不能进行转换,默认转换器会返回 null

  • 如果未设置 ConverterCulture,绑定引擎会使用绑定目标对象的 Language 属性。 在 XAML 中,此属性默认为“en-US”,如果已显式设置了一个值,则从页面的根元素(或任何元素)继承该值。

  • 只要绑定已具有数据上下文(例如,来自父元素的继承数据上下文),并且该上下文返回的任何项或集合无需进一步修改路径即适用于绑定,则绑定声明可以不必使用任何子句:{Binding}。 这通常是为数据样式指定绑定所用的方法,其中该绑定作用于某个集合。 有关详细信息,请参阅将整个对象用作绑定源

  • 默认 Mode 可能为单向,也可能为双向,具体取决于要绑定的依赖属性。 始终可以显式声明绑定模式,以确保绑定具有所需行为。 一般情况下,用户可编辑的控件属性(例如 TextBox.TextRangeBase.Value)默认为双向绑定,但其他大多数属性默认为单向绑定。

  • 默认 UpdateSourceTrigger 值可能为 PropertyChanged,也可能为 LostFocus,具体同样取决于绑定的依赖属性。 大多数依赖属性的默认值为 PropertyChanged,而 TextBox.Text 属性的默认值为 LostFocus

另请参阅