基本绑定
.NET Multi-platform App UI (.NET MAUI) 数据绑定在两个对象之间链接一对属性,其中至少一个对象通常是用户界面对象。 这两个对象称为“目标”和“源”:
- “目标”是设置数据要绑定的对象(和属性)。
- “源”是数据绑定引用的对象(和属性)。
在最简单的情况下,数据从源流到目标,这意味着目标属性值是从源属性的值设置的。 但是,在某些情况下,数据也可以从目标流向源,或者双向流动。
重要
目标始终是在其上设置数据绑定的对象,即使它提供数据而不接收数据也是如此。
使用绑定上下文绑定
请考虑以下 XAML 示例,其目的是通过操作 Slider 来旋转 Label:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicCodeBindingPage"
Title="Basic Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="48"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="Center" />
</StackLayout>
</ContentPage>
如果没有数据绑定,你可以将 Slider 的 ValueChanged
事件设置为访问 Slider 的 Value
属性的事件处理程序,并将该值设置为 Label 的 Rotation
属性。 数据绑定会自动执行此任务,因此不再需要事件处理程序及其中的代码。
可以在派生自 BindableObject 的任何类的实例上设置绑定,这些类包括 Element、VisualElement、View 和 View 派生物。 绑定始终在目标对象上进行设置。 绑定引用源对象。 要设置数据绑定,请使用目标类的以下两个成员:
BindingContext
属性指定源对象。SetBinding
方法指定目标属性和源属性。
在本例中,Label 是绑定目标,Slider 是绑定源。 Slider 源中的更改会影响 Label 目标的旋转。 数据从源流向目标。
BindableObject 定义的 SetBinding
方法的参数类型为 BindingBase
,Binding
类从该类派生而来,但 BindableObjectExtensions
类还定义了其他 SetBinding
方法。 XAML 的代码隐藏使用 BindableObjectExtensions
类中更简单的 SetBinding
扩展方法:
public partial class BasicCodeBindingPage : ContentPage
{
public BasicCodeBindingPage()
{
InitializeComponent();
label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
}
}
Label 对象是绑定目标,因此它是设置该属性和调用该方法的对象。 BindingContext
属性指示绑定源 Slider。 SetBinding
方法在绑定目标上进行调用,但需同时指定目标属性和源属性。 目标属性指定为 BindableProperty 对象:Label.RotationProperty
。 源属性指定为字符串,并指示 Slider 的 Value
属性。
重要
目标属性必须由可绑定属性支持。 因此,目标对象必须是派生自 BindableObject 的类的实例。 有关详细信息,请参阅可绑定布局。
将源属性指定为字符串。 在内部,反射用于访问实际属性。 然而,在这种特殊情况下,Value
属性还受可绑定属性支持。
或者,可以在 XAML 中指定数据绑定:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicXamlBindingPage"
Title="Basic XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="Center"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="Center" />
</StackLayout>
</ContentPage>
正如在代码中一样,数据绑定是在目标对象(即 Label)上设置的。 有两个 XAML 标记扩展可用于定义数据绑定:
- 引用源对象(命名为
slider
的 Slider)需要x:Reference
标记扩展。 Binding
标记扩展将 Label 的Rotation
属性链接到 Slider 的Value
属性。
有关 XAML 标记扩展的详细信息,请参阅使用 XAML 标记扩展。
注意
源属性由 Binding
标记扩展的 Path
属性指定,它对应于 Binding
类的 Path
属性。
XAML 标记扩展名(如 x:Reference
和 Binding
)可以定义“内容属性”属性,对于 XAML 标记扩展,这意味着不需要出现属性名称。 Name
属性是 x:Reference
的内容属性,Path
属性是 Binding
的内容属性,这意味着可以从表达式中删除它们:
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="Center"
BindingContext="{x:Reference slider}"
Rotation="{Binding Value}" />
重要
可以使用已编译的绑定来改进绑定性能。 有关详细信息,请参阅已编译的绑定。
不使用绑定上下文的绑定
BindingContext
属性是数据绑定的重要组件,但并不总是必要的。 可以改为在 SetBinding
调用或 Binding
标记扩展中指定源对象:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeCodeBindingPage"
Title="Alternative Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
在此示例中,定义了 Slider 来控制 Label 的 Scale
属性。 因此,将 Slider 设置为介于 -2 到 2 之间。
代码隐藏文件使用 SetBinding
方法设置绑定,其中第二个参数是 Binding
类的构造函数:
public partial class AlternativeCodeBindingPage : ContentPage
{
public AlternativeCodeBindingPage()
{
InitializeComponent();
label.SetBinding(Label.ScaleProperty, new Binding("Value", source: slider));
}
}
Binding
构造函数有 6 个参数,因此 source
参数是用命名参数指定的。 该参数是 slider
对象。
注意
VisualElement 类还定义了 ScaleX
和 ScaleY
属性,这些属性可以在水平和垂直方向上以不同方式缩放 VisualElement。
或者,可以在 XAML 中指定数据绑定:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeXamlBindingPage"
Title="Alternative XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="Center"
Scale="{Binding Source={x:Reference slider},
Path=Value}" />
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="Center" />
</StackLayout>
</ContentPage>
在此示例中,Binding
标记扩展设置了两个属性,即 Source
和 Path
,用逗号分隔。 Source
属性设置为嵌入的 x:Reference
标记扩展,否则具有与设置 BindingContext
相同的语法。
Binding
标记扩展的内容属性是 Path
,但是标记扩展的 Path=
部分只有在它是表达式中的第一个属性时才能被删除。 若要消除 Path=
部分,需要交换这两个属性:
Scale="{Binding Value, Source={x:Reference slider}}" />
尽管 XAML 标记扩展通常由大括号分隔,但它们也可以表示为对象元素:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label.Scale>
<Binding Source="{x:Reference slider}"
Path="Value" />
</Label.Scale>
</Label>
在此示例中,Source
和 Path
属性是常规 XAML 特性。 值出现在引号中,属性之间没有逗号分隔。 x:Reference
标记扩展也可以成为对象元素:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label.Scale>
<Binding Path="Value">
<Binding.Source>
<x:Reference Name="slider" />
</Binding.Source>
</Binding>
</Label.Scale>
</Label>
这种语法并不常见,但当涉及到复杂对象时,有时它也是必要的。
到目前为止显示的示例将 Binding
的 BindingContext
属性和 Source
属性设置为 x:Reference
标记扩展,以引用页面上的另一个视图。 这两个属性的类型是 Object
,可以将它们设置为包含适合绑定源的属性的任何对象。 还可以将 BindingContext
或 Source
属性设置为 x:Static
标记扩展以引用静态属性或字段的值,或将 StaticResource
标记扩展设置为引用存储在资源字典中的对象,或直接设置为通常是 viewmodel 实例的对象。
注意
还可以将 BindingContext
属性设置为 Binding
对象,以便 Binding
的 Source
和 Path
属性定义绑定上下文。
绑定上下文继承
可以使用 Binding
对象的 BindingContext
属性或 Source
属性指定源对象。 如果两者都已设置,则 Binding
的 Source
属性优先于 BindingContext
。
重要
BindingContext
属性值是通过可视化树继承的。
以下 XAML 示例演示了绑定上下文继承:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BindingContextInheritancePage"
Title="BindingContext Inheritance">
<StackLayout Padding="10">
<StackLayout VerticalOptions="Fill"
BindingContext="{x:Reference slider}">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="End"
Rotation="{Binding Value}" />
<BoxView Color="#800000FF"
WidthRequest="180"
HeightRequest="40"
HorizontalOptions="Center"
VerticalOptions="Start"
Rotation="{Binding Value}" />
</StackLayout>
<Slider x:Name="slider"
Maximum="360" />
</StackLayout>
</ContentPage>
在此示例中,StackLayout 的 BindingContext
属性被设置为 slider
对象。 该绑定上下文由 Label 和 BoxView 继承,它们的 Rotation
属性都设置为 Slider 的 Value
属性: