第 16 章摘要。 数据绑定
注意
本书于 2016 年春季出版,之后再未更新。 书中有许多内容仍然有价值,但有些内容已过时,有些主题不再完全正确或完整。
程序员经常会编写事件处理程序以检测某对象属性的更改时间,并使用该事件处理程序更改另一个对象中的属性值。 可以使用数据绑定方法自动执行此流程。 数据绑定通常在 XAML 中定义,且属于用户界面定义。
通常,这些数据绑定会将用户界面对象连接到基础数据。 第 18 章 MVVM 中详细介绍了此技术。 但数据绑定还可以连接两个或多个用户界面元素。 本章中,大多数数据绑定早期示例均演示了此方法。
关于绑定的基础知识
数据绑定涉及多个属性、方法和类:
Binding
类派生自BindingBase
且可封装数据绑定的许多特性BindingContext
属性由BindableObject
类定义SetBinding
方法也由BindableObject
类定义BindableObjectExtensions
类定义其他三个SetBinding
方法
以下两个类支持用于绑定的 XAML 标记扩展:
BindingExtension
支持Binding
标记扩展ReferenceExtension
支持x:Reference
标记扩展
数据绑定涉及两个接口:
System.ComponentModel
命名空间中的INotifyPropertyChanged
用于在属性更改时进行通知IValueConverter
用于定义数据绑定中将值从一种类型转换为另一种类型的小型类
数据绑定连接同一对象或两个不同对象(更常见)的两个属性。 这两个属性称为源和目标。 通常,源属性更改会导致目标属性发生更改,但有时情况相反。 不考虑:
- 目标属性必须由
BindableProperty
支持 - 源属性通常是可实现
INotifyPropertyChanged
的类的成员
属性更改值时,可实现 INotifyPropertyChanged
的类会触发 PropertyChanged
事件。 BindableObject
可实现 INotifyPropertyChanged
并在 BindableProperty
支持的属性更改值时自动触发 PropertyChanged
事件,但你可以自己编写可实现 INotifyPropertyChanged
的类,而无需从 BindableObject
派生。
代码和 XAML
OpacityBindingCode 示例演示如何在代码中设置数据绑定:
- 源是
Slider
的Value
属性 - 目标是
Label
的Opacity
属性
将 Label
对象的 BindingContext
设置为 Slider
对象即可连接两个对象。 调用 Label
上的 SetBinding
扩展方法(可引用以字符串形式表示的 Slider
的 OpacityProperty
可绑定属性和 Value
属性)即可连接这两个属性。
然后,操作 Slider
会使 Label
淡入和淡出。
OpacityBindingXaml 是与 XAML 中所设数据绑定相同的程序。 Label
的 BindingContext
设置为 x:Reference
标记扩展,其引用 Slider
,而 Label
的 Opacity
属性设置为 Binding
标记扩展,其 Path
属性引用 Slider
的 Value
属性。
源和 BindingContext
BindingSourceCode 示例显示代码中的替代方法。 将 Source
属性设置为 Slider
对象并将 Path
属性设置为“Value”即可创建 Binding
对象。 然后在 Label
对象上调用 BindableObject
的 SetBinding
方法。
Binding
构造函数也可以用于定义 Binding
对象。
BindingSourceXaml 示例显示 XAML 中的类似方法。 Label
的 Opacity
属性设置为 Binding
标记扩展,其中 Path
设置为 Value
属性,Source
设置为嵌入式 x:Reference
标记扩展。
总而言之,以下两种方式可以引用绑定源对象:
- 通过目标的
BindingContext
属性 - 通过
Binding
对象自身的Source
属性
如果同时指定两者,则第二种优先。 BindingContext
的优点在于它通过可视化树传播。 如果将多个目标属性绑定到同一源对象,这非常方便。
WebViewDemo 程序使用 WebView
元素演示此技术。 用于向后导航和向前导航的两个 Button
元素从引用 WebView
的父级继承 BindingContext
。 然后,两个按钮的 IsEnabled
属性具有简单的 Binding
标记扩展,适用于基于 WebView
的 CanGoBack
和 CanGoForward
只读属性的设置的按钮 IsEnabled
属性。
绑定模式
将 Binding
的 Mode
属性设置为 BindingMode
枚举的成员:
OneWay
,使源属性的更改影响目标OneWayToSource
,使目标属性的更改影响源TwoWay
,使源和目标的更改彼此影响Default
,使用创建目标BindableProperty
时指定的DefaultBindingMode
。 如果未指定,则常规可绑定属性默认为OneWay
,只读可绑定属性默认为OneWayToSource
。
注意
BindingMode
枚举现还包括 OnTime
,用于仅在绑定上下文发生更改时而不是在源属性发生更改时应用绑定。
MVVM 场景中可能成为数据绑定目标的属性的 DefaultBindingMode
通常为 TwoWay
。 这些功能是:
Slider
和Stepper
的Value
属性Switch
的IsToggled
属性Entry
、Editor
和SearchBar
的Text
属性DatePicker
的Date
属性TimePicker
的Time
属性
BindingModes 示例演示了数据绑定的四种绑定模式,其中目标是 Label
的 FontSize
属性,源是 Slider
的 Value
属性。 这使每个 Slider
可以控制相应的 Label
的字号。 但 Slider
元素未初始化,因为 FontSize
属性的 DefaultBindingMode
是 OneWay
。
ReverseBinding 示例在 Slider
(可引用每个 Label
的 FontSize
属性)的 Value
属性上设置绑定。 这似乎是向后的,但更适合初始化 Slider
元素,因为 Slider
的 Value
属性的 DefaultBindingMode
是 TwoWay
。
这类似于在 MVVM 中定义绑定的方式,你将经常使用这种类型的绑定。
字符串格式设置
如果目标属性是 string
类型,可以使用 BindingBase
定义的 StringFormat
属性将源转换为 string
。 将 StringFormat
属性设置为 .NET 格式设置字符串,该字符串将与静态 String.Format
格式一起用于显示对象。 在标记扩展中使用此格式设置字符串时,用单引号将它括起来,以免大括号被误以为是嵌入的标记扩展。
ShowViewValues 示例演示如何在 XAML 中使用 StringFormat
。
WhatSizeBindings 示例演示如何绑定 ContentPage
的 Width
和 Height
属性以显示页面的大小。
为什么称其为“路径”?
Binding
的 Path
属性被称为“路径”是因为它可以是由句点分隔的一系列属性和索引器。 BindingPathDemos 示例显示了多个示例。
绑定值转换器
如果绑定的源属性和目标属性是不同类型,可以使用绑定转换器在类型之间进行转换。 这个类可实现 IValueConverter
接口,且包含两个方法:将源转换为目标的 Convert
,以及将目标转换为源的 ConvertBack
。
Xamarin.FormsBook.Toolkit 库中的 IntToBoolConverter
类是将 int
转换为 bool
的示例。 ButtonEnabler 示例对此进行了演示,该示例在 Entry
中至少已键入一个字符时才启用 Button
。
BoolToStringConverter
类将 bool
转换为 string
,并定义两个属性以指定应针对 false
和 true
值而返回的文本。
BoolToColorConverter
类似。 SwitchText 示例演示如何使用这两个转换器基于 Switch
设置以不同颜色显示不同文本。
通用的 BoolToObjectConverter
可替代 BoolToStringConverter
和 BoolToColorConverter
,并且可用作任何类型的通用 bool
-to-object 转换器。
绑定和自定义视图
可以使用数据绑定简化自定义控件。 NewCheckBox.cs
代码文件定义 Text
、TextColor
、FontSize
、FontAttributes
和 IsChecked
属性,但对于控件的视觉对象而言完全没有逻辑。
而 NewCheckBox.cs.xaml
文件基于代码隐藏文件中定义的属性,在 Label
元素上通过数据绑定包含控件视觉对象的所有标记。
NewCheckBoxDemo 示例演示 NewCheckBox
自定义控件。