绑定和连接:什么是数据绑定?
WPF 的核心功能——数据绑定的基本方面
在本文中,我们将探讨 WPF 的核心功能之一——数据绑定的基本方面。
XAML 数据绑定是一种无需编写代码(声明式)的方式,可以将信息从一个对象传输到另一个对象。这在 UI 中非常有用,其中一个对象中的数据可以控制另一个对象的特性(或作为显示在另一个对象中的数据的来源)。数据绑定的主要好处是极大地减少(如果不是完全消除)您需要在代码隐藏类事件处理程序中编写的程序性代码行数。如果充分利用,设计师(非程序员)可以在设计工具中定义 GUI 的外观和行为,而无需程序员的协助。
图 1 展示了一个简单的例子。窗口有一个水平滑动条和一个静态文本。移动滑块会改变静态文本的大小。
要使用代码同步控件,您需要实现六个事件。(好的,每个事件只有一行代码。)您需要在 Window 的 Open 事件中将文本大小初始化为滑块的起始位置;然后,您需要编写 LineLeft、LineRight、Moved、PageLeft 和 PageRight 事件来将文本大小与滑块位置同步。图 2 展示了代码和六个事件中的五个。
图 3 展示了一个等效的 XAML 数据绑定表达式。您通过编写一个简单的简写绑定表达式来建立控件之间的关联,该表达式将 TextSize
属性值链接到其 TrackBar 数据源。
表达式以大括号 {
开头,后跟关键字 Binding,然后是源对象的名称和求值为源内包含该值的属性名称的路径表达式。如果您不清楚,图 4 突出显示了源对象和目标对象。图 5 展示了编写相同绑定表达式的长格式。在这里,您可以清楚地看到绑定对象的作用。
编写绑定表达式会导致编译器生成一个 Binding 对象,该对象连接绑定目标对象的属性与数据源。
控制数据流方向
您可以控制源与其绑定对象之间的流方向。流可以是
- TwoWay(双向):绑定属性的值更改会反映在其源中,源的更改也会反映在绑定属性中。
- OneWay(单向):源的更改会反映在绑定属性中。
- OneTime(一次性):源的值更改最初会反映在绑定属性中。后续更改将被忽略。
- OneWayToSource(单向到源):绑定属性的值更改会反映在其源中。这是 OneWay 的反向。
默认流方向取决于属性。对于用户可设置的属性,默认值为 TwoWay;其他所有属性均为 OneWay。
我将扩展我们的示例,添加一个单行输入框,允许我直接输入字体大小。为了保持一切同步,我只需要将其绑定到水平滑动条。图 6 展示了新的 UI;图 7 展示了其 XAML。
有趣的是(虽然您应该预料到),在代码中更改依赖属性可以反映在绑定控件之间,前提是设置了正确的绑定方向。为了演示,我将添加几个命令按钮,它们的单击事件将增加和减少字体大小。由于 TextSize
属性默认是 OneWay,我需要将其设置为 TwoWay,以便它能够将其更改通知其源。图 8 展示了修改后的窗口和新的 XAML(已突出显示更改)。
AcceptText()
正如我们所知,DataWindow 中编辑控件内容的更改在用户更改焦点或您的代码调用 AcceptText()
之前不会反映在主缓冲区中。WPF TextBox(PB SLE 的祖先)的 Text 属性默认情况下行为相同。在我们的例子中,如果用户在 SingleLineEdit
中输入新的字体大小,则在用户更改焦点之前,大小不会改变。但是,有一个名为 UpdateSourceTrigger
的枚举,其值允许您控制何时更新源。可能的值是
- PropertyChanged(属性更改):源会立即更新。
- LostFocus(失去焦点):源会在属性更改且目标控件失去焦点时更新。
- Explicit(显式):源只能通过代码调用来更新。
图 9 展示了 XAML 的最终更改,该更改将在用户输入时显示更改。
这一切是如何工作的?
构建 WPF 的主要架构理念之一是偏好属性而不是方法或事件。您可以在 XAML 中以声明方式使用属性。这使您可以轻松指定意图(设置属性值),而不是操作(调用方法)。该机制支持一种模型驱动或数据驱动的系统来显示用户界面内容。这种理念产生了创建更多可绑定属性的预期效果,以便更好地控制应用程序的行为。
为了支持由属性驱动的系统,WPF 需要一个比 CLR 提供的更丰富的属性系统。这种丰富性的一个简单例子是更改通知。为了启用双向绑定,绑定的两边都需要支持更改通知。为了将行为与属性值关联起来,您需要及时了解属性值何时发生更改。Microsoft .NET Framework 提供了一个可选接口 INotifyPropertyChange,它允许对象发布更改通知。
WPF 提供了一个更丰富的属性系统,它继承自 DependencyObject
类型。该属性系统确实是一个“依赖”属性系统,因为它跟踪属性表达式之间的依赖关系,并在依赖项更改时自动重新验证属性值。在我们的示例中,如果它所依赖的任何属性发生更改,Static Text 的 FontSize
就会被系统自动更新。