摘要:第 11 章. 可绑定的基础结构

注意

本书于 2016 年春季出版,之后再未更新。 书中有许多内容仍然有价值,但有些内容已过时,有些主题不再完全正确或完整。

每个 C# 程序员都熟悉 C# 属性。 属性包含 set 访问器和/或 get 访问器。 它们通常称为公共语言运行时的 CLR 属性

Xamarin.Forms 定义了一个增强属性定义,称为“可绑定属性”,由 BindableProperty 类封装,并由 BindableObject 类提供支持。 这些类是相关的,但非常不同:BindableProperty 用于定义属性本身;BindableObjectobject 相似,因为它是定义可绑定属性的类的基类。

Xamarin.Forms 类层次结构

ClassHierarchy 示例使用反射来显示 Xamarin.Forms 的类层次结构,并演示 BindableObject 在此层次结构中发挥的重要作用BindableObject 派生自 Object,是 Element 的父类,VisualElement 派生自该父类。 这是 PageView 的父类,后者是 Layout 的父类:

类层次结构共享的三倍屏幕截图

查看 BindableObject 和 BindableProperty

在从 BindableObject 派生的类中,许多 CLR 属性被称为“受支持的”可绑定属性。 例如,Label 类的 Text 属性是 CLR 属性,但是 Label 类还定义了类型为 BindableProperty 的名为 TextProperty 的公共静态只读字段。

应用程序可以正常设置或获取 LabelText 属性,或者应用程序可以通过使用 Label.TextProperty 参数调用 BindableObject 定义的 SetValue 方法来设置 Text。 同样,应用程序可以通过再次使用 Label.TextProperty 参数调用 GetValue 方法来获取 Text 属性的值。 PropertySettings 示例对此进行了演示。

实际上,Text CLR 属性完全是使用由 BindableObject 以及 Label.TextProperty 静态属性一起定义的 SetValueGetValue 方法实现的。

BindableObjectBindableProperty 为以下操作提供支持:

  • 提供属性默认值
  • 存储其当前值
  • 提供验证属性值的机制
  • 保持单个类中相关属性之间的一致性
  • 响应属性变化
  • 在属性即将更改或已更改时触发通知
  • 支持数据绑定
  • 支持样式
  • 支持动态资源

每当由可绑定属性提供支持的属性发生更改时,BindableObject 就会触发 PropertyChanged 事件,以标识已更改的属性。 当属性设置为相同值时,不会触发此事件。

某些属性不受可绑定属性支持,而某些 Xamarin.Forms 类(例如 Span)不是从 BindableObject 派生的。 只有从 BindableObject 派生的类才能支持可绑定属性,因为 BindableObject 定义了 SetValueGetValue 方法。

因为 Span 不是从 BindableObject 派生的,所以它的任何属性(例如 Text)都不受可绑定属性的支持。 这就是上一章的 DynamicVsStatic 示例中,SpanText 属性上的 DynamicResource 设置引发异常的原因。 DynamicVsStaticCode 示例演示如何使用 Element 定义的 SetDynamicResource 方法在代码中设置动态资源。 第一个参数是类型为 BindableProperty 的对象。

同样,BindableObject 定义的 SetBinding 方法具有类型为 BindableProperty 的第一个参数。

定义可绑定属性

可以使用静态 BindableProperty.Create 方法定义自己的可绑定属性,以创建类型为 BindableProperty 的静态只读字段。

Xamarin.FormsBook.Toolkit 库中的 AltLabel 类对此进行了演示。 该类派生自 Label,可让用户指定字号(以磅为单位)。 PointSizedText 示例对此进行了演示。

BindableProperty.Create 方法需要四个参数:

  • propertyName:属性的文本名称(与 CLR 属性名称相同)
  • returnType:CLR 属性的类型
  • declaringType:声明属性的类的类型
  • defaultValue:属性的默认值

由于 defaultValue 的类型为 object,因此编译器必须能够确定默认值的类型。 例如,如果 returnTypedouble,则应将 defaultValue 设置为类似于 0.0 的值,而不是仅设置为 0,否则类型不匹配将在运行时触发异常。

可绑定属性通常还包括:

  • propertyChanged:属性更改值时调用的静态方法。 第一个参数是属性已更改的类的实例。

BindableProperty.Create 的其他参数并不常见:

  • defaultBindingMode:与数据绑定结合使用(如以下章节中所述:第 16 章数据绑定
  • validateValue:用于检查有效值的回叫
  • propertyChanging:一个回叫,指示何时要更改属性
  • coerceValue:一个回叫,将设定值强制转换为另一个值
  • defaultValueCreate:一个回叫,创建无法在类(例如,集合)的实例之间共享的默认值

只读可绑定属性

可绑定属性可以是只读的。 创建只读可绑定属性需要调用静态方法 BindableProperty.CreateReadOnly 来定义类型为 BindablePropertyKey 的专用静态只读字段。

然后,将 CLR 属性 set 访问器定义为 private,以使用 BindablePropertyKey 对象调用 SetValue 重载。 这样可以防止在类外部设置属性。

BaskervillesCount 示例中使用的 CountedLabel 类对此进行了演示。