共用方式為


數據系結基本概念

流覽範例。 流覽範例

.NET 多平臺應用程式 UI (.NET MAUI) 數據系結允許連結兩個對象的屬性,讓其中一個對象的變更造成另一個對象的變更。 這是一個非常有價值的工具,雖然數據系結可以完全在程式碼中定義,但 XAML 提供快捷方式和便利性。

數據系結

數據系結會連接兩個物件的屬性,稱為 來源目標。 在程序代碼中,需要兩個步驟:

  1. 目標 BindingContext 物件的 屬性必須設定為來源物件,
  2. SetBinding方法(通常與 Binding 類別搭配使用)必須在目標物件上呼叫,才能將該對象的 屬性系結至來源物件的屬性。

目標屬性必須是可繫結的屬性,這表示目標對象必須衍生自 BindableObject。 的屬性 Label,例如 Text,與可系結屬性 TextProperty相關聯。

在 XAML 中,您也必須執行程式碼中所需的相同兩個步驟,但 Binding 標記延伸會取代 SetBinding 呼叫和 Binding 類別。 不過,當您在 XAML 中定義資料系結時,有多種方式可以設定 BindingContext 目標物件的 。 有時候會從程式代碼後置檔案進行設定,有時使用 StaticResourcex:Static 標記延伸,有時則是屬性元素標記的內容 BindingContext

檢視對檢視系結

您可以定義數據系結,以連結相同頁面上兩個檢視的屬性。 在這裡情況下,您會使用x:Reference標記延伸來設定BindingContext目標物件的 。

下列範例包含 和 SliderLabel 個檢視,其中一個是由 Slider 值旋轉,另一個則顯示 Slider 值:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SliderBindingsPage"
             Title="Slider Bindings Page">
    <StackLayout>
        <Label Text="ROTATION"
               BindingContext="{x:Reference slider}"
               Rotation="{Binding Path=Value}"
               FontAttributes="Bold"
               FontSize="18"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <Slider x:Name="slider"
                Maximum="360"
                VerticalOptions="Center" />
        <Label BindingContext="{x:Reference slider}"
               Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"
               FontAttributes="Bold"
               FontSize="18"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
    </StackLayout>
</ContentPage>

Slider包含使用標記延伸之兩Labelx:Name檢視x:Reference所參考的屬性。 系 x:Reference 結延伸會定義名為 Name 的屬性,以設定為參考項目的名稱,在此案例 slider中為 。 不過, ReferenceExtension 定義標記延伸的 x:Reference 類別也會定義 ContentProperty 的屬性 Name,這表示它並非明確必要。

Binding標記延伸本身可以有數個屬性,就像和 Binding 類別一樣BindingBaseContentProperty Binding的 是 Path,但如果路徑是標記延伸中的第一個專案,則可以省略標記延伸的 Binding “Path=” 部分。

第二個 Binding 標記延伸會設定 StringFormat 屬性。 在 .NET MAUI 中,系結不會執行任何隱含類型轉換,而且如果您需要將非字串對象顯示為字串,則必須提供類型轉換器或使用 StringFormat

重要

格式化字串必須放在單引號中。

繫結模式

單一檢視可以在其數個屬性上具有數據系結。 不過,每個檢視只能有一個 BindingContext,因此該檢視上的多個數據系結必須擁有相同物件的所有參考屬性。

這個和其他問題的解決方案牽 Mode 涉到 屬性,該屬性會設定為 列舉的成員 BindingMode

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

下列範例示範 和 TwoWay 系結模式的OneWayToSource一個常見用法:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SliderTransformsPage"
             Padding="5"
             Title="Slider Transforms Page">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <!-- Scaled and rotated Label -->
        <Label x:Name="label"
               Text="TEXT"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <!-- Slider and identifying Label for Scale -->
        <Slider x:Name="scaleSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="1" Grid.Column="0"
                Maximum="10"
                Value="{Binding Scale, Mode=TwoWay}" />
        <Label BindingContext="{x:Reference scaleSlider}"
               Text="{Binding Value, StringFormat='Scale = {0:F1}'}"
               Grid.Row="1" Grid.Column="1"
               VerticalTextAlignment="Center" />

        <!-- Slider and identifying Label for Rotation -->
        <Slider x:Name="rotationSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="2" Grid.Column="0"
                Maximum="360"
                Value="{Binding Rotation, Mode=OneWayToSource}" />
        <Label BindingContext="{x:Reference rotationSlider}"
               Text="{Binding Value, StringFormat='Rotation = {0:F0}'}"
               Grid.Row="2" Grid.Column="1"
               VerticalTextAlignment="Center" />

        <!-- Slider and identifying Label for RotationX -->
        <Slider x:Name="rotationXSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="3" Grid.Column="0"
                Maximum="360"
                Value="{Binding RotationX, Mode=OneWayToSource}" />
        <Label BindingContext="{x:Reference rotationXSlider}"
               Text="{Binding Value, StringFormat='RotationX = {0:F0}'}"
               Grid.Row="3" Grid.Column="1"
               VerticalTextAlignment="Center" />

        <!-- Slider and identifying Label for RotationY -->
        <Slider x:Name="rotationYSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="4" Grid.Column="0"
                Maximum="360"
                Value="{Binding RotationY, Mode=OneWayToSource}" />
        <Label BindingContext="{x:Reference rotationYSlider}"
               Text="{Binding Value, StringFormat='RotationY = {0:F0}'}"
               Grid.Row="4" Grid.Column="1"
               VerticalTextAlignment="Center" />
    </Grid>
</ContentPage>

在此範例中,四SliderLabel檢視是用來控制 Scale的、 RotateXRotate、 和 RotateY 屬性。 起初,這似乎這四個 Label 屬性應該是數據系結目標,因為每個屬性都是由 所 Slider設定。 不過, BindingContextLabel 只能是一個 物件,而且有四個不同的滑桿。 因此, BindingContext 四個滑桿中每個滑桿的 都設定為 Label,而且系結會設定在滑桿的屬性上 Value 。 藉由使用 OneWayToSourceTwoWay 模式,這些 Value 屬性可以設定來源屬性,也就是 Scale的、 RotateRotateXRotateY 屬性 Label

三個 Slider 檢視上的系結是 OneWayToSource,這表示 Slider 值會導致其 BindingContext的屬性變更,也就是 Label 具名 label的 。 這三Slider個檢視會導致的、 RotateXRotateY 屬性Label變更Rotate

反向系結。

不過,屬性的 Scale 系結是 TwoWay。 這是因為 Scale 屬性的預設值為1,而使用 TwoWay 系結會導致 Slider 初始值設定為1而不是0。 如果該系結為 OneWayToSource,則 Scale 屬性一開始會從 Slider 預設值設定為0。 Label不會顯示 。

注意

類別 VisualElement 也有 ScaleXScaleY 屬性,分別在 x 軸和 Y 軸上縮放 VisualElement

系結和集合

ListViewItemsSource 定義 類型的 IEnumerable屬性,並顯示該集合中的專案。 這些專案可以是任何類型的物件。 根據預設, ListView 會使用 ToString 每個專案的 方法來顯示該專案。 有時候這隻是您想要的,但在許多情況下, ToString 只會傳回物件的完整類別名稱。

不過,您可以透過使用範本,以任何方式顯示集合中的ListView專案,其中包含衍生自 Cell的類別。 範本會針對 中 ListView設定的每個專案複製範本,而且範本上設定的數據系結會傳送至個別複製品。 您可以使用 類別為專案 ViewCell 建立自訂儲存格。

ListView 可以透過 類別的協助 NamedColor ,顯示 .NET MAUI 中可用之每個具名色彩的清單:

using System.Reflection;
using System.Text;

namespace XamlSamples
{
    public class NamedColor
    {
        public string Name { get; private set; }
        public string FriendlyName { get; private set; }
        public Color Color { get; private set; }

        // Expose the Color fields as properties
        public float Red => Color.Red;
        public float Green => Color.Green;
        public float Blue => Color.Blue;

        public static IEnumerable<NamedColor> All { get; private set; }

        static NamedColor()
        {
            List<NamedColor> all = new List<NamedColor>();
            StringBuilder stringBuilder = new StringBuilder();

            // Loop through the public static fields of the Color structure.
            foreach (FieldInfo fieldInfo in typeof(Colors).GetRuntimeFields())
            {
                if (fieldInfo.IsPublic &&
                    fieldInfo.IsStatic &&
                    fieldInfo.FieldType == typeof(Color))
                {
                    // Convert the name to a friendly name.
                    string name = fieldInfo.Name;
                    stringBuilder.Clear();
                    int index = 0;

                    foreach (char ch in name)
                    {
                        if (index != 0 && Char.IsUpper(ch))
                        {
                            stringBuilder.Append(' ');
                        }
                        stringBuilder.Append(ch);
                        index++;
                    }

                    // Instantiate a NamedColor object.
                    NamedColor namedColor = new NamedColor
                    {
                        Name = name,
                        FriendlyName = stringBuilder.ToString(),
                        Color = (Color)fieldInfo.GetValue(null)
                    };

                    // Add it to the collection.
                    all.Add(namedColor);
                }
            }
            all.TrimExcess();
            All = all;
        }
    }
}

每個NamedColor物件都有 Name 類型的 和 FriendlyName 屬性、Color類型stringColor為、 和RedGreen、 和 Blue 屬性的屬性。 此外,靜態建NamedColor構函式會建立集合IEnumerable<NamedColor>,其中包含NamedColor對應至 類別中ColorsColor別字段的物件,並將它指派給其公用靜態All屬性。

您可以使用x:Static標記延伸,將靜態NamedColor.All屬性設定為 ItemsSourceListView

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
             x:Class="XamlSamples.ListViewDemoPage"
             Title="ListView Demo Page">
    <ListView ItemsSource="{x:Static local:NamedColor.All}" />
</ContentPage>

結果會建立項目的類型 XamlSamples.NamedColor為 :

系結至集合。

若要定義項目的樣本, ItemTemplate 應該將 設定為 DataTemplate 參考 的 ViewCellViewCell應該定義一或多個檢視的配置,以顯示每個專案:

