数据绑定概述Data Binding Overview

Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) 数据绑定为应用程序呈现数据并与数据交互提供了一种简单且一致的方式。data binding provides a simple and consistent way for applications to present and interact with data. 元素可以绑定到各种数据源中的数据, 格式为公共语言运行时 (CLR) 对象和XMLXMLElements can be bound to data from a variety of data sources in the form of common language runtime (CLR) objects and XMLXML. ContentControlButton等和ItemsControl都具有内置功能,可实现单一数据项或数据项集合的灵活样式。ListBox ListViewContentControls such as Button and ItemsControls such as ListBox and ListView have built-in functionality to enable flexible styling of single data items or collections of data items. 可基于数据生成排序、筛选和分组视图。Sort, filter, and group views can be generated on top of the data.

WPFWPF 中的数据绑定功能与传统模型相比具有几个优点,包括本质上支持数据绑定的大量属性、灵活的 UIUI 数据 UI 表示形式以及业务逻辑与 UIUI 的完全分离。The data binding functionality in WPFWPF has several advantages over traditional models, including a broad range of properties that inherently support data binding, flexible UIUI representation of data, and clean separation of business logic from UIUI.

本主题首先讨论有关WPFWPF数据绑定的基本概念, 并探讨Binding类的用法和数据绑定的其他功能。This topic first discusses concepts fundamental to WPFWPF data binding and then goes into the usage of the Binding class and other features of data binding.

什么是数据绑定?What Is Data Binding?

数据绑定是在应用程序 UIUI 和业务逻辑之间建立连接的过程。Data binding is the process that establishes a connection between the application UIUI and business logic. 如果绑定具有正确的设置,并且数据提供适当的通知,则在数据更改其值时,绑定到该数据的元素会自动反映更改。If the binding has the correct settings and the data provides the proper notifications, then, when the data changes its value, the elements that are bound to the data reflect changes automatically. 数据绑定还意味着,如果元素中数据的外部表示形式发生更改,则基础数据可以自动进行更新以反映更改。Data binding can also mean that if an outer representation of the data in an element changes, then the underlying data can be automatically updated to reflect the change. 例如, 如果用户编辑TextBox元素中的值, 则基础数据值会自动更新以反映此更改。For example, if the user edits the value in a TextBox element, the underlying data value is automatically updated to reflect that change.

数据绑定的典型用法是将服务器或本地配置数据放置到窗体或其他 UIUI 控件中。A typical use of data binding is to place server or local configuration data into forms or other UIUI controls. WPFWPF 中,此概念得到扩展,包括将大量属性绑定到各种数据源。In WPFWPF, this concept is expanded to include the binding of a broad range of properties to a variety of data sources. WPFWPF中, 元素的依赖项属性可以绑定到 CLR 对象 (包括与 web 服务和 web 属性相关联的 ADO.NET 对象或XMLXML对象) 和数据。In WPFWPF, dependency properties of elements can be bound to CLR objects (including ADO.NET objects or objects associated with Web Services and Web properties) and XMLXML data.

有关数据绑定的示例,请参阅数据绑定演示中的以下应用程序 UIUIFor an example of data binding, take a look at the following application UIUI from the Data Binding Demo:

数据绑定示例屏幕快照Data binding sample screenshot

以上是一个显示拍卖项列表的应用程序 UIUIThe above is the UIUI of an application that displays a list of auction items. 应用程序演示了数据绑定的以下功能:The application demonstrates the following features of data binding:

  • ListBox内容绑定到AuctionItem对象的集合。The content of the ListBox is bound to a collection of AuctionItem objects. AuctionItem 对象具有 DescriptionStartPriceStartDateCategorySpecialFeatures 等属性。An AuctionItem object has properties such as Description, StartPrice, StartDate, Category, SpecialFeatures, etc.

  • 中显示的 ListBox数据 (AuctionItem 对象) 为模板化, 以便为每个项目显示说明和当前价格。The data (AuctionItem objects) displayed in the ListBox is templated so that the description and the current price are shown for each item. 这是使用来完成DataTemplate的。This is done using a DataTemplate. 此外,每个项的外观取决于要显示的 AuctionItemSpecialFeatures 值。In addition, the appearance of each item depends on the SpecialFeatures value of the AuctionItem being displayed. 如果 AuctionItemSpecialFeatures 值为 Color,则该项具有蓝色边框。If the SpecialFeatures value of the AuctionItem is Color, the item has a blue border. 如果值为 Highlight,则该项具有橙色边框和一个星号。If the value is Highlight, the item has an orange border and a star. 数据模板化部分提供了数据模板化的相关信息。The Data Templating section provides information about data templating.

  • 用户可以使用所提供的CheckBoxes 对数据进行分组、筛选或排序。The user can group, filter, or sort the data using the CheckBoxes provided. 在上面的图像中, 选择了 "按类别分组" 和 "按类别排序和CheckBox日期排序"。In the image above, the "Group by category" and "Sort by category and date" CheckBoxes are selected. 你可能已注意到,数据按产品类别分组,类别名称按字母顺序排序。You may have noticed that the data is grouped based on the category of the product, and the category name is in alphabetical order. 这些项还按每个类别中的开始日期排序,但难以从图中注意到这一点。It is difficult to notice from the image but the items are also sorted by the start date within each category. 这可使用集合视图来实现。This is done using a collection view. 绑定到集合部分讨论了集合视图。The Binding to Collections section discusses collection views.

  • 当用户选择某一项时, ContentControl将显示所选项的详细信息。When the user selects an item, the ContentControl displays the details of the selected item. 这称为主从方案This is called the Master-Detail scenario. 主从方案部分提供了有关此类型的绑定方案的信息。The Master-Detail Scenario section provides information about this type of binding scenario.

  • 开始属性的类型为DateTime, 它返回包含毫秒的时间的日期。The type of the StartDate property is DateTime, which returns a date that includes the time to the millisecond. 在此应用程序中,使用了一个自定义转换器,以便显示较短的日期字符串。In this application, a custom converter has been used so that a shorter date string is displayed. 数据转换部分提供了有关转换器的信息。The Data Conversion section provides information about converters.

当用户单击“添加产品”按钮时,会出现以下窗体:When the user clicks the Add Product button, the following form comes up:

添加产品清单页Add Product Listing page

用户可以编辑窗体中的字段,使用简略预览和详细预览窗格来预览产品清单,然后单击“提交”以添加新的产品清单。The user can edit the fields in the form, preview the product listing using the short preview and the more detailed preview panes, and then click submit to add the new product listing. 任何现有的分组、筛选和排序功能都将应用于新项。Any existing grouping, filtering and sorting functionalities will apply to the new entry. 在这种特殊情况下,上图中输入的项会作为 Computer 类别中的第二项显示。In this particular case, the item entered in the above image will be displayed as the second item within the Computer category.

此图中未显示的是在开始日期 TextBox提供的验证逻辑。Not shown in this image is the validation logic provided in the Start Date TextBox. 如果用户输入无效的日期 (格式无效或过去的日期), 则将向用户通知ToolTip , 旁边TextBox有一个红色的感叹号。If the user enters an invalid date (invalid formatting or a past date), the user will be notified with a ToolTip and a red exclamation point next to the TextBox. 数据验证一节讨论了如何创建验证逻辑。The Data Validation section discusses how to create validation logic.

在详细介绍数据绑定的上述不同功能之前,我们会先在下一节中讨论一些对理解 WPFWPF 数据绑定非常重要的基本概念。Before going into the different features of data binding outlined above, we will first discuss in the next section the fundamental concepts that are critical to understanding WPFWPF data binding.

数据绑定基本概念Basic Data Binding Concepts

不论要绑定什么元素,也不论数据源的特性是什么,每个绑定都始终遵循下图所示的模型:Regardless of what element you are binding and the nature of your data source, each binding always follows the model illustrated by the following figure:


如上图所示,数据绑定实质上是绑定目标与绑定源之间的桥梁。As illustrated by the above figure, data binding is essentially the bridge between your binding target and your binding source. 该图演示了以下基本的 WPFWPF 数据绑定概念:The figure demonstrates the following fundamental WPFWPF data binding concepts:

  • 通常,每个绑定都具有以下四个组件:绑定目标对象、目标属性、绑定源,以及要使用的绑定源中的值路径。Typically, each binding has these four components: a binding target object, a target property, a binding source, and a path to the value in the binding source to use. 例如, 如果想要将的TextBox内容绑定到Employee对象的TextBox Name属性, 则目标对象为, 目标属性是Text属性, 要使用的值为Name,源对象是Employee对象。For example, if you want to bind the content of a TextBox to the Name property of an Employee object, your target object is the TextBox, the target property is the Text property, the value to use is Name, and the source object is the Employee object.

  • 目标属性必须为依赖属性。The target property must be a dependency property. 大多数UIElement属性都是依赖属性, 大多数依赖属性 (只读属性除外) 默认支持数据绑定。Most UIElement properties are dependency properties and most dependency properties, except read-only ones, support data binding by default. (仅DependencyObject类型可以定义依赖属性, 而UIElement所有的都DependencyObject是从派生的。)(Only DependencyObject types can define dependency properties and all UIElements derive from DependencyObject.)

  • 虽然图中未指定, 但应注意, 绑定源对象并不限于自定义 CLR 对象。Although not specified in the figure, it should be noted that the binding source object is not restricted to being a custom CLR object. WPFWPF数据绑定支持 CLR 对象和XMLXML格式的数据。data binding supports data in the form of CLR objects and XMLXML. 若要提供一些示例, 绑定源可以是UIElement、任何列表对象、与 ADO.NET 数据或 Web 服务关联的 CLR 对象, 也可以是XMLXML包含数据的 XmlNode。To provide some examples, your binding source may be a UIElement, any list object, a CLR object that is associated with ADO.NET data or Web Services, or an XmlNode that contains your XMLXML data. 有关详细信息,请参阅绑定源概述For more information, see Binding Sources Overview.

当你通读其他 SDK 主题时, 请务必记住, 在建立绑定时, 将绑定目标绑定绑定源。As you read through other SDK topics, it is important to remember that when you are establishing a binding, you are binding a binding target to a binding source. 例如, 如果ListBox使用数据绑定显示某些基础XMLXML数据ListBox , 则XMLXML会将绑定到数据。For example, if you are displaying some underlying XMLXML data in a ListBox using data binding, you are binding your ListBox to the XMLXML data.

若要建立绑定, 请使用Binding对象。To establish a binding, you use the Binding object. 本主题的其余部分讨论与相关联的许多概念以及Binding对象的一些属性和用法。The rest of this topic discusses many of the concepts associated with and some of the properties and usage of the Binding object.

数据流的方向Direction of the Data Flow

如前所述, 如上图中的箭头所示, 绑定的数据流可以从绑定目标传输到绑定源 (例如, 当用户编辑的TextBox值时, 源值将更改) 和/或从绑定源如果绑定源提供了正确的通知, TextBox则为绑定目标 (例如, 内容会更新到绑定源中的更改)。As mentioned previously and as indicated by the arrow in the figure above, the data flow of a binding can go from the binding target to the binding source (for example, the source value changes when a user edits the value of a TextBox) and/or from the binding source to the binding target (for example, your TextBox content gets updated with changes in the binding source) if the binding source provides the proper notifications.

可能希望应用程序允许用户更改数据,然后将该数据传播回源对象。You may want your application to enable users to change the data and propagate it back to the source object. 或者,可能不希望允许用户更新源数据。Or you may not want to enable users to update the source data. 可以通过设置Binding对象的属性对Mode此进行控制。You can control this by setting the Mode property of your Binding object. 下图演示了不同类型的数据流:The following figure illustrates the different types of data flow:

数据绑定数据流Data binding data flow

  • OneWay绑定会导致对源属性的更改自动更新目标属性, 但对目标属性所做的更改不会传播回 source 属性。OneWay binding causes changes to the source property to automatically update the target property, but changes to the target property are not propagated back to the source property. 如果绑定的控件为隐式只读,则此类型的绑定适用。This type of binding is appropriate if the control being bound is implicitly read-only. 例如,可能绑定到如股票行情自动收录器这样的源,或许目标属性没有用于进行更改的控件接口(如表的数据绑定背景色)。For instance, you may bind to a source such as a stock ticker or perhaps your target property has no control interface provided for making changes, such as a data-bound background color of a table. 如果无需监视目标属性的更改,则使用 OneWay 绑定模式可避免 TwoWay 绑定模式的系统开销。If there is no need to monitor the changes of the target property, using the OneWay binding mode avoids the overhead of the TwoWay binding mode.

  • TwoWay绑定会导致对源属性或目标属性的更改自动更新。TwoWay binding causes changes to either the source property or the target property to automatically update the other. 此类型的绑定适用于可编辑窗体或其他完整交互式的 UIUI 方案。This type of binding is appropriate for editable forms or other fully-interactive UIUI scenarios. 大多数属性默认为OneWay绑定, 但某些依赖属性 (通常是用户可编辑控件的属性TextBox , 例如Text的属性和IsChecked的属性CheckBox) 默认为TwoWay绑定。Most properties default to OneWay binding, but some dependency properties (typically properties of user-editable controls such as the Text property of TextBox and the IsChecked property of CheckBox) default to TwoWay binding. 确定依赖属性绑定在默认情况下是单向还是双向的编程方法是:使用 GetMetadata 获取属性的属性元数据,然后检查 BindsTwoWayByDefault 属性的布尔值。A programmatic way to determine whether a dependency property binds one-way or two-way by default is to get the property metadata of the property using GetMetadata and then check the Boolean value of the BindsTwoWayByDefault property.

  • OneWayToSource是反向OneWay绑定; 当目标属性发生更改时, 它将更新源属性。OneWayToSource is the reverse of OneWay binding; it updates the source property when the target property changes. 一个示例方案是只需要从 UIUI 重新计算源值的情况。One example scenario is if you only need to re-evaluate the source value from the UIUI.

  • 图中未说明OneTime绑定, 这会导致源属性初始化目标属性, 但后续更改不会传播。Not illustrated in the figure is OneTime binding, which causes the source property to initialize the target property, but subsequent changes do not propagate. 这意味着,如果数据上下文发生了更改,或者数据上下文中的对象发生了更改,该更改不会反映在目标属性中。This means that if the data context undergoes a change or the object in the data context changes, then the change is not reflected in the target property. 如果你在适合使用当前状态的快照或数据实际为静态数据的位置使用数据,则此类型的绑定适合。This type of binding is appropriate if you are using data where either a snapshot of the current state is appropriate to use or the data is truly static. 如果你想使用源属性中的某个值来初始化目标属性,且提前不知道数据上下文,则此类型的绑定也有用。This type of binding is also useful if you want to initialize your target property with some value from a source property and the data context is not known in advance. 这是实质上是 OneWay 绑定的一种简化形式,它在源值不更改的情况下提供更好的性能。This is essentially a simpler form of OneWay binding that provides better performance in cases where the source value does not change.

请注意, 若要检测源更改 ( OneWay适用TwoWay于和绑定), 源必须实现适当的属性INotifyPropertyChanged更改通知机制, 例如。Note that to detect source changes (applicable to OneWay and TwoWay bindings), the source must implement a suitable property change notification mechanism such as INotifyPropertyChanged. 有关INotifyPropertyChanged实现的示例, 请参阅实现属性更改通知See Implement Property Change Notification for an example of an INotifyPropertyChanged implementation.

Mode属性页提供了有关绑定模式的详细信息, 以及如何指定绑定方向的示例。The Mode property page provides more information about binding modes and an example of how to specify the direction of a binding.

触发源更新的因素What Triggers Source Updates

作为TwoWayOneWayToSource侦听目标属性中的更改并将其传播回源的绑定。Bindings that are TwoWay or OneWayToSource listen for changes in the target property and propagate them back to the source. 这称为更新源。This is known as updating the source. 例如,可以编辑文本框的文本以更改基础源值。For example, you may edit the text of a TextBox to change the underlying source value. 如最后一部分所述, 数据流的方向由绑定的Mode属性值决定。As described in the last section, the direction of the data flow is determined by the value of the Mode property of the binding.

但是,源值是在编辑文本的同时进行更新,还是在结束编辑文本并将鼠标指针从文本框移走后才进行更新呢?However, does your source value get updated while you are editing the text or after you finish editing the text and point your mouse away from the TextBox? 绑定UpdateSourceTrigger的属性确定源更新的触发因素。The UpdateSourceTrigger property of the binding determines what triggers the update of the source. 下图中右箭头的点说明了UpdateSourceTrigger属性的角色:The dots of the right arrows in the following figure illustrate the role of the UpdateSourceTrigger property:

显示 System.windows.data.binding.updatesourcetrigger 属性的角色的关系图。

如果值为PropertyChanged, 则TwoWayOneWayToSource的右箭头指向的值将在目标属性更改后立即更新。 UpdateSourceTriggerIf the UpdateSourceTrigger value is PropertyChanged, then the value pointed to by the right arrow of TwoWay or the OneWayToSource bindings gets updated as soon as the target property changes. 但是, 如果UpdateSourceTrigger该值为, LostFocus则只有当目标属性失去焦点时, 该值才会更新为新值。However, if the UpdateSourceTrigger value is LostFocus, then that value only gets updated with the new value when the target property loses focus.

与属性类似, 不同的依赖属性具有不同的UpdateSourceTrigger默认值。 ModeSimilar to the Mode property, different dependency properties have different default UpdateSourceTrigger values. 大多数依赖属性的默认值为 PropertyChanged,而 Text 属性的默认值为 LostFocusThe default value for most dependency properties is PropertyChanged, while the Text property has a default value of LostFocus. 这意味着, 当目标属性发生更改时, 通常会发生源更新, 这CheckBox对于 es 和其他简单控件来说是很不错的。This means that source updates usually happen whenever the target property changes, which is fine for CheckBoxes and other simple controls. 但对于文本字段,每次击键之后都进行更新会降低性能,用户也没有机会在提交新值之前使用 Backspace 键修改键入错误。However, for text fields, updating after every keystroke can diminish performance and it denies the user the usual opportunity to backspace and fix typing errors before committing to the new value. 这就是为什么Text属性具有默认LostFocus值而不是的PropertyChanged原因。That is why the Text property has a default value of LostFocus instead of PropertyChanged.

有关如何查找依赖属性的默认UpdateSourceTrigger值的信息, 请参阅属性页。UpdateSourceTriggerSee the UpdateSourceTrigger property page for information about how to find the default UpdateSourceTrigger value of a dependency property.

下表提供了UpdateSourceTrigger TextBox使用作为示例的每个值的示例方案:The following table provides an example scenario for each UpdateSourceTrigger value using the TextBox as an example:

UpdateSourceTrigger 值UpdateSourceTrigger value 源值何时进行更新When the Source Value Gets Updated 文本框的示例方案Example Scenario for TextBox
LostFocus (默认值TextBox.Text)LostFocus (default for TextBox.Text) 当 TextBox 控件失去焦点时When the TextBox control loses focus TextBox与验证逻辑关联的 (请参阅 "数据验证" 一节)A TextBox that is associated with validation logic (see Data Validation section)
PropertyChangedPropertyChanged 当你键入TextBoxAs you type into the TextBox TextBox聊天室窗口中的控件TextBox controls in a chat room window
ExplicitExplicit 当应用程序调用UpdateSourceWhen the application calls UpdateSource TextBox可编辑窗体中的控件 (仅当用户单击 "提交" 按钮时才更新源值)TextBox controls in an editable form (updates the source values only when the user clicks the submit button)

有关示例,请参阅控制文本框文本更新源的时间For an example, see Control When the TextBox Text Updates the Source.

创建绑定Creating a Binding

若要 recapitulate 前面几节中讨论的一些概念, 请使用Binding对象建立绑定, 每个绑定通常具有四个组件: 绑定目标、目标属性、绑定源和要使用的源值的路径。To recapitulate some of the concepts discussed in the previous sections, you establish a binding using the Binding object, and each binding usually has four components: binding target, target property, binding source, and a path to the source value to use. 本节讨论如何设置绑定。This section discusses how to set up a binding.

请考虑以下示例,其中的绑定源对象是一个名为 MyData 的类,该类在 SDKSample 命名空间中定义。Consider the following example, in which the binding source object is a class named MyData that is defined in the SDKSample namespace. 出于演示目的,MyData 类具有一个名为 ColorName 的字符串属性,该属性的值设置为“Red”。For demonstration purposes, MyData class has a string property named ColorName, of which the value is set to "Red". 因此,此示例生成一个具有红色背景的按钮。Thus, this example generates a button with a red background.

    <c:MyData x:Key="myDataSource"/>
    <Binding Source="{StaticResource myDataSource}"/>
  <Button Background="{Binding Path=ColorName}"
          Width="150" Height="30">I am bound to be RED!</Button>

有关绑定声明语法的详细信息以及如何在代码中设置绑定的示例,请参阅绑定声明概述For more details on the binding declaration syntax and for examples of how to set up a binding in code, see Binding Declarations Overview.

如果将此示例应用于基本关系图,则生成的图如下所示。If we apply this example to our basic diagram, the resulting figure looks like the following. 这是一个OneWay绑定, 因为默认情况下OneWay , 该后台属性支持绑定。This is a OneWay binding because the Background property supports OneWay binding by default.


尽管ColorName属性的类型为字符串Background , 但该属性的类型Brush为, 但你可能想知道为什么此操作有效。You may wonder why this works even though the ColorName property is of type string while the Background property is of type Brush. 这是由于进行了默认类型转换,此类型转换在数据转换一节中进行讨论。This is default type conversion at work and is discussed in the Data Conversion section.

指定绑定源Specifying the Binding Source

请注意, 在上面的示例中, 通过在DataContext DockPanel元素上设置属性来指定绑定源。Notice that in the previous example, the binding source is specified by setting the DataContext property on the DockPanel element. 然后从中继承DataContext值,该值是其父元素。DockPanel ButtonThe Button then inherits the DataContext value from the DockPanel, which is its parent element. 重申一下,绑定源对象是绑定的四个必需组件之一。To reiterate, the binding source object is one of the four necessary components of a binding. 因此,如果未指定绑定源对象,则绑定将没有任何作用。Therefore, without the binding source object being specified, the binding would do nothing.

可通过多种方法指定绑定源对象。There are several ways to specify the binding source object. 将多个属性绑定到同一个源时, 对父元素使用属性非常有用。DataContextUsing the DataContext property on a parent element is useful when you are binding multiple properties to the same source. 不过,有时在个别绑定声明中指定绑定源可能更为合适。However, sometimes it may be more appropriate to specify the binding source on individual binding declarations. 对于前面的示例, DataContext可以通过直接在按钮的绑定声明上Source设置属性来指定绑定源, 如以下示例中所示:For the previous example, instead of using the DataContext property, you can specify the binding source by setting the Source property directly on the binding declaration of the button, as in the following example:

  <c:MyData x:Key="myDataSource"/>
<Button Width="150" Height="30"
        Background="{Binding Source={StaticResource myDataSource},
                             Path=ColorName}">I am bound to be RED!</Button>

除了直接在元素DataContext上设置属性, 还会从祖先DataContext继承值 (如第一个示例中的按钮), 并通过设置中的Source属性显式指定绑定源。Binding(如最后一个示例中的按钮), 也可以使用ElementName属性RelativeSource或属性来指定绑定源。Other than setting the DataContext property on an element directly, inheriting the DataContext value from an ancestor (such as the button in the first example), and explicitly specifying the binding source by setting the Source property on the Binding (such as the button the last example), you can also use the ElementName property or the RelativeSource property to specify the binding source. 如果要绑定到应用程序中的其他元素 (例如, 当使用滑块调整按钮的宽度时),属性会很有用。ElementNameThe ElementName property is useful when you are binding to other elements in your application, such as when you are using a slider to adjust the width of a button. 如果RelativeSource 在或Style中指定了绑定, 则属性很有用。 ControlTemplateThe RelativeSource property is useful when the binding is specified in a ControlTemplate or a Style. 有关详细信息,请参阅指定绑定源For more information, see Specify the Binding Source.

指定值的路径Specifying the Path to the Value

如果绑定源是一个对象, 则可以使用Path属性来指定要用于绑定的值。If your binding source is an object, you use the Path property to specify the value to use for your binding. 如果要绑定到XMLXML数据, 请XPath使用属性指定值。If you are binding to XMLXML data, you use the XPath property to specify the value. 在某些情况下, 即使在您的数据为Path XMLXML时也可能会使用属性。In some cases, it may be applicable to use the Path property even when your data is XMLXML. 例如, 如果想要访问返回的 XmlNode 的 Name 属性 (作为 XPath 查询的结果), 则应使用Path属性以及XPath属性。For example, if you want to access the Name property of a returned XmlNode (as a result of an XPath query), you should use the Path property in addition to the XPath property.

有关语法信息和示例, 请参见PathXPath属性页。For syntax information and examples, see the Path and XPath property pages.

请注意, 尽管我们已经强调Path , 要使用的值是绑定的四个必需组件之一, 但在要绑定到整个对象的情况下, 要使用的值将与绑定源对象的值相同。Note that although we have emphasized that the Path to the value to use is one of the four necessary components of a binding, in the scenarios which you want to bind to an entire object, the value to use would be the same as the binding source object. 在这些情况下, 它适用于不指定PathIn those cases, it is applicable to not specify a Path. 请看下面的示例:Consider the following example:

<ListBox ItemsSource="{Binding}"

以上示例使用空绑定语法:{Binding}。The above example uses the empty binding syntax: {Binding}. 在这种情况下ListBox , 将从父 system.windows.controls.dockpanel> 元素继承 DataContext (在本示例中未显示)。In this case, the ListBox inherits the DataContext from a parent DockPanel element (not shown in this example). 未指定路径时,默认为绑定到整个对象。When the path is not specified, the default is to bind to the entire object. 换句话说, 在此示例中, 路径已被省略, 因为我们要将ItemsSource属性绑定到整个对象。In other words, in this example, the path has been left out because we are binding the ItemsSource property to the entire object. (有关深入讨论,请参阅绑定到集合一节。)(See the Binding to Collections section for an in-depth discussion.)

除了绑定到集合以外,在希望绑定到整个对象,而不是仅绑定到对象的单个属性时,也可以使用此方案。Other than binding to a collection, this scenario is also useful when you want to bind to an entire object instead of just a single property of an object. 例如,在源对象为类型字符串,并且仅仅希望绑定到该字符串本身时。For example, if your source object is of type string and you simply want to bind to the string itself. 另一种常见情况是希望将一个元素绑定到一个具有多个属性的对象。Another common scenario is when you want to bind an element to an object with several properties.

请注意,可能需要应用自定义逻辑,以便数据对于绑定的目标属性有意义。Note that you may need to apply custom logic so that the data is meaningful to your bound target property. 自定义逻辑可能采用自定义转换器形式(如果不存在默认的类型转换)。The custom logic may be in the form of a custom converter (if default type conversion does not exist). 有关转换器的信息,请参阅数据转换See Data Conversion for information about converters.

Binding 和 BindingExpressionBinding and BindingExpression

在进入数据绑定的其他功能和用法之前, 引入BindingExpression类将十分有用。Before getting into other features and usages of data binding, it would be useful to introduce the BindingExpression class. 正如您在前面的Binding部分中所示, 类是绑定声明的高级类Binding ; 类提供了许多允许您指定绑定特性的属性。As you have seen in previous sections, the Binding class is the high-level class for the declaration of a binding; the Binding class provides many properties that allow you to specify the characteristics of a binding. 相关类BindingExpression是维护源与目标之间的连接的基础对象。A related class, BindingExpression, is the underlying object that maintains the connection between the source and the target. 一个绑定包含了可以在多个绑定表达式之间共享的所有信息。A binding contains all the information that can be shared across several binding expressions. 是无法共享的实例表达式, 它包含的所有实例信息BindingBindingExpressionA BindingExpression is an instance expression that cannot be shared and contains all the instance information of the Binding.

例如, 请考虑以下情况, 其中myDataObjectMyData类的实例, myBinding是源Binding对象, MyData类是包含名为MyDataPropertyFor example, consider the following, where myDataObject is an instance of MyData class, myBinding is the source Binding object, and MyData class is a defined class that contains a string property named MyDataProperty. 此示例将mytext(实例TextBlock) 的文本内容绑定到MyDataPropertyThis example binds the text content of mytext, an instance of TextBlock, to MyDataProperty.

// Make a new source.
MyData myDataObject = new MyData(DateTime.Now);      
Binding myBinding = new Binding("MyDataProperty");
myBinding.Source = myDataObject;
// Bind the new data source to the myText TextBlock control's Text dependency property.
myText.SetBinding(TextBlock.TextProperty, myBinding);
' Make a new source.
Dim data1 As New MyData(DateTime.Now)
Dim binding1 As New Binding("MyDataProperty")
binding1.Source = data1
' Bind the new data source to the myText TextBlock control's Text dependency property.
Me.myText.SetBinding(TextBlock.TextProperty, binding1)

可以使用同一 myBinding 对象来创建其他绑定。You can use the same myBinding object to create other bindings. 例如,可以使用 myBinding 对象将复选框的文本内容绑定到 MyDataPropertyFor example, you may use myBinding object to bind the text content of a check box to MyDataProperty. 在这种情况下, 将有两个BindingExpression共享myBinding对象的实例。In that scenario, there will be two instances of BindingExpression sharing the myBinding object.

可以通过对数据绑定对象调用GetBindingExpression的返回值来获取对象。BindingExpressionA BindingExpression object can be obtained through the return value of calling GetBindingExpression on a data-bound object. 以下主题演示了BindingExpression类的一些用法:The following topics demonstrate some of the usages of the BindingExpression class:

数据转换Data Conversion

在上面的示例中, 按钮是红色的, Background因为其属性已绑定到值为 "red" 的字符串属性。In the previous example, the button is red because its Background property is bound to a string property with the value "Red". 这是因为类型转换器在Brush类型上存在, 以将字符串值转换Brush为。This works because a type converter is present on the Brush type to convert the string value to a Brush.

若要将此信息添加到创建绑定一节的图中,关系图如下所示:To add this information to the figure in the Creating a Binding section, the diagram looks like the following:


但是, 如果绑定源对象的颜色属性Color不是字符串类型, 则会发生什么情况呢?However, what if instead of having a property of type string your binding source object has a Color property of type Color? 在这种情况下, 为了使绑定正常工作, 需要首先将颜色属性值转换为Background属性接受的内容。In that case, in order for the binding to work you would need to first turn the Color property value into something that the Background property accepts. 需要通过实现IValueConverter接口来创建自定义转换器, 如以下示例中所示:You would need to create a custom converter by implementing the IValueConverter interface, as in the following example:

[ValueConversion(typeof(Color), typeof(SolidColorBrush))]
public class ColorBrushConverter : IValueConverter
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        Color color = (Color)value;
        return new SolidColorBrush(color);

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        return null;
<ValueConversion(GetType(Color), GetType(SolidColorBrush))>
Public Class ColorBrushConverter
    Implements IValueConverter
    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
        Dim color As Color = CType(value, Color)
        Return New SolidColorBrush(color)
    End Function

    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
        Return Nothing
    End Function
End Class

IValueConverter参考页提供了详细信息。The IValueConverter reference page provides more information.

现在使用自定义转换器而不是默认转换,关系图如下所示:Now the custom converter is used instead of default conversion, and our diagram looks like this:


重申一下,由于要绑定到的类型中提供了类型转换器,因此可以使用默认转换。To reiterate, default conversions may be available because of type converters that are present in the type being bound to. 此行为取决于目标中可用的类型转换器。This behavior will depend on which type converters are available in the target. 如果无法确定,请创建自己的转换器。If in doubt, create your own converter.

下面提供了一些典型方案,在这些方案中,实现数据转换器非常有意义:Following are some typical scenarios where it makes sense to implement a data converter:

  • 数据应根据区域性以不同方式显示。Your data should be displayed differently, depending on culture. 例如,可能需要根据在特定区域性中使用的值或标准,实现货币转换器或日历日期/时间转换器。For instance, you might want to implement a currency converter or a calendar date/time converter based on the values or standards used in a particular culture.

  • 使用的数据不一定会更改属性的文本值,但会更改其他某个值(如图像的源,或显示文本的颜色或样式)。The data being used is not necessarily intended to change the text value of a property, but is instead intended to change some other value, such as the source for an image, or the color or style of the display text. 在这种情况下,可以通过转换可能不合适的属性绑定(如将文本字段绑定到表单元格的 Background 属性)来使用转换器。Converters can be used in this instance by converting the binding of a property that might not seem to be appropriate, such as binding a text field to the Background property of a table cell.

  • 将多个控件或控件的多个属性绑定到相同数据。More than one control or to multiple properties of controls are bound to the same data. 在这种情况下,主绑定可能仅显示文本,而其他绑定则处理特定的显示问题,但仍使用同一绑定作为源信息。In this case, the primary binding might just display the text, whereas other bindings handle specific display issues but still use the same binding as source information.

  • 到目前为止, 我们尚未讨论MultiBinding, 其中目标属性具有绑定的集合。So far we have not yet discussed MultiBinding, where a target property has a collection of bindings. 对于MultiBinding, 你可以使用自定义IMultiValueConverter从绑定值生成最终值。In the case of a MultiBinding, you use a custom IMultiValueConverter to produce a final value from the values of the bindings. 例如,可以从红色、蓝色和绿色的值来计算颜色,这些值可能来自相同绑定源对象,也可能来自不同绑定源对象。For example, color may be computed from red, blue, and green values, which can be values from the same or different binding source objects. 有关示例和信息, 请参阅类页。MultiBindingSee the MultiBinding class page for examples and information.

绑定到集合Binding to Collections

绑定源对象可以视为其属性包含数据的单个对象,也可以视为通常组合在一起的多态对象的数据集合(如数据库的查询结果)。A binding source object can be treated either as a single object of which the properties contain data or as a data collection of polymorphic objects that are often grouped together (such as the result of a query to a database). 到目前为止,我们仅讨论了绑定到单个对象,但绑定到数据集合才是一种常见方案。So far we've only discussed binding to single objects, however, binding to a data collection is a common scenario. 例如, 一种常见ItemsControl方案是使用ListBoxListViewTreeView来显示数据集合, 如在什么是数据绑定?一节中显示的应用程序中。For example, a common scenario is to use an ItemsControl such as a ListBox, ListView, or TreeView to display a data collection, such as in the application shown in the What Is Data Binding? section.

幸运的是,基本关系图仍然适用。Fortunately, our basic diagram still applies. 如果要将绑定ItemsControl到集合, 关系图如下所示:If you are binding an ItemsControl to a collection, the diagram looks like this:

显示数据绑定 System.windows.controls.itemscontrol> 对象的关系图。

如图所示, 若要将绑定ItemsControl到集合对象, ItemsSource属性是要使用的属性。As shown in this diagram, to bind an ItemsControl to a collection object, ItemsSource property is the property to use. 可以ItemsSource将属性视为的内容ItemsControlYou can think of ItemsSource property as the content of the ItemsControl. 请注意, 此绑定OneWay是因为ItemsSource默认情况OneWay下, 该属性支持绑定。Note that the binding is OneWay because the ItemsSource property supports OneWay binding by default.

如何实现集合How to Implement Collections

可以枚举实现IEnumerable接口的任何集合。You can enumerate over any collection that implements the IEnumerable interface. 但是, 若要设置动态绑定, 以便集合中的插入或删除操作UIUI自动更新, 该集合必须INotifyCollectionChanged实现接口。However, to set up dynamic bindings so that insertions or deletions in the collection update the UIUI automatically, the collection must implement the INotifyCollectionChanged interface. 此接口公开一个事件,只要基础集合发生更改,就应该引发该事件。This interface exposes an event that should be raised whenever the underlying collection changes.

WPFWPF提供类, 该类是INotifyCollectionChanged公开接口的数据集合的内置实现。 ObservableCollection<T>provides the ObservableCollection<T> class, which is a built-in implementation of a data collection that exposes the INotifyCollectionChanged interface. 请注意, 若要完全支持将数据值从源对象传输到目标, 则支持可绑定属性的集合中的每个INotifyPropertyChanged对象还必须实现接口。Note that to fully support transferring data values from source objects to targets, each object in your collection that supports bindable properties must also implement the INotifyPropertyChanged interface. 有关详细信息,请参阅绑定源概述For more information, see Binding Sources Overview.

在实现自己的集合之前, 请ObservableCollection<T>考虑使用或一个现有的集合类, List<T>例如、 Collection<T>BindingList<T>Before implementing your own collection, consider using ObservableCollection<T> or one of the existing collection classes, such as List<T>, Collection<T>, and BindingList<T>, among many others. 如果你有一个高级方案, 并且想要实现自己的集合, 请IList考虑使用, 它提供了一个对象的非泛型集合, 该集合可按索引单独访问, 从而获得最佳性能。If you have an advanced scenario and want to implement your own collection, consider using IList, which provides a non-generic collection of objects that can be individually accessed by index and thus the best performance.

集合视图Collection Views

ItemsControl将绑定到数据集合后, 您可能需要对数据进行排序、筛选或分组。Once your ItemsControl is bound to a data collection, you may want to sort, filter, or group the data. 为此, 需要使用集合视图, 这些视图是实现ICollectionView接口的类。To do that, you use collection views, which are classes that implement the ICollectionView interface.

什么是集合视图?What Are Collection Views?

集合视图这一层基于绑定源集合,它允许基于排序、筛选和分组查询来导航并显示源集合,而无需更改基础源集合本身。A collection view is a layer on top of a binding source collection that allows you to navigate and display the source collection based on sort, filter, and group queries, without having to change the underlying source collection itself. 集合视图还维护一个指向集合中当前项的指针。A collection view also maintains a pointer to the current item in the collection. 如果源集合实现了INotifyCollectionChanged接口, 则会将CollectionChanged事件引发的更改传播到视图。If the source collection implements the INotifyCollectionChanged interface, the changes raised by the CollectionChanged event are propagated to the views.

由于视图不会更改基础源集合,因此每个源集合都可以有多个关联的视图。Because views do not change the underlying source collections, each source collection can have multiple views associated with it. 例如,可以有 Task 对象的集合。For example, you may have a collection of Task objects. 使用视图,可以通过不同方式显示相同数据。With the use of views, you can display that same data in different ways. 例如,可能希望在页面左侧显示按优先级排序的任务,而在页面右侧显示按区域分组的任务。For example, on the left side of your page you may want to show tasks sorted by priority, and on the right side, grouped by area.

如何创建视图How to Create a View

创建并使用视图的一种方式是直接实例化视图对象,然后将它用作绑定源。One way to create and use a view is to instantiate the view object directly and then use it as the binding source. 例如,请考虑在什么是数据绑定?一节中显示的数据绑定演示应用程序。For example, consider the Data Binding Demo application shown in the What Is Data Binding? section. 实现应用程序, 以便在ListBox数据集合而不是直接对数据集合绑定到视图。The application is implemented such that the ListBox binds to a view over the data collection instead of the data collection directly. 下面的示例摘自数据绑定演示应用程序。The following example is extracted from the Data Binding Demo application. 类是继承自CollectionView的类的代理。可扩展应用程序标记语言 (XAML)Extensible Application Markup Language (XAML) CollectionViewSourceThe CollectionViewSource class is the 可扩展应用程序标记语言 (XAML)Extensible Application Markup Language (XAML) proxy of a class that inherits from CollectionView. 在此特定示例中, Source视图的绑定到当前应用程序对象的AuctionItems集合 ( ObservableCollection<T>类型为)。In this particular example, the Source of the view is bound to the AuctionItems collection (of type ObservableCollection<T>) of the current application object.

      Source="{Binding Source={x:Static Application.Current}, Path=AuctionItems}"   
      x:Key="listingDataView" />

然后, 资源listingDataView充当应用程序中的元素的绑定源, 例如ListBox:The resource listingDataView then serves as the binding source for elements in the application, such as the ListBox:

<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8"
    ItemsSource="{Binding Source={StaticResource listingDataView}}">

若要为同一集合创建另一个视图, 可以创建另CollectionViewSource一个实例, 并为其x:Key指定一个不同的名称。To create another view for the same collection, you can create another CollectionViewSource instance and give it a different x:Key name.

下表显示了将哪些视图数据类型创建为默认集合视图或CollectionViewSource基于源集合类型。The following table shows which view data types are created as the default collection view or by CollectionViewSource based on the source collection type.

源集合类型Source collection type 集合视图类型Collection view type 说明Notes
IEnumerable 基于的内部类型CollectionViewAn internal type based on CollectionView 无法对项进行分组。Cannot group items.
IList ListCollectionView 最快。Fastest.
IBindingList BindingListCollectionView
使用默认视图Using a Default View

创建并使用集合视图的一种方式是指定集合视图作为绑定源。Specifying a collection view as a binding source is one way to create and use a collection view. WPF 还会为用作绑定源的每个集合创建一个默认集合视图。WPF also creates a default collection view for every collection used as a binding source. 如果直接绑定到集合,WPF 会绑定到该集合的默认视图。If you bind directly to a collection, WPF binds to its default view. 请注意,此默认视图由同一集合的所有绑定共享,因此一个绑定控件或代码对默认视图所做的更改(如排序或对当前项指针的更改,下文将对此进行讨论)会反映到同一集合的所有其他绑定中。Note that this default view is shared by all bindings to the same collection, so a change made to a default view by one bound control or code (such as sorting or a change to the current item pointer, discussed later) is reflected in all other bindings to the same collection.

若要获取默认视图, 请使用GetDefaultView方法。To get the default view, you use the GetDefaultView method. 有关示例,请参阅获取数据集合的默认视图For an example, see Get the Default View of a Data Collection.

包含 ADO.NET DataTables 的集合视图Collection Views with ADO.NET DataTables

为了提高性能, ADO.NET DataTableDataView对象的集合视图将对DataView进行排序和筛选。To improve performance, collection views for ADO.NET DataTable or DataView objects delegate sorting and filtering to the DataView. 这会导致排序和筛选任务由数据源的所有集合视图分担。This causes sorting and filtering to be shared across all collection views of the data source. 若要使每个集合视图分别进行排序和筛选, 请使用其自己DataView的对象初始化每个集合视图。To enable each collection view to sort and filter independently, initialize each collection view with its own DataView object.


如前所述,视图可以将排序顺序应用于集合。As mentioned before, views can apply a sort order to a collection. 如同在基础集合中一样,数据可能具有或不具有相关的固有顺序。As it exists in the underlying collection, your data may or may not have a relevant, inherent order. 借助集合视图,可以根据自己提供的比较条件来强制确定顺序,或更改默认顺序。The view over the collection allows you to impose an order, or change the default order, based on comparison criteria that you supply. 由于这是基于客户端的数据视图,因此一种常见情况是用户可能希望根据列对应的值,对多列表格数据进行排序。Because it is a client-based view of the data, a common scenario is that the user might want to sort columns of tabular data per the value that the column corresponds to. 通过使用视图,可以应用这种用户实施的排序,而无需对基础集合进行任何更改,甚至不必再次查询集合内容。Using views, this user-driven sort can be applied, again without making any changes to the underlying collection or even having to requery for the collection content. 有关示例,请参阅在单击标题时对 GridView 列进行排序For an example, see Sort a GridView Column When a Header Is Clicked.

下面的示例演示了 "什么是数据绑定? " 一节中的CheckBox "按类别UIUI和日期排序" 应用程序的排序逻辑:The following example shows the sorting logic of the "Sort by category and date" CheckBox of the application UIUI in the What Is Data Binding? section:

private void AddSorting(object sender, RoutedEventArgs args)
    // This sorts the items first by Category and within each Category,
    // by StartDate. Notice that because Category is an enumeration,
    // the order of the items is the same as in the enumeration declaration
        new SortDescription("Category", ListSortDirection.Ascending));
        new SortDescription("StartDate", ListSortDirection.Ascending));
