共用方式為


系結模式

Browse sample. 流覽範例

每個 .NET 多平臺應用程式 UI (.NET MAUI) 可系結屬性都有預設系結模式,可在建立可系結屬性時設定,而且可從 DefaultBindingMode 物件的 屬性 BindableProperty 取得。 這個預設繫結模式表示當該屬性是資料繫結目標時,模式即已生效。 針對 RotationScaleOpacity 等大部分屬性,預設繫結模式是 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 是目標。 繫結參考 LabelOpacity 屬性,其預設值為 1。 因此, Slider 會從的初始 OpacityLabel初始化為值 1。 這會顯示在下列螢幕快照中:

Reverse binding.

此外,仍 Slider 可繼續運作。 這是因為的屬性Slider的預設系結模式ValueTwoWay。 這表示當 屬性是數據系結目標時 Value ,則會從來源設定目標,但來源也會從目標設定。 這可讓 Slider 從初始 Opacity 值設定 。

注意

除非屬性實際變更,否則可系結屬性不會發出屬性變更的訊號。 這可防止無限迴圈。

如果目標屬性上的預設系結模式不適用於特定數據系結,可以將 的 屬性設定為 (或Mode標記延伸的 BindingBindingMode 屬性Binding)設定為其中一個列舉的成員,以覆寫它Mode

  • Default
  • TwoWay — 資料在來源和目標之間雙向
  • OneWay — 資料會從來源到目標
  • OneWayToSource — 資料會從目標到來源
  • OneTime— 資料會從來源移至目標,但只有在變更時BindingContext

雙向系結

大部分可系結的屬性都有的預設系結模式 OneWay ,但某些屬性的預設系結模式 TwoWay為 ,包括下列專案:

這些屬性會定義為 TwoWay ,因為當數據系結與Model-View-ViewModel (MVVM) 模式搭配使用時,viewmodel 類別是數據系結來源,而檢視是由這類 Slider檢視所組成的檢視都是數據系結目標。 MVVM 系結與上述範例類似,因為您可能希望頁面上的每個檢視都以 viewmodel 中對應屬性的值初始化,但檢視中的變更也會影響 viewmodel 屬性。

單向來源系結

唯讀可繫結屬性的預設繫結模式為 OneWayToSource。 例如, SelectedItemListView 屬性具有的預設系結模式 OneWayToSource。 這是因為 屬性上的 SelectedItem 系結應該會導致設定系結來源。

一次性系結

繫結模式為 OneTime 的目標屬性只有在繫結內容變更時才會更新。 針對這些目標屬性的繫結,這麼做可以簡化繫結基礎結構,因為不需要監視來源屬性中的變更。

有數個屬性的預設繫結模式為 OneTime,包含 EntryIsTextPredictionEnabled 屬性。

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"));
            }
        }
    }
}

在此範例中,類別 HslColorViewModelHue定義 、 SaturationLuminosityColor、 和 Name 屬性。 當三個色彩元件中的任何一個變更值時, Color 就會重新計算 屬性,並 PropertyChanged 針對這四個屬性引發事件。 當Color屬性變更時,類別中的NamedColor靜態GetNearestColorName方法會取得最接近的具名色彩,並設定 Name 屬性。

當 viewmodel 設定為系結來源時,系結基礎結構會將處理程式附加至 PropertyChanged 事件。 如此一來,系結就可以收到屬性變更的通知,然後可以從變更的值設定目標屬性。 不過,當目標屬性 (或目標屬性上的 Binding 定義) 具有 OneTimeBindingMode 時,繫結基礎結構就不需要將處理常式附加到 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 屬性集,並設定為頁面的 BindingContextBoxViewLabel 和三個 Slider 檢視會繼承 ContentPage 的繫結內容。 這些檢視都是參考 viewmodel 中來源屬性的系結目標。 Color對於 的 屬性BoxViewTextLabel屬性,數據系結為 OneWay - 檢視中的屬性會從 viewmodel 中的屬性設定。 Value不過,的 Slider屬性會使用TwoWay系結模式。 這可讓每一個 Slider 都從 viewmodel 進行設定,也讓 viewmodel 從每個 Slider設定。

第一次執行範例時,BoxView會根據 ViewModel 具現化時所設定的初始Color屬性,從 viewmodel 設定 、 Label和 三Slider個元素:

Simple color selector.

當您操作滑桿時, BoxViewLabel 會據以更新。

覆寫系結模式

您可以藉由將 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 類別也會定義 ScaleXScaleY 屬性,它們可以在水平和垂直方向以不同的方式調整 VisualElement

使用系結模式覆寫預設系結模式 TwoWay 的非常有用應用程式,牽涉到 SelectedItemListView屬性。 預設繫結模式為 OneWayToSource。 在 屬性上 SelectedItem 設定數據系結以參考 ViewModel 中的來源屬性時,就會從 ListView 選取範圍設定該來源屬性。 不過,在某些情況下,您可能也會想要 ListView 從 viewmodel 初始化 。

重要

默認系結模式可能會因控件而異,而且會在建立可系結屬性時設定。 它可從 DefaultBindingMode 物件的 屬性 BindableProperty 取得。