系結模式
每個 .NET 多平臺應用程式 UI (.NET MAUI) 可系結屬性都有預設系結模式,可在建立可系結屬性時設定,而且可從 DefaultBindingMode
物件的 屬性 BindableProperty 取得。 這個預設繫結模式表示當該屬性是資料繫結目標時,模式即已生效。 針對 Rotation
、Scale
和 Opacity
等大部分屬性,預設繫結模式是 OneWay
。 當這些屬性是資料繫結目標時,即會從來源設定目標屬性。
下列範例顯示 上 Slider定義的數據系結:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.ReverseBindingPage"
Title="Reverse Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Slider x:Name="slider"
VerticalOptions="Center"
Value="{Binding Source={x:Reference label},
Path=Opacity}" />
</StackLayout>
</ContentPage>
在此範例中, Label 是數據系結來源,而 Slider 是目標。 繫結參考 Label 的 Opacity
屬性,其預設值為 1。 因此, Slider 會從的初始 Opacity
值 Label初始化為值 1。 這會顯示在下列螢幕快照中:
此外,仍 Slider 可繼續運作。 這是因為的屬性Slider的預設系結模式Value
是 TwoWay
。 這表示當 屬性是數據系結目標時 Value
,則會從來源設定目標,但來源也會從目標設定。 這可讓 Slider 從初始 Opacity
值設定 。
注意
除非屬性實際變更,否則可系結屬性不會發出屬性變更的訊號。 這可防止無限迴圈。
如果目標屬性上的預設系結模式不適用於特定數據系結,可以將 的 屬性設定為 (或Mode
標記延伸的 Binding
BindingMode
屬性Binding
)設定為其中一個列舉的成員,以覆寫它Mode
:
Default
TwoWay
— 資料在來源和目標之間雙向OneWay
— 資料會從來源到目標OneWayToSource
— 資料會從目標到來源OneTime
— 資料會從來源移至目標,但只有在變更時BindingContext
雙向系結
大部分可系結的屬性都有的預設系結模式 OneWay
,但某些屬性的預設系結模式 TwoWay
為 ,包括下列專案:
- DatePicker 的
Date
屬性 - Editor、Entry、SearchBar 及 EntryCell 的
Text
屬性 - ListView 的
IsRefreshing
屬性 MultiPage
的SelectedItem
屬性- Picker 的
SelectedIndex
和SelectedItem
屬性 - Slider和 Stepper 的
Value
屬性 - Switch 的
IsToggled
屬性 - SwitchCell 的
On
屬性 - TimePicker 的
Time
屬性
這些屬性會定義為 TwoWay
,因為當數據系結與Model-View-ViewModel (MVVM) 模式搭配使用時,viewmodel 類別是數據系結來源,而檢視是由這類 Slider檢視所組成的檢視都是數據系結目標。 MVVM 系結與上述範例類似,因為您可能希望頁面上的每個檢視都以 viewmodel 中對應屬性的值初始化,但檢視中的變更也會影響 viewmodel 屬性。
單向來源系結
唯讀可繫結屬性的預設繫結模式為 OneWayToSource
。 例如, SelectedItem
的 ListView 屬性具有的預設系結模式 OneWayToSource
。 這是因為 屬性上的 SelectedItem
系結應該會導致設定系結來源。
一次性系結
繫結模式為 OneTime
的目標屬性只有在繫結內容變更時才會更新。 針對這些目標屬性的繫結,這麼做可以簡化繫結基礎結構,因為不需要監視來源屬性中的變更。
有數個屬性的預設繫結模式為 OneTime
,包含 Entry 的 IsTextPredictionEnabled
屬性。
Viewmodels 和屬性變更通知
在數據系結中使用 viewmodel 時,viewmodel 是數據系結來源。 viewmodel 不會定義可系結的屬性,但會實作通知機制,讓系結基礎結構在屬性值變更時收到通知。 此通知機制是 INotifyPropertyChanged
介面,其會定義名為 PropertyChanged
的單一事件。 實作這個介面的類別通常會在其中一個公用屬性變更值時引發 事件。 如果屬性永遠不會變更,則不需要引發 事件。 介面 INotifyPropertyChanged
也會由 BindableObject 實作, PropertyChanged
而且每當可系結屬性變更值時,就會引發 事件。
在下列範例中,數據系結可讓您針對色調、飽和度和亮度使用三 Slider 個元素來選取色彩:
public class HslColorViewModel : INotifyPropertyChanged
{
Color color;
string name;
float hue;
float saturation;
float luminosity;
public event PropertyChangedEventHandler PropertyChanged;
public float Hue
{
get
{
return hue;
}
set
{
if (hue != value)
{
Color = Color.FromHsla(value, saturation, luminosity);
}
}
}
public float Saturation
{
get
{
return saturation;
}
set
{
if (saturation != value)
{
Color = Color.FromHsla(hue, value, luminosity);
}
}
}
public float Luminosity
{
get
{
return luminosity;
}
set
{
if (luminosity != value)
{
Color = Color.FromHsla(hue, saturation, value);
}
}
}
public Color Color
{
get
{
return color;
}
set
{
if (color != value)
{
color = value;
hue = color.GetHue();
saturation = color.GetSaturation();
luminosity = color.GetLuminosity();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Hue"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Saturation"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Luminosity"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));
Name = NamedColor.GetNearestColorName(color);
}
}
}
public string Name
{
get
{
return name;
}
private set
{
if (name != value)
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
在此範例中,類別 HslColorViewModel
會 Hue
定義 、 Saturation
、 Luminosity
、 Color
、 和 Name
屬性。 當三個色彩元件中的任何一個變更值時, Color
就會重新計算 屬性,並 PropertyChanged
針對這四個屬性引發事件。 當Color
屬性變更時,類別中的NamedColor
靜態GetNearestColorName
方法會取得最接近的具名色彩,並設定 Name
屬性。
當 viewmodel 設定為系結來源時,系結基礎結構會將處理程式附加至 PropertyChanged
事件。 如此一來,系結就可以收到屬性變更的通知,然後可以從變更的值設定目標屬性。 不過,當目標屬性 (或目標屬性上的 Binding
定義) 具有 OneTime
的 BindingMode
時,繫結基礎結構就不需要將處理常式附加到 PropertyChanged
事件。 只有在 BindingContext
變更時 (而非來源屬性本身變更時),才會更新目標屬性。
下列 XAML 會取用 HslColorViewModel
:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.SimpleColorSelectorPage">
<ContentPage.BindingContext>
<local:HslColorViewModel Color="MediumTurquoise" />
</ContentPage.BindingContext>
<ContentPage.Resources>
<Style TargetType="Slider">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<BoxView Color="{Binding Color}"
Grid.Row="0" />
<StackLayout Grid.Row="1"
Margin="10, 0">
<Label Text="{Binding Name}"
HorizontalTextAlignment="Center" />
<Slider Value="{Binding Hue}" />
<Slider Value="{Binding Saturation}" />
<Slider Value="{Binding Luminosity}" />
</StackLayout>
</Grid>
</ContentPage>
在這裡範例中,會 HslColorViewModel
具現化 和 Color
屬性集,並設定為頁面的 BindingContext
。 BoxView、Label 和三個 Slider 檢視會繼承 ContentPage 的繫結內容。 這些檢視都是參考 viewmodel 中來源屬性的系結目標。 Color
對於 的 屬性BoxView和 Text
的 Label屬性,數據系結為 OneWay
- 檢視中的屬性會從 viewmodel 中的屬性設定。 Value
不過,的 Slider屬性會使用TwoWay
系結模式。 這可讓每一個 Slider 都從 viewmodel 進行設定,也讓 viewmodel 從每個 Slider設定。
第一次執行範例時,BoxView會根據 ViewModel 具現化時所設定的初始Color
屬性,從 viewmodel 設定 、 Label和 三Slider個元素:
當您操作滑桿時, BoxView 和 Label 會據以更新。
覆寫系結模式
您可以藉由將 Mode
標記延伸的 Binding
屬性Binding
設定Mode
為列舉的其中一個成員,以覆寫目標屬性的BindingMode
系結模式。
不過,設定 Mode
屬性不一定會產生預期的結果。 例如,在下列範例中,將 Mode
屬性設定為 TwoWay
無法如您所預期般運作:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value,
Mode=TwoWay}" />
在此範例中,可能會預期 Slider 將 初始化為 屬性的初始值 Scale
,也就是 1,但這不會發生。 當 TwoWay
繫結初始化時,會先從來源設定目標,這表示 Scale
屬性會設為 Slider 預設值 0。 當 Slider 設定了 TwoWay
繫結時,一開始會從來源設定 Slider。
或者,您可以將繫結模式設定為 OneWayToSource
:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value,
Mode=OneWayToSource}" />
Slider現在 ,會初始化為1(預設值Scale
為),但操作 Slider 不會影響 Scale
屬性。
注意
VisualElement 類別也會定義 ScaleX
和 ScaleY
屬性,它們可以在水平和垂直方向以不同的方式調整 VisualElement。
使用系結模式覆寫預設系結模式 TwoWay
的非常有用應用程式,牽涉到 SelectedItem
的 ListView屬性。 預設繫結模式為 OneWayToSource
。 在 屬性上 SelectedItem
設定數據系結以參考 ViewModel 中的來源屬性時,就會從 ListView 選取範圍設定該來源屬性。 不過,在某些情況下,您可能也會想要 ListView 從 viewmodel 初始化 。
重要
默認系結模式可能會因控件而異,而且會在建立可系結屬性時設定。 它可從 DefaultBindingMode
物件的 屬性 BindableProperty 取得。