<ListView ItemsSource="{x:Static local:NamedColor.All}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Label Text="{Binding FriendlyName}" />
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

注意

單元格和儲存格子系的系結來源是 ListView.ItemsSource 集合。

在此範例中,元素 Label 會設定為 ViewViewCell屬性。 ViewCell.View不需要標記,View因為 屬性是 的內容ViewCell屬性。 此 XAML 會顯示 FriendlyName 每個 NamedColor 物件的 屬性:

使用 DataTemplate 系結至集合。

專案範本可以展開以顯示更多資訊和實際色彩:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             x:Class="XamlSamples.ListViewDemoPage"
             Title="ListView Demo Page">
    <ContentPage.Resources>
        <x:Double x:Key="boxSize">50</x:Double>
        <x:Int32 x:Key="rowHeight">60</x:Int32>
        <local:FloatToIntConverter x:Key="intConverter" />
    </ContentPage.Resources>

    <ListView ItemsSource="{x:Static local:NamedColor.All}"
              RowHeight="{StaticResource rowHeight}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Padding="5, 5, 0, 5"
                                 Orientation="Horizontal"
                                 Spacing="15">
                        <BoxView WidthRequest="{StaticResource boxSize}"
                                 HeightRequest="{StaticResource boxSize}"
                                 Color="{Binding Color}" />
                        <StackLayout Padding="5, 0, 0, 0"
                                     VerticalOptions="Center">
                            <Label Text="{Binding FriendlyName}"
                                   FontAttributes="Bold"
                                   FontSize="14" />
                            <StackLayout Orientation="Horizontal"
                                         Spacing="0">
                                <Label Text="{Binding Red,
                                                      Converter={StaticResource intConverter},
                                                      ConverterParameter=255,
                                                      StringFormat='R={0:X2}'}" />                                
                                <Label Text="{Binding Green,
                                                      Converter={StaticResource intConverter},
                                                      ConverterParameter=255,
                                                      StringFormat=', G={0:X2}'}" />                                
                                <Label Text="{Binding Blue,
                                                      Converter={StaticResource intConverter},
                                                      ConverterParameter=255,
                                                      StringFormat=', B={0:X2}'}" />
                            </StackLayout>
                        </StackLayout>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>

系結值轉換器

上一個 XAML 範例會顯示每個 NamedColor的個別RedGreenBlue 屬性。 這些屬性的類型 float 和範圍從 0 到 1。 如果您想要顯示十六進位值,則不能只搭配 「X2」 格式規格使用 StringFormat 。 這隻適用於整數和此外,值 float 必須乘以 255。

這個問題可以使用值轉換器來解決,也稱為系結轉換器 這是實作 介面的 IValueConverter 類別,這表示它有兩個名為 ConvertConvertBack的方法。 當 Convert 值從來源傳輸至目標時,會呼叫 方法。 方法ConvertBack會呼叫 ,以便從目標傳輸至 或 TwoWay 系結中的OneWayToSource來源:

using System.Globalization;

namespace XamlSamples
{
    public class FloatToIntConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            float multiplier;

            if (!float.TryParse(parameter as string, out multiplier))
                multiplier = 1;

            return (int)Math.Round(multiplier * (float)value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            float divider;

            if (!float.TryParse(parameter as string, out divider))
                divider = 1;

            return ((float)(int)value) / divider;
        }
    }
}

注意

方法 ConvertBack 在此範例中不會扮演角色,因為系結只是從來源到目標的一種方式。

系結會參考具有 屬性的 Converter 系結轉換子。 係結轉換器也可以接受以 ConverterParameter 屬性指定的參數。 對於某些多功能性,這就是指定乘數的方式。 系結轉換器會檢查轉換器參數是否有有效的 float 值。

轉換器會在頁面的資源字典中具現化,以便在多個系結之間共用:

<local:FloatToIntConverter x:Key="intConverter" />

三個數據系結會參考這個單一實例:

<Label Text="{Binding Red,
                      Converter={StaticResource intConverter},
                      ConverterParameter=255,
                      StringFormat='R={0:X2}'}" />

專案範本會播放色彩、其易記名稱,以及其 RGB 值:

使用 DataTemplate 和轉換器系結至集合。

ListView可以處理動態發生在基礎數據中的變更,但只有在您採取特定步驟時。 如果指派給 ItemsSource 運行時間期間變更屬性 ListView 的專案集合,請使用 ObservableCollection<T> 類別做為這些專案。 ObservableCollection<T> 會實作 INotifyCollectionChanged 介面,並 ListView 會安裝 事件的處理程式 CollectionChanged

如果專案的屬性在運行時間本身變更,則集合中的專案應該實 INotifyPropertyChanged 作 介面,並使用 PropertyChanged 事件向屬性值發出變更訊號。

下一步

數據系結提供強大的機制,可在頁面內的兩個對象之間,或可視化對象與基礎數據之間連結屬性。 但是當應用程式開始使用數據源時,熱門的應用程式架構模式會開始以有用的範例形式出現。