Private Sub AddSorting(ByVal sender As Object, ByVal args As RoutedEventArgs)
    'This sorts the items first by Category and within each Category, by StartDate
    'Notice that because Category is an enumeration, the order of the items is the same as in the 
    'enumeration declaration
    listingDataView.SortDescriptions.Add(New SortDescription("Category", ListSortDirection.Ascending))
    listingDataView.SortDescriptions.Add(New SortDescription("StartDate", ListSortDirection.Ascending))
End Sub


视图还可以将筛选器应用于集合。Views can also apply a filter to a collection. 这意味着即使集合中可能存在一个项,此特定视图也仅用于显示整个集合的某个子集。This means that although an item might exist in the collection, this particular view is intended to show only a certain subset of the full collection. 可以根据条件在数据中进行筛选。You might filter on a condition in the data. 例如, 当应用程序在什么是数据绑定?一节中完成, "仅显示 bargains" CheckBox包含用于筛选出成本 $25 或更高的项的逻辑。For instance, as is done by the application in the What Is Data Binding? section, the "Show only bargains" CheckBox contains logic to filter out items that cost $25 or more. 选择以下代码时CheckBox , 将ShowOnlyBargainsFilter Filter设置为事件处理程序:The following code is executed to set ShowOnlyBargainsFilter as the Filter event handler when that CheckBox is selected:

listingDataView.Filter += new FilterEventHandler(ShowOnlyBargainsFilter);
AddHandler listingDataView.Filter, AddressOf ShowOnlyBargainsFilter

ShowOnlyBargainsFilter 事件处理程序具有以下实现:The ShowOnlyBargainsFilter event handler has the following implementation:

private void ShowOnlyBargainsFilter(object sender, FilterEventArgs e)
    AuctionItem product = e.Item as AuctionItem;
    if (product != null)
        // Filter out products with price 25 or above
        if (product.CurrentPrice < 25)
            e.Accepted = true;
            e.Accepted = false;
Private Sub ShowOnlyBargainsFilter(ByVal sender As Object, ByVal e As FilterEventArgs)
    Dim product As AuctionItem = CType(e.Item, AuctionItem)
    If Not (product Is Nothing) Then
        'Filter out products with price 25 or above
        If product.CurrentPrice < 25 Then
            e.Accepted = True
            e.Accepted = False
        End If
    End If
End Sub

如果直接使用某个CollectionViewCollectionViewSource而不是Filter , 则可以使用属性来指定回调。If you are using one of the CollectionView classes directly instead of CollectionViewSource, you would use the Filter property to specify a callback. 有关示例,请参阅筛选视图中的数据For an example, see Filter Data in a View.


除查看IEnumerable集合的内部类之外, 所有集合视图都支持分组功能, 这允许用户将集合视图中的集合分区为逻辑组。Except for the internal class that views an IEnumerable collection, all collection views support the functionality of grouping, which allows the user to partition the collection in the collection view into logical groups. 这些组可以是显式的,由用户提供组列表;也可以是隐式的,这些组依据数据动态生成。The groups can be explicit, where the user supplies a list of groups, or implicit, where the groups are generated dynamically depending on the data.

下面的示例显示 "Group by category" CheckBox的逻辑:The following example shows the logic of the "Group by category" CheckBox:

// This groups the items in the view by the property "Category"
PropertyGroupDescription groupDescription = new PropertyGroupDescription();
groupDescription.PropertyName = "Category";
'This groups by property "Category"
Dim groupDescription As PropertyGroupDescription = New PropertyGroupDescription
groupDescription.PropertyName = "Category"

有关其他分组示例,请参阅对实现 GridView 的 ListView 中的项进行分组For another grouping example, see Group Items in a ListView That Implements a GridView.

当前项指针Current Item Pointers

视图还支持当前项的概念。Views also support the notion of a current item. 可以在集合视图中的对象之间导航。You can navigate through the objects in a collection view. 在导航时,你是在移动项指针,该指针可用于检索存在于集合中特定位置的对象。As you navigate, you are moving an item pointer that allows you to retrieve the object that exists at that particular location in the collection. 有关示例,请参阅在数据集合视图中的对象之间导航For an example, see Navigate Through the Objects in a Data CollectionView.

