編譯的系結
.NET 多平臺應用程式 UI (.NET MAUI) 資料系結有兩個主要問題:
- 無法在編譯時間驗證繫結運算式。 相反地,繫結是在執行階段進行解析。 因此,當應用程式不如預期般運作或出現錯誤訊息時,要到執行階段才會偵測到任何無效的繫結。
- 不符合成本效益。 繫結使用一般用途物件檢查 (反射) 在執行階段進行解析,而執行此作業的成本會因平台而異。
編譯的系結可藉由在編譯時期解析系結運算式,而不是執行時間,來改善 .NET MAUI 應用程式中的資料系結效能。 此外,在編譯時間驗證繫結運算式可改善開發人員的疑難排解體驗,因為無效的繫結會回報為建置錯誤。
若要使用編譯的系結,請將 上的 VisualElement 屬性設定 x:DataType
為 和 其子系系所系結之 物件的 VisualElement 型別。 建議在檢視階層架構中與設定 BindingContext
相同的層級設定 x:DataType
屬性。 不過,這個屬性可以在檢視階層中的任何位置重新定義。
注意
編譯的系結需要使用預設在 .NET MAUI 中啟用的 XAML 編譯。 如果您已停用 XAML 編譯,則必須啟用它。 如需詳細資訊,請參閱 XAML 編譯。
若要使用編譯的系結, x:DataType
屬性必須設定為字串常值,或使用標記延伸的類型 x:Type
。 在 XAML 編譯期間,任何無效的繫結運算式都會回報為建置錯誤。 不過,XAML 編譯器只會在第一次遇到無效的繫結運算式時回報建置錯誤。 定義於 VisualElement 或其子系的任何有效繫結運算式都會經過編譯,無論 BindingContext
是在 XAML 或程式碼中設定。 編譯繫結運算式會產生經過編譯的程式碼,該程式碼會從「來源」屬性取得一個值,並在標記中指定的「目標」屬性上進行設定。 此外,視繫結運算式而定,產生的程式碼可以在「來源」屬性值中觀察變更並重新整理「目標」屬性,也可以將變更從「目標」推送回到「來源」。
重要
已編譯的系結會針對定義 Source
屬性的任何系結運算式停用。 這是因為 Source
屬性一律使用 x:Reference
標記延伸設定,因此無法在編譯時間進行解析。
此外,多重系結目前不支援編譯的系結。
使用編譯的繫結
下列範例示範如何在 .NET MAUI 檢視和 viewmodel 屬性之間使用已編譯的系結:
<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.CompiledColorSelectorPage"
x:DataType="local:HslColorViewModel"
Title="Compiled Color Selector">
<ContentPage.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</ContentPage.BindingContext>
...
<StackLayout>
<BoxView Color="{Binding Color}"
... />
<StackLayout Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ContentPage>
具 ContentPage 現化 , HslColorViewModel
並在 屬性的屬性專案標記 BindingContext
內初始化 Color
屬性。 ContentPage也會將 屬性定義為 x:DataType
viewmodel 類型,表示將編譯檢視階層中的任何 ContentPage 系結運算式。 您可以藉由變更任何系結運算式以系結至不存在的 viewmodel 屬性來驗證此情況,這會導致建置錯誤。 雖然這個範例會將 x:DataType
屬性設定為字串常值,但它也可以設定為具有標記延伸的類型 x:Type
。 如需標記延伸的詳細資訊 x:Type
,請參閱 x:Type 標記延伸 。
重要
您可以在檢視階層架構中的任何位置重新定義 x:DataType
屬性。
BoxView、Label 項目和 Slider 檢視會繼承 ContentPage 的繫結內容。 這些檢視都是參考 viewmodel 中來源屬性的系結目標。 BoxView.Color
針對 屬性和 Label.Text
屬性,資料系結為 OneWay
– 檢視中的屬性會從 viewmodel 中的屬性設定。 不過,Slider.Value
屬性使用 TwoWay
繫結。 這可讓每一個 Slider 都從 viewmodel 進行設定,也允許從每個 Slider 設定 viewmodel。
第一次執行範例時, BoxView 會根據 ViewModel 具現化時所設定的初始 Color
屬性,從 viewmodel 設定 、 Label 元素和 Slider 元素。 當滑杆被操作時, BoxView 和 Label 元素會據以更新:
如需此色彩選取器的詳細資訊,請參閱 ViewModels 和屬性變更通知 。
在 DataTemplate 中使用已編譯的系結
DataTemplate 中的繫結是在所要樣板化的物件內容中進行解譯。 因此,在 DataTemplate 中使用編譯的繫結時,DataTemplate 必須使用 x:DataType
屬性來宣告其資料物件類型。
下列範例示範如何在 中使用已編譯的 DataTemplate 系結:
<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.CompiledColorListPage"
Title="Compiled Color List">
<Grid>
...
<ListView x:Name="colorListView"
ItemsSource="{x:Static local:NamedColor.All}"
... >
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:NamedColor">
<ViewCell>
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
... />
<Label Text="{Binding FriendlyName}"
... />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- The BoxView doesn't use compiled bindings -->
<BoxView Color="{Binding Source={x:Reference colorListView}, Path=SelectedItem.Color}"
... />
</Grid>
</ContentPage>
ListView.ItemsSource
屬性設定為靜態 NamedColor.All
屬性。 類別 NamedColor
會使用 .NET 反映來列舉 類別中的所有 Colors 靜態公用欄位,並將其名稱儲存在可從靜態 All
屬性存取的集合中。 因此,ListView 會填入所有的 NamedColor
執行個體。 針對 ListView 中的每個項目,項目的繫結內容會設定為 NamedColor
物件。 ViewCell 中的 BoxView 和 Label 項目會繫結至 NamedColor
屬性。
DataTemplate會 x:DataType
定義要做為型別的屬性 NamedColor
,表示將編譯檢視階層中的任何 DataTemplate 系結運算式。 若要進行驗證,請將任何繫結運算式變更為繫結至不存在的 NamedColor
屬性,這會導致建置錯誤。 雖然這個範例會將 x:DataType
屬性設定為字串常值,但它也可以設定為具有標記延伸的類型 x:Type
。 如需標記延伸的詳細資訊 x:Type
,請參閱 x:Type 標記延伸 。
第一次執行範例時,會 ListView 填入 NamedColor
實例。 當選取 ListView 中的項目時,BoxView.Color
屬性會設定為 ListView 中所選項目的色彩:
選取 ListView 中其他項目會更新 BoxView 的色彩。
結合編譯的系結與傳統系結
只有在已定義 x:DataType
屬性的檢視階層架構中才能編譯繫結運算式。 相反地,未定義 x:DataType
屬性之階層架構中的任何檢視則會使用傳統繫結。 因此,您可以將編譯的繫結與傳統繫結合併成一頁。 例如,在上一節中,DataTemplate 中的檢視使用所編譯繫結,而設定為 ListView 中所選色彩的 BoxView 則否。
因此,您可以謹慎建構 x:DataType
屬性,來產生同時使用編譯繫結和傳統繫結的頁面。 或者,您可以在檢視階層架構中的任何位置,使用 x:Null
標記延伸將 x:DataType
屬性重新定義為 null
。 這樣做表示檢視階層架構中的任何繫結運算式都會使用傳統繫結。 下列範例示範此方法:
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />
<StackLayout x:DataType="{x:Null}"
Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
根 StackLayout 會將 x:DataType
屬性設定為 HslColorViewModel
類型,表示根 StackLayout 檢視階層架構中的任何繫結運算式都會經過編譯。 不過,內部 StackLayout 會使用 x:Null
標記延伸將 x:DataType
屬性重新定義為 null
。 因此,內部 StackLayout 中的繫結運算式會使用傳統繫結。 只有根 StackLayout 檢視階層架構中的 BoxView 會使用所編譯繫結。
如需 x:Null
標記延伸的詳細資訊,請參閱 x:Null 標記延伸。
效能
編譯的系結可改善資料系結效能,效能優點不同:
- 使用屬性變更通知之編譯繫結 (例如
OneWay
、OneWayToSource
或TwoWay
繫結) 的解析速度,大致上比傳統繫結快 8 倍。 - 不使用屬性變更通知之編譯繫結 (例如
OneTime
繫結) 的解析速度,大致上比傳統繫結快 20 倍。 - 在使用屬性變更通知的編譯繫結 (例如
OneWay
、OneWayToSource
或TwoWay
繫結) 上設定BindingContext
,大致上比在傳統繫結上設定BindingContext
快 5 倍。 - 在不使用屬性變更通知的編譯繫結 (例如
OneTime
繫結) 上設定BindingContext
,大致上比在傳統繫結上設定BindingContext
快 7 倍。
這些效能差異在行動裝置上可能會更大,視所使用的平台、所使用的作業系統版本,以及執行應用程式的裝置而定。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應