.NET 多平台应用 UI (.NET MAUI) 可绑定属性通过支持具有 BindableProperty 类型的属性而不是字段来扩展公共语言运行时 (CLR) 属性功能。 可绑定属性的目的是提供支持通过父子关系设置的数据绑定、样式、模板和值的属性系统。 此外,可绑定属性可以提供默认值、属性值验证以及监视属性更改的回调。
在 .NET MAUI 应用中,属性应实现为可绑定属性,以支持以下一个或多个功能:
- 充当数据绑定的有效 目标 属性。 有关目标属性的详细信息,请参阅 基本绑定。
- 通过样式设置属性。
- 提供与属性类型的默认值不同的默认属性值。
- 验证属性的值。
- 监视属性更改。
.NET MAUI 可绑定属性的示例包括 Label.Text、Button.BorderRadius 和StackLayout.Orientation。 每个可绑定属性都有一个在相同类上公开的相应 public static readonly 类型的 BindableProperty 字段,该字段是可绑定属性的标识符。 例如,与 Label.Text 属性相对应的可绑定属性标识符是 Label.TextProperty。
创建可绑定属性
创建可绑定属性的过程如下所示:
- 使用
BindableProperty.Create中的一种方法重载来创建BindableProperty实例。 - 为BindableProperty实例定义属性访问器。
必须在 UI 线程上创建所有 BindableProperty 实例。 这意味着,只有 UI 线程上运行的代码才能获取或设置可绑定属性的值。 但是,可以通过将实例封送到 UI 线程,从其他线程访问 BindableProperty。 有关详细信息,请参阅 UI 线程上的“运行代码”。
创建属性
若要创建 BindableProperty 实例,包含类必须派生自该 BindableObject 类。 但是, BindableObject 该类在类层次结构中很高,因此用于 UI 功能的大多数类支持可绑定属性。
可以通过声明 public static readonly 类型属性 BindableProperty来创建可绑定属性。 可绑定的属性应设置为方法重载之一的BindableProperty.Create返回值。 声明应位于派生类的 BindableObject 正文中,但不属于任何成员定义。
创建BindableProperty时,至少必须指定一个标识符以及以下参数:
- BindableProperty的名称。
- 属性的类型。
- 拥有对象的类型。
- 属性的默认值。 这可以确保属性在未设置时始终返回特定的默认值,并且它与属性类型的默认值不同。 在可绑定属性上调用该方法时
ClearValue,将还原默认值。
重要
可绑定属性的命名约定是,可绑定属性标识符必须与方法中指定的 Create 属性名称匹配,并将“Property”追加到该方法中。
以下代码显示了可绑定属性的示例,其中包含四个必需参数的标识符和值:
public static readonly BindableProperty IsExpandedProperty =
BindableProperty.Create ("IsExpanded", typeof(bool), typeof(Expander), false);
将会创建一个类型为bool、名为IsExpandedProperty的BindableProperty实例。 该属性由 Expander 类拥有,默认值为 false.
注释
Expander 是 .NET MAUI 社区工具包中的控件。 有关详细信息,请参阅 Expander。
(可选)创建 BindableProperty 实例时,可以指定以下参数:
- 绑定模式。 这用于指定属性值更改将传播的方向。 在默认绑定模式下,更改将从 源 传播到 目标。 有关详细信息,请参阅 基本绑定。
- 设置属性值时将调用的验证委托。 有关详细信息,请参阅 验证回调。
- 属性已更改委托,在属性值发生更改时将调用该委托。 有关详细信息,请参阅 检测属性更改。
- 属性更改委托,用于在属性值即将更改时进行调用。 此委托与属性更改的委托具有相同的签名。
- 每当属性值发生更改时,将调用用于强制转换值的委托。 有关详细信息,请参阅 强制转换值回调。
- A
Func用于初始化默认属性值。 有关详细信息,请参阅 使用 Func 创建默认值。
创建访问器
属性访问器需要使用属性语法来访问可绑定属性。 访问器 Get 应返回对应可绑定属性中所包含的值。 这可以通过调用 GetValue 方法来实现,传入要获取值的可绑定属性标识符,然后将结果强制转换为所需类型。 访问器Set应该设置相应可绑定属性的值。 这可以通过调用 SetValue 方法、传入要设置值的可绑定属性标识符和要设置的值来实现。
下面的代码示例显示了IsExpanded可绑定属性的访问器:
public bool IsExpanded
{
get => (bool)GetValue(IsExpandedProperty);
set => SetValue(IsExpandedProperty, value);
}
使用可绑定属性
创建可绑定属性后,可以从 XAML 或代码使用它。 在 XAML 中,这是通过声明具有前缀的命名空间、指示 CLR 命名空间名称的命名空间声明以及(可选)程序集名称来实现的。 有关详细信息,请参阅 XAML 命名空间。
下面的代码示例演示包含可绑定属性的自定义类型的 XAML 命名空间,该属性在引用自定义类型的应用程序代码所在的程序集中定义:
<ContentPage ... xmlns:local="clr-namespace:DataBindingDemos" ...>
...
</ContentPage>
设置 IsExpanded 可绑定属性时使用命名空间声明,如以下 XAML 代码示例所示:
<Expander IsExpanded="true">
...
</Expander>
下面的代码示例显示了等效的 C# 代码:
Expander expander = new Expander
{
IsExpanded = true
};
高级场景
创建 BindableProperty 实例时,可以设置许多可选参数来启用高级可绑定属性方案。 本部分探讨这些方案。
检测属性更改
可以通过指定propertyChanged方法的BindableProperty.Create参数,将属性更改回调方法注册到可绑定属性上。 当可绑定属性的值发生更改时,将调用指定的回调方法。
下面的代码示例演示了可绑定属性如何将方法 OnIsExpandedChanged 注册为属性更改的回调方法:
public static readonly BindableProperty IsExpandedProperty =
BindableProperty.Create(nameof(IsExpanded), typeof(bool), typeof(Expander), false, propertyChanged: OnIsExpandedChanged);
...
static void OnIsExpandedChanged (BindableObject bindable, object oldValue, object newValue)
{
// Property changed implementation goes here
}
在属性更改回调方法中,参数 BindableObject 用于表示拥有类的哪个实例报告了更改,两 object 个参数的值表示可绑定属性的旧值和新值。
验证回调
通过为BindableProperty.Create方法指定validateValue参数,可以将验证回调方法注册到可绑定属性上。 设置可绑定属性的值时,将调用指定的回调方法。
以下代码示例展示了如何将 Angle 绑定属性注册为 IsValidValue 方法的验证回调方法。
public static readonly BindableProperty AngleProperty =
BindableProperty.Create("Angle", typeof(double), typeof(MainPage), 0.0, validateValue: IsValidValue);
...
static bool IsValidValue(BindableObject view, object value)
{
double result;
double.TryParse(value.ToString(), out result);
return (result >= 0 && result <= 360);
}
验证回调函数会接收一个值,如果该值对属性有效,则应返回true;否则,应返回false。 验证回调方法的一个典型用法是在设置可绑定属性的时候用于限制整数或双精度值的范围。 例如,该方法 IsValidValue 检查属性值是否在 double 0 到 360 范围内。
强制值回调
通过指定coerceValue方法的BindableProperty.Create参数,可以为可绑定属性注册一个static强制值回调函数。 当可绑定属性的值即将更改时,将调用指定的回调方法,以便在应用新值之前对其进行调整。
重要
除了由可绑定属性引擎触发外,还可以从代码调用强制值回调。 该 BindableObject 类型具有一个 CoerceValue 方法,可以通过调用其强制值回调来强制重新计算其 BindableProperty 参数的值。
强制值回调用于在属性值即将更改时强制重新计算可绑定属性。 例如,强制值回调可用于确保一个可绑定属性的值不大于另一个可绑定属性的值。
下面的代码示例展示了如何将 Angle 可绑定属性注册为 CoerceAngle 方法的强制值回调方法:
public static readonly BindableProperty AngleProperty =
BindableProperty.Create("Angle", typeof(double), typeof(MainPage), 0.0, coerceValue: CoerceAngle);
public static readonly BindableProperty MaximumAngleProperty =
BindableProperty.Create("MaximumAngle", typeof(double), typeof(MainPage), 360.0, propertyChanged: ForceCoerceValue);
...
static object CoerceAngle(BindableObject bindable, object value)
{
MainPage page = bindable as MainPage;
double input = (double)value;
if (input > page.MaximumAngle)
{
input = page.MaximumAngle;
}
return input;
}
static void ForceCoerceValue(BindableObject bindable, object oldValue, object newValue)
{
bindable.CoerceValue(AngleProperty);
}
该方法检查 MaximumAngle 属性的值,如果 Angle 属性值大于 MaximumAngle 属性值,则会将该值强制调整为 MaximumAngle 属性值。 此外,当 MaximumAngle 属性变化时,强制值回调函数会通过调用 CoerceValue 方法作用于 Angle 属性。
使用 Func 创建默认值
A Func 可用于初始化可绑定属性的默认值,如以下示例所示:
public static readonly BindableProperty DateProperty =
BindableProperty.Create ("Date", typeof(DateTime), typeof(MyPage), default(DateTime), BindingMode.TwoWay, defaultValueCreator: bindable => DateTime.Today);
该defaultValueCreator参数被设置为一个Func,该Func返回一个表示当前日期的DateTime。