由于 WPF 只通过使用视图(你指定的视图或集合的默认视图)绑定到集合,因此集合的所有绑定都有一个当前项指针。Because WPF binds to a collection only by using a view (either a view you specify, or the collection's default view), all bindings to collections have a current item pointer. 绑定到视图时,Path 值中的斜杠(“/”)字符用于指定视图的当前项。When binding to a view, the slash ("/") character in a Path value designates the current item of the view. 在下面的示例中,数据上下文是一个集合视图。In the following example, the data context is a collection view. 第一行绑定到集合。The first line binds to the collection. 第二行绑定到集合中的当前项。The second line binds to the current item in the collection. 第三行绑定到集合中当前项的 Description 属性。The third line binds to the Description property of the current item in the collection.

<Button Content="{Binding }" />  
<Button Content="{Binding Path=/}" />  
<Button Content="{Binding Path=/Description}" />   

还可以连着使用斜杠和属性语法以遍历集合的分层。The slash and property syntax can also be stacked to traverse a hierarchy of collections. 以下示例绑定到一个名为 Offices 的集合的当前项,此集合是源集合的当前项的属性。The following example binds to the current item of a collection named Offices, which is a property of the current item of the source collection.

<Button Content="{Binding /Offices/}" />  

当前项指针可能会受对集合应用的任何排序或筛选操作的影响。The current item pointer can be affected by any sorting or filtering that is applied to the collection. 排序操作将当前项指针保留在所选的最后一项上,但集合视图现已围绕此指针重构。Sorting preserves the current item pointer on the last item selected, but the collection view is now restructured around it. (或许所选项以前曾位于列表的开头,但现在所选项可能位于中间的某个位置。)如果所选内容在筛选之后保留在视图中,则筛选操作会保留所选项。(Perhaps the selected item was at the beginning of the list before, but now the selected item might be somewhere in the middle.) Filtering preserves the selected item if that selection remains in view after the filtering. 否则,当前项指针会设置为经过筛选的集合视图的第一项。Otherwise, the current item pointer is set to the first item of the filtered collection view.

主-从绑定方案Master-Detail Binding Scenario

当前项的概念不仅适用于集合中各项的导航,也适用于主-从绑定方案。The notion of a current item is useful not only for navigation of items in a collection, but also for the master-detail binding scenario. 再考虑一下什么是数据绑定?一节中的应用程序 UIUIConsider the application UIUI in the What Is Data Binding? section again. 在该应用程序中, 中ListBox的选择确定ContentControl中显示的内容。In that application, the selection within the ListBox determines the content shown in the ContentControl. 若要以另一种方式将其ListBox放在选定项时ContentControl , 将显示所选项的详细信息。To put it in another way, when a ListBox item is selected, the ContentControl shows the details of the selected item.

只需将两个或更多控件绑定到同一视图即可实现主-从方案。You can implement the master-detail scenario simply by having two or more controls bound to the same view. 以下来自数据绑定演示的示例显示ListBox了的标记, 以及ContentControl什么是数据绑定?UIUI节中的应用程序上看到的标记:The following example from the Data Binding Demo shows the markup of the ListBox and the ContentControl you see on the application UIUI in the What Is Data Binding? section:

<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8"
    ItemsSource="{Binding Source={StaticResource listingDataView}}">
<ContentControl Name="Detail" Grid.Row="3" Grid.ColumnSpan="3" 
        Content="{Binding Source={StaticResource listingDataView}}" 
        ContentTemplate="{StaticResource detailsProductListingTemplate}" 

请注意,这两个控件都绑定到同一个源,即 listingDataView 静态资源(请参阅如何创建视图一节中此资源的定义)。Notice that both of the controls are bound to the same source, the listingDataView static resource (see the definition of this resource in the How to Create a View section). 这是因为当单一实例对象 ( ContentControl在本例中为) 绑定到集合视图时, 它会自动绑定到该CurrentItem视图的。This works because when a singleton object (the ContentControl in this case) is bound to a collection view, it automatically binds to the CurrentItem of the view. 请注意CollectionViewSource , 对象会自动同步货币和选择。Note that CollectionViewSource objects automatically synchronize currency and selection. 如果列表控件未绑定到CollectionViewSource对象 (如本示例所示), 则需要将其IsSynchronizedWithCurrentItem属性设置为true , 以便此工作。If your list control is not bound to a CollectionViewSource object as in this example, then you would need to set its IsSynchronizedWithCurrentItem property to true for this to work.

有关其他示例,请参阅绑定到集合并基于选择显示信息对分层数据使用主-从模式For other examples, see Bind to a Collection and Display Information Based on Selection and Use the Master-Detail Pattern with Hierarchical Data.

你可能已经注意到上述示例使用了一个模板。You may have noticed that the above example uses a template. 事实上, 数据不会以我们所需的方式显示, 无需使用模板 (显式ContentControl使用的模板和ListBox由隐式使用的模板)。In fact, the data would not be displayed the way we wish without the use of templates (the one explicitly used by the ContentControl and the one implicitly used by the ListBox). 现在,我们开始介绍下一节中的数据模板化。We now turn to data templating in the next section.

数据模板化Data Templating

如果不使用数据模板,什么是数据绑定?一节中的应用程序 UIUI 将如下所示:Without the use of data templates, our application UIUI in the What Is Data Binding? section would look like the following:


如上一部分的示例中所示, ListBox控件ContentControl和都绑定到AuctionItems 的整个集合对象 (或更具体地说, 是集合对象上的视图)。As shown in the example in the previous section, both the ListBox control and the ContentControl are bound to the entire collection object (or more specifically, the view over the collection object) of AuctionItems. 如果没有关于如何显示数据集合的特定说明, ListBox将显示基础集合中每个对象的字符串表示形式, ContentControl并显示它所绑定到的对象的字符串表示形式。Without specific instructions of how to display the data collection, the ListBox is displaying a string representation of each object in the underlying collection and the ContentControl is displaying a string representation of the object it is bound to.

若要解决此问题, 应用程序DataTemplate将定义。To solve that problem, the application defines DataTemplates. 如上一部分的示例中所示, ContentControl显式使用detailsProductListingTemplateDataTemplateAs shown in the example in the previous section, the ContentControl explicitly uses the detailsProductListingTemplateDataTemplate. 显示ListBox集合中的AuctionItem对象DataTemplate时, 控件隐式使用以下内容:The ListBox control implicitly uses the following DataTemplate when displaying the AuctionItem objects in the collection:

<DataTemplate DataType="{x:Type src:AuctionItem}">
    <Border BorderThickness="1" BorderBrush="Gray"
            Padding="7" Name="border" Margin="3" Width="500">
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="86"/>
            <ColumnDefinition Width="*"/>
            <Polygon Grid.Row="0" Grid.Column="0" Grid.RowSpan="4"
                     Fill="Yellow" Stroke="Black" StrokeThickness="1"
                     StrokeLineJoin="Round" Width="20" Height="20"
                     Points="9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7"
                     Visibility="Hidden" Name="star"/>

            <TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,8,0"
                       Style="{StaticResource smallTitleStyle}">Description:</TextBlock>
            <TextBlock Name="DescriptionDTDataType" Grid.Row="0" Grid.Column="2" 
                Text="{Binding Path=Description}" 
                Style="{StaticResource textStyleTextBlock}"/>

            <TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,8,0"
                       Style="{StaticResource smallTitleStyle}">Current Price:</TextBlock>
            <StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal">
                <TextBlock Text="$" Style="{StaticResource textStyleTextBlock}"/>
                <TextBlock Name="CurrentPriceDTDataType" 
                    Text="{Binding Path=CurrentPrice}" 
                    Style="{StaticResource textStyleTextBlock}"/>
        <DataTrigger Binding="{Binding Path=SpecialFeatures}">
            <Setter Property="BorderBrush" Value="DodgerBlue" TargetName="border" />
            <Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
            <Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
            <Setter Property="BorderThickness" Value="3" TargetName="border" />
            <Setter Property="Padding" Value="5" TargetName="border" />
        <DataTrigger Binding="{Binding Path=SpecialFeatures}">
            <Setter Property="BorderBrush" Value="Orange" TargetName="border" />
            <Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
            <Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
            <Setter Property="Visibility" Value="Visible" TargetName="star" />
            <Setter Property="BorderThickness" Value="3" TargetName="border" />
            <Setter Property="Padding" Value="5" TargetName="border" />

使用这两个DataTemplate, 生成的 UI 就是在什么是数据绑定?一节中显示的 UI。With the use of those two DataTemplates, the resulting UI is the one shown in the What Is Data Binding? section. 从该屏幕截图中可以看到, 除了允许您将数据放置在控件中外, DataTemplate还允许您为数据定义引人注目的视觉对象。As you can see from that screenshot, in addition to letting you place data in your controls, DataTemplates allow you to define compelling visuals for your data. 例如, 在DataTrigger上述DataTemplate示例中使用了, 这样, 带有SpecialFeatures突出显示的AuctionItem将显示为橙色边框和星形。For example, DataTriggers are used in the above DataTemplate so that AuctionItems with SpecialFeatures value of HighLight would be displayed with an orange border and a star.

有关数据模板的详细信息,请参阅数据模板化概述For more information about data templates, see the Data Templating Overview.

数据验证Data Validation

接受用户输入的大多数应用程序都需要具有验证逻辑,以确保用户输入了预期信息。Most applications that take user input need to have validation logic to ensure that the user has entered the expected information. 可基于类型、范围、格式或特定于应用程序的其他要求执行验证检查。The validation checks can be based on type, range, format, or other application-specific requirements. 本节讨论了数据验证在 WPFWPF 中的工作原理。This section discusses how data validation works in the WPFWPF.

将验证规则与绑定关联Associating Validation Rules with a Binding

数据绑定模型允许您将与您Binding的对象相关联ValidationRulesWPFWPFThe WPFWPF data binding model allows you to associate ValidationRules with your Binding object. 例如, 下面的TextBox示例将绑定到名StartPrice为的属性, 并Binding.ValidationRulesExceptionValidationRule对象添加到属性。For example, the following example binds a TextBox to a property named StartPrice and adds a ExceptionValidationRule object to the Binding.ValidationRules property.

<TextBox Name="StartPriceEntryForm" Grid.Row="2" Grid.Column="1"
    Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5">
    <Binding Path="StartPrice" UpdateSourceTrigger="PropertyChanged">
        <ExceptionValidationRule />

ValidationRule对象检查属性的值是否有效。A ValidationRule object checks whether the value of a property is valid. WPFWPF具有以下两种类型的内置ValidationRule对象:has the following two types of built-in ValidationRule objects:

你还可以通过从ValidationRule类派生并Validate实现方法来创建自己的验证规则。You can also create your own validation rule by deriving from the ValidationRule class and implementing the Validate method. 下面的示例显示了 "什么是数据绑定? " 部分TextBox中 "添加产品列表" 开始日期所使用的规则:The following example shows the rule used by the Add Product Listing "Start Date" TextBox from the What Is Data Binding? section:

class FutureDateRule : ValidationRule
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        DateTime date;
            date = DateTime.Parse(value.ToString());
        catch (FormatException)
            return new ValidationResult(false, "Value is not a valid date.");
        if (DateTime.Now.Date > date)
            return new ValidationResult(false, "Please enter a date in the future.");
            return ValidationResult.ValidResult;
Public Class FutureDateRule
    Inherits ValidationRule

    Public Overrides Function Validate(ByVal value As Object,
                                       ByVal cultureInfo As System.Globalization.CultureInfo) _
                                   As System.Windows.Controls.ValidationResult

        Dim DateVal As DateTime

            DateVal = DateTime.Parse(value.ToString)
        Catch ex As FormatException
            Return New ValidationResult(False, "Value is not a valid date.")
        End Try

        If DateTime.Now.Date > DateVal Then
            Return New ValidationResult(False, "Please enter a date in the future.")
            Return ValidationResult.ValidResult
        End If
    End Function
End Class

StartDateEntryFormTextBox使用此FutureDateRule, 如以下示例中所示:The StartDateEntryForm TextBox uses this FutureDateRule, as shown in the following example:

<TextBox Name="StartDateEntryForm" Grid.Row="3" Grid.Column="1" 
    Validation.ErrorTemplate="{StaticResource validationTemplate}" 
    Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5">
        <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged" 
            Converter="{StaticResource dateConverter}" >
                <src:FutureDateRule />

请注意, 由于UpdateSourceTrigger值为PropertyChanged, 因此绑定引擎将在每次击键时更新源值, 这意味着它还会检查每个ValidationRules击键的集合中的每个规则。Note that because the UpdateSourceTrigger value is PropertyChanged, the binding engine updates the source value on every keystroke, which means it also checks every rule in the ValidationRules collection on every keystroke. 我们会在“验证过程”一节中对此深入讨论。We discuss this further in the Validation Process section.

提供视觉反馈Providing Visual Feedback

如果用户输入的值无效,你可能希望在应用程序 UIUI 上提供一些有关错误的反馈。If the user enters an invalid value, you may want to provide some feedback about the error on the application UIUI. 提供此类反馈的一种方法是将Validation.ErrorTemplate附加属性设置为自ControlTemplate定义。One way to provide such feedback is to set the Validation.ErrorTemplate attached property to a custom ControlTemplate. 如上一节所示, StartDateEntryForm TextBox使用ErrorTemplate称为validationTemplateAs shown in the previous subsection, the StartDateEntryForm TextBox uses an ErrorTemplate called validationTemplate. 以下示例显示了 validationTemplate 的定义:The following example shows the definition of validationTemplate:

<ControlTemplate x:Key="validationTemplate">
    <TextBlock Foreground="Red" FontSize="20">!</TextBlock>

AdornedElementPlaceholder元素指定要装饰的控件的放置位置。The AdornedElementPlaceholder element specifies where the control being adorned should be placed.

此外, 你还可以使用ToolTip来显示错误消息。In addition, you may also use a ToolTip to display the error message. StartDateEntryFormStartPriceEntryFormTextBoxes 都使用 style textStyleTextBox, 这会创建一个ToolTip显示错误消息的。Both the StartDateEntryForm and the StartPriceEntryFormTextBoxes use the style textStyleTextBox, which creates a ToolTip that displays the error message. 以下示例显示了 textStyleTextBox 的定义。The following example shows the definition of textStyleTextBox. 当绑定元素HasErrortrue属性上的一个或多个绑定出错时, 附加属性为。The attached property HasError is true when one or more of the bindings on the properties of the bound element are in error.

<Style x:Key="textStyleTextBox" TargetType="TextBox">
  <Setter Property="Foreground" Value="#333333" />
  <Setter Property="MaxLength" Value="40" />
  <Setter Property="Width" Value="392" />
    <Trigger Property="Validation.HasError" Value="true">
      <Setter Property="ToolTip"
        Value="{Binding RelativeSource={RelativeSource Self},

如果存在验证ErrorTemplate错误ToolTip, 则使用自定义和时, StartDateEntryForm TextBox如下所示:With the custom ErrorTemplate and the ToolTip, the StartDateEntryForm TextBox looks like the following when there is a validation error:

数据绑定验证错误Data binding validation error

如果你Binding具有关联的验证规则, 但你未ErrorTemplate在绑定控件上指定, 则将ErrorTemplate使用默认值来在发生验证错误时通知用户。If your Binding has associated validation rules but you do not specify an ErrorTemplate on the bound control, a default ErrorTemplate will be used to notify users when there is a validation error. 默认值ErrorTemplate是在装饰器层中定义红色边框的控件模板。The default ErrorTemplate is a control template that defines a red border in the adorner layer. 如果存在验证ErrorTemplate错误ToolTip, 则默认UIUI值为, StartPriceEntryForm TextBox的如下所示:With the default ErrorTemplate and the ToolTip, the UIUI of the StartPriceEntryForm TextBox looks like the following when there is a validation error:

数据绑定验证错误Data binding validation error

有关如何提供逻辑以验证对话框中所有控件的示例,请参阅对话框概述中的“自定义对话框”一节。For an example of how to provide logic to validate all controls in a dialog box, see the Custom Dialog Boxes section in the Dialog Boxes Overview.

验证过程Validation Process

通常,在目标的值传输到绑定源属性时会进行验证。Validation usually occurs when the value of a target is transferred to the binding source property. 此操作发生TwoWayOneWayToSource和绑定上。This occurs on TwoWay and OneWayToSource bindings. 重申一下, 源更新的原因取决于UpdateSourceTrigger属性的值, 如什么触发器源更新部分所述。To reiterate, what causes a source update depends on the value of the UpdateSourceTrigger property, as described in the What Triggers Source Updates section.

下面描述了验证过程。The following describes the validation process. 注意,只要在验证过程中发生验证错误或其他类型的错误,该过程就会中断。Note that if a validation error or other type of error occurs at any time during this process, the process is halted.

  1. 绑定引擎检查是否存在ValidationRule RawProposedValue ValidationStep Validate 为设置ValidationRule为的自定义对象,在这种情况下,将在每个对象上调用方法,直到其中一个对象出现错误Binding或直到全部通过。The binding engine checks if there are any custom ValidationRule objects defined whose ValidationStep is set to RawProposedValue for that Binding, in which case it calls the Validate method on each ValidationRule until one of them runs into an error or until all of them pass.

  2. 绑定引擎随后会调用转换器(如果存在)。The binding engine then calls the converter, if one exists.

  3. 如果转换器成功, 绑定引擎会检查是否有定义的任何自ValidationRule定义对象Binding( ValidationStep将其设置ConvertedProposedValue为), 在这种情况下, ValidateValidationRule将对具有设置为ConvertedProposedValue , 直到其中一个错误发生, 或直到全部通过为止。 ValidationStepIf the converter succeeds, the binding engine checks if there are any custom ValidationRule objects defined whose ValidationStep is set to ConvertedProposedValue for that Binding, in which case it calls the Validate method on each ValidationRule that has ValidationStep set to ConvertedProposedValue until one of them runs into an error or until all of them pass.

  4. 绑定引擎设置源属性。The binding engine sets the source property.

  5. 绑定ValidationRule引擎检查是否有ValidationStep ValidationStep Validate UpdatedValue 为设置为的ValidationRule自定义对象,该对象的设置为,在这种情况下,它将在设置为的每个上调用方法。BindingUpdatedValue直到其中一个出现错误, 或直到全部通过为止。The binding engine checks if there are any custom ValidationRule objects defined whose ValidationStep is set to UpdatedValue for that Binding, in which case it calls the Validate method on each ValidationRule that has ValidationStep set to UpdatedValue until one of them runs into an error or until all of them pass. 如果与某个绑定相关联, 并且其ValidationStep设置为默认值, UpdatedValue DataErrorValidationRule则此时会检查。 DataErrorValidationRuleIf a DataErrorValidationRule is associated with a binding and its ValidationStep is set to the default, UpdatedValue, the DataErrorValidationRule is checked at this point. 这也是在检查设置为ValidatesOnDataErrors true的绑定时的点。This is also the point when bindings that have the ValidatesOnDataErrors set to true are checked.

  6. 绑定ValidationRule引擎检查是否有ValidationStep ValidationStep Validate CommittedValue 为设置为的ValidationRule自定义对象,该对象的设置为,在这种情况下,它将在设置为的每个上调用方法。BindingCommittedValue直到其中一个出现错误, 或直到全部通过为止。The binding engine checks if there are any custom ValidationRule objects defined whose ValidationStep is set to CommittedValue for that Binding, in which case it calls the Validate method on each ValidationRule that has ValidationStep set to CommittedValue until one of them runs into an error or until all of them pass.

如果在此过程中的任何时间都未通过, 则绑定引擎将创建ValidationError一个对象Errors并将其添加到绑定元素的集合中。 ValidationRuleIf a ValidationRule does not pass at any time throughout this process, the binding engine creates a ValidationError object and adds it to the Errors collection of the bound element. 在绑定引擎运行任何给定ValidationRule步骤的对象之前, 它会删除在ValidationError该步骤中添加到Errors绑定元素的附加属性的任何。Before the binding engine runs the ValidationRule objects at any given step, it removes any ValidationError that was added to the Errors attached property of the bound element during that step. 例如, 如果设置为ValidationRule UpdatedValue " ValidationStep失败" 的, 则下一次执行验证过程时, 绑定ValidationRule引擎会立即删除ValidationError , 然后再调用已ValidationStep设置为UpdatedValue.For example, if a ValidationRule whose ValidationStep is set to UpdatedValue failed, the next time the validation process occurs, the binding engine removes that ValidationError immediately before it calls any ValidationRule that has ValidationStep set to UpdatedValue.

如果Errors不为空HasError , 则元素的附加属性设置为trueWhen Errors is not empty, the HasError attached property of the element is set to true. 此外, 如果NotifyOnValidationError将的Binding属性设置为true, 则绑定引擎将在元素上引发Validation.Error附加事件。Also, if the NotifyOnValidationError property of the Binding is set to true, then the binding engine raises the Validation.Error attached event on the element.

另请注意, 在任一方向 (目标到源或源到目标) 的有效值传输都将Errors清除附加属性。Also note that a valid value transfer in either direction (target to source or source to target) clears the Errors attached property.

如果绑定具有与之关联ExceptionValidationRule的, 或ValidatesOnExceptions将属性设置为true , 并且在绑定引擎设置源时引发异常, 则绑定UpdateSourceExceptionFilter引擎会检查是否存在。If the binding either has an ExceptionValidationRule associated with it, or had the ValidatesOnExceptions property is set to true and an exception is thrown when the binding engine sets the source, the binding engine checks to see if there is a UpdateSourceExceptionFilter. 您可以选择使用UpdateSourceExceptionFilter回调提供自定义处理程序来处理异常。You have the option to use the UpdateSourceExceptionFilter callback to provide a custom handler for handling exceptions. 如果未ValidationError Errors在上指定, 则绑定引擎将创建一个具有异常的, 并将其添加到绑定元素的集合中。 Binding UpdateSourceExceptionFilterIf an UpdateSourceExceptionFilter is not specified on the Binding, the binding engine creates a ValidationError with the exception and adds it to the Errors collection of the bound element.

调试机制Debugging Mechanism

您可以对与绑定相关TraceLevel的对象设置附加属性, 以接收有关特定绑定的状态的信息。You can set the attached property TraceLevel on a binding-related object to receive information about the status of a specific binding.

请参阅See also