什么是绑定声明?

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

先决条件

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

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

在 XAML 中声明绑定

Binding 是标记扩展。 使用绑定扩展声明绑定时,声明由一系列语句组成,在 Binding 关键字之后并用逗号(,)分隔。 绑定声明中的子句可以按任意顺序排列,并且有许多可能的组合。 子句是 Name= 对,其中 Name 是属性的名称 BindingValue 是要为属性设置的值。

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

<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 不支持 XAML 扩展语法。 因此,如果要在 XAML 中 MultiBinding 声明或 PriorityBinding 声明对象元素语法,则必须使用对象元素语法。

在代码中创建绑定

指定绑定的另一种方法是直接在代码中的对象上 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 属性指定绑定的方向。 以下模式是绑定更新的可用选项:

绑定模式 DESCRIPTION
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值因绑定依赖属性的不同而在PropertyChangedLostFocus之间变化。 大多数依赖属性的默认值是 ,而 属性的默认值为 < a0/>。

另请参阅