Xamarin.Forms 可绑定属性

可绑定属性通过使用 BindableProperty 类型支持属性,而不是使用字段支持属性,扩展了 CLR 属性功能。 可绑定属性的目的是提供一个属性系统,它支持通过父子关系设置的数据绑定、样式、模板和值。 此外,可绑定属性可以提供默认值、属性值验证以及监控属性更改的回调。

属性应作为可绑定属性实现,以支持以下一个或多个功能:

  • 充当数据绑定的有效目标属性。
  • 通过样式设置属性。
  • 提供与属性类型的默认值不同的默认属性值。
  • 验证属性的值。
  • 监控属性更改。

Xamarin.Forms 可绑定属性的示例包括 Label.TextButton.BorderRadiusStackLayout.Orientation。 每个可绑定属性都有一个在相同类上公开的相应 public static readonly 类型的 BindableProperty 字段,该字段是可绑定属性的标识符。 例如,Label.Text 属性的相应可绑定属性标识符为 Label.TextProperty

创建可绑定属性

创建可绑定属性的过程如下所示:

  1. 使用其中一个 BindableProperty.Create 方法重载创建 BindableProperty 实例。
  2. 定义 BindableProperty 实例的属性访问器。

必须在 UI 线程上创建所有 BindableProperty 实例。 这意味着,只有 UI 线程上运行的代码才能获取或设置可绑定属性的值。 但是,可以通过使用 Device.BeginInvokeOnMainThread 方法封送到 UI 线程,从其他线程访问 BindableProperty 实例。

创建属性

若要创建 BindableProperty 实例,包含类必须派生自 BindableObject 类。 不过,BindableObject 类在类层次结构中的位置较高,因此大多数用于用户界面功能的类都支持可绑定属性。

可以通过声明 BindableProperty 类型的 public static readonly 属性来创建可绑定属性。 可绑定属性应设置为 BindableProperty.Create 方法重载之一的返回值。 声明应位于 BindableObject 派生类的正文中,但不属于任何成员定义。

创建 BindableProperty 时,必须至少指定一个标识符以及以下参数:

  • BindableProperty 的名称。
  • 属性类型。
  • 所属对象的类型。
  • 属性的默认值。 这可以确保属性在未设置时始终返回特定的默认值,并且它可以与该属性类型的默认值不同。 在可绑定属性上调用 ClearValue 方法时,将还原默认值。

重要

可绑定属性的命名约定是,可绑定属性标识符必须与 Create 方法中指定的属性名称匹配,并将“属性”追加到该方法中。

以下代码展示了可绑定属性的示例,其中包含四个必需参数的标识符和值:

public static readonly BindableProperty EventNameProperty =
  BindableProperty.Create ("EventName", typeof(string), typeof(EventToCommandBehavior), null);

这将创建名为 EventNamePropertyBindableProperty 实例,类型为 string。 此属性归 EventToCommandBehavior 类所有,其默认值为 null

创建 BindableProperty 实例时,也可以选择指定以下参数:

  • 绑定模式。 这用于指定属性值更改的传播方向。 在默认绑定模式下,更改将从源传播到目标
  • 设置属性值时将调用的验证委托。 有关详细信息,请参阅验证回调
  • 属性值发生更改时将调用的属性已更改委托。 有关详细信息,请参阅检测属性更改
  • 属性值即将更改时将调用的属性即将更改委托。 此委托与属性更改的委托具有相同的签名。
  • 属性值发生更改时将调用的强制值委托。 有关详细信息,请参阅强制值回调
  • 用于初始化默认属性值的 Func。 有关详细信息,请参阅使用 Func 创建默认值

创建访问器

属性访问器需要使用属性语法才能访问可绑定属性。 Get 访问器应返回相应可绑定属性中包含的值。 可以通过调用 GetValue 方法,传入要获取值的可绑定属性标识符,然后将结果强制转换为所需的类型来达成此目的。 Set 访问器应设置相应可绑定属性的值。 可以通过调用 SetValue 方法、传入要设置值的可绑定属性标识符和要设置的值达成此目的。

以下代码示例演示 EventName 可绑定属性的访问器:

public string EventName
{
  get { return (string)GetValue (EventNameProperty); }
  set { SetValue (EventNameProperty, value); }
}

使用可绑定属性

创建可绑定属性后,可以从 XAML 或代码使用它。 在 XAML 中,可通过声明带有前缀的命名空间、指示 CLR 命名空间名称的命名空间声明,以及(可选)程序集名称来达成此目的。 有关详细信息,请参阅 XAML 命名空间

以下代码示例演示包含可绑定属性的自定义类型的 XAML 命名空间,该属性在与引用自定义类型的应用程序代码相同的程序集中定义:

<ContentPage ... xmlns:local="clr-namespace:EventToCommandBehavior" ...>
  ...
</ContentPage>

设置 EventName 可绑定属性时将使用命名空间声明,如以下 XAML 代码示例所示:

<ListView ...>
  <ListView.Behaviors>
    <local:EventToCommandBehavior EventName="ItemSelected" ... />
  </ListView.Behaviors>
</ListView>

以下代码示例显示相应的 C# 代码:

var listView = new ListView ();
listView.Behaviors.Add (new EventToCommandBehavior
{
  EventName = "ItemSelected",
  ...
});

高级方案

创建 BindableProperty 实例时,可以设置许多可选参数来启用高级可绑定属性应用场景。 本部分将探讨这些应用场景。

检测属性更改

可通过为 BindableProperty.Create 方法指定 propertyChanged 参数,向可绑定属性注册 static 属性更改的回调方法。 当可绑定属性的值更改时,将调用指定的回叫方法。

以下代码示例演示 EventName 可绑定属性如何将 OnEventNameChanged 方法注册为属性更改的回调方法:

public static readonly BindableProperty EventNameProperty =
  BindableProperty.Create (
    "EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
...

static void OnEventNameChanged (BindableObject bindable, object oldValue, object newValue)
{
  // Property changed implementation goes here
}

在属性更改的回调方法中,BindableObject 参数用于表示所属类的哪个实例报告了更改,两个 object 参数的值分别表示可绑定属性的新旧值。

验证回调

可通过为 BindableProperty.Create 方法指定 validateValue 参数,通过可绑定属性注册 static 验证回调方法。 设置可绑定属性的值时,将调用指定的回调方法。

以下代码示例演示 Angle 可绑定属性如何将 IsValidValue 方法注册为验证回调方法:

public static readonly BindableProperty AngleProperty =
  BindableProperty.Create ("Angle", typeof(double), typeof(HomePage), 0.0, validateValue: IsValidValue);
...

static bool IsValidValue (BindableObject view, object value)
{
  double result;
  bool isDouble = double.TryParse (value.ToString (), out result);
  return (result >= 0 && result <= 360);
}

验证回调随值一起提供,如果该值对属性有效,则应返回 true,否则返回 false。 如果验证回叫返回 false(应由开发人员处理),则会引发异常。 验证回调方法的典型用法是在设置可绑定属性时约束整数值或双精度值。 例如,IsValidValue 方法将检查属性值是否为介于 0 到 360 范围之间的 double

强制值回调

可通过为 BindableProperty.Create 方法指定 coerceValue 参数,向可绑定属性注册 static 强制值回调方法。 当可绑定属性的值更改时,将调用指定的回叫方法。

重要

BindableObject 类型包含 CoerceValue 方法,可以通过调用其强制值回调来强制重新计算其 BindableProperty 参数的值。

强制值回叫用于在属性值更改时强制重新计算可绑定属性。 例如,可使用强制值回调确保一个可绑定属性的值不大于另一个可绑定属性的值。

以下代码示例演示 Angle 可绑定属性如何将 CoerceAngle 方法注册为强制值回调方法:

public static readonly BindableProperty AngleProperty = BindableProperty.Create (
  "Angle", typeof(double), typeof(HomePage), 0.0, coerceValue: CoerceAngle);
public static readonly BindableProperty MaximumAngleProperty = BindableProperty.Create (
  "MaximumAngle", typeof(double), typeof(HomePage), 360.0, propertyChanged: ForceCoerceValue);
...

static object CoerceAngle (BindableObject bindable, object value)
{
  var homePage = bindable as HomePage;
  double input = (double)value;

  if (input > homePage.MaximumAngle)
  {
    input = homePage.MaximumAngle;
  }
  return input;
}

static void ForceCoerceValue(BindableObject bindable, object oldValue, object newValue)
{
  bindable.CoerceValue(AngleProperty);
}

CoerceAngle 方法检查 MaximumAngle 属性的值,并且如果 Angle 属性值大于该值,则将该值强制转换为 MaximumAngle 属性值。 此外,当 MaximumAngle 属性更改时,通过调用 CoerceValue 方法,对 Angle 属性调用强制值回调。

使用 Func 创建默认值

Func 可用于初始化可绑定属性的默认值,如以下代码示例所示:

public static readonly BindableProperty SizeProperty =
  BindableProperty.Create ("Size", typeof(double), typeof(HomePage), 0.0,
  defaultValueCreator: bindable => Device.GetNamedSize (NamedSize.Large, (Label)bindable));

defaultValueCreator 参数设置为 Func,它调用 Device.GetNamedSize 方法来返回 double,表示在本机平台上用于 Label 的字体的命名大小。