Kompilerade bindningar
Databindningar för .NET Multi-Platform App UI (.NET MAUI) har två huvudsakliga problem:
- Det finns ingen kompileringstidsverifiering av bindningsuttryck. Bindningar löses i stället vid körning. Därför identifieras inte ogiltiga bindningar förrän vid körning när applikationen inte uppträder som förväntat eller felmeddelanden visas.
- De är inte kostnadseffektiva. Bindningar löses vid körning med hjälp av objektgranskning för generell användning (reflektion), och kostnaderna för att göra detta varierar från plattform till plattform.
Kompilerade bindningar förbättrar databindningsprestanda i .NET MAUI-program genom att lösa bindningsuttryck vid kompileringstid istället för körtid. Dessutom möjliggör den här kompileringstidens validering av bindningsuttryck en bättre felsökningsupplevelse för utvecklare eftersom ogiltiga bindningar rapporteras som byggfel.
Viktig
Kompilerade bindningar krävs i stället för strängbaserade bindningar i NativeAOT-appar och i appar med fullständig trimning aktiverad. Mer information finns i Trimma en .NET MAUI-app och Native AOT-distribution.
Kompilerade bindningar i XAML
Om du vill använda kompilerade bindningar i XAML anger du ett x:DataType
-attribut på en VisualElement till den typ av objekt som VisualElement och dess underordnade objekt binder till. Vi rekommenderar att du anger attributet x:DataType
på samma nivå i vyhierarkin som BindingContext anges. Det här attributet kan dock definieras om på valfri plats i en vyhierarki.
Viktig
Kompilerade bindningar kräver användning av XAML-kompilering, vilket är aktiverat som standard i .NET MAUI. Om du har inaktiverat XAML-kompilering måste du aktivera den. Mer information finns i XAML-kompilering.
Om du vill använda kompilerade bindningar i XAML måste attributet x:DataType
anges till en strängliteral eller en typ med hjälp av x:Type
markeringstillägg. Vid XAML-kompileringstillfället rapporteras ogiltiga bindningsuttryck som byggfel. XAML-kompilatorn rapporterar dock bara ett byggfel för det första ogiltiga bindningsuttrycket som det stöter på. Giltiga bindningsuttryck som definieras på VisualElement eller dess underordnade objekt kompileras, oavsett om BindingContext anges i XAML eller kod. Kompilering av ett bindningsuttryck genererar kompilerad kod som hämtar ett värde från en egenskap på källan och sätter det på egenskapen på målet som anges i uppmärkningen. Beroende på bindningsuttrycket kan dessutom den genererade koden observera ändringar i värdet för egenskapen källa och uppdatera egenskapen mål och kan skicka ändringar från mål tillbaka till källa.
Viktig
Kompilerade bindningar är inaktiverade för alla XAML-bindningsuttryck som definierar egenskapen Source
. Det beror på att egenskapen Source
alltid anges med hjälp av x:Reference
markeringstillägget, som inte kan matchas vid kompileringstillfället.
Dessutom stöds inte kompilerade bindningar i XAML för närvarande på flera bindningar.
Som standard producerar .NET MAUI inte byggvarningar för XAML-bindningar som inte använder kompilerade bindningar. Du kan dock välja att aktivera varningar för kompilerade bindningar genom att ange bygg-egenskapen $(MauiStrictXamlCompilation)
till true
i appens projektfil (*.csproj).
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
Som standard skapar .NET MAUI byggvarningar för XAML-bindningar som inte använder kompilerade bindningar.
Mer information om varningar för XAML-kompilerade bindningar finns i XAML-kompilerade bindningsvarningar.
Använda kompilerade bindningar i XAML
I följande exempel visas hur du använder kompilerade bindningar mellan .NET MAUI-vyer och viewmodel-egenskaper:
<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 instansierar HslColorViewModel
och initierar egenskapen Color
i egenskapselementtaggar för egenskapen BindingContext.
ContentPage definierar också attributet x:DataType
som viewmodel-typ, vilket indikerar att alla bindningsuttryck i ContentPage vyhierarkin kommer att kompileras. Detta kan verifieras genom att ändra något av bindningsuttrycken så att de binder till en obefintlig viewmodel-egenskap, vilket resulterar i ett byggfel. Även om det här exemplet anger attributet x:DataType
till en strängliteral kan det också anges till en typ med x:Type
markeringstillägget. Mer information om x:Type
markup-tillägget finns i x:Type Markup Extension.
Viktig
Attributet x:DataType
kan definieras om när som helst i en vyhierarki.
Elementen BoxView, Label och Slider ärver bindningskontexten från ContentPage. Dessa vyer är alla bindningsmål som refererar till källegenskaper i viewmodel. För egenskapen BoxView.Color
och egenskapen Label.Text
är databindningarna OneWay
– egenskaperna i vyn anges från egenskaperna i viewmodel. Egenskapen Slider.Value
använder dock en TwoWay
bindning. Detta gör att varje Slider kan ställas in från vymodellen, och även att vymodellen kan anges från varje Slider.
När exemplet först körs, anges BoxView-, Label- och Slider-elementen från ViewModel baserat på den initiala Color
-egenskapen som angavs när ViewModel instansierades. När skjutreglagen manipuleras uppdateras BoxView- och Label-elementen i enlighet med detta:
Mer information om den här färgväljaren finns i ViewModels och egenskapsändringsmeddelanden.
Använda kompilerade bindningar i XAML i ett DataTemplate
Bindningar i en DataTemplate tolkas i kontexten för objektet som mallas. När du använder kompilerade bindningar i en DataTemplatemåste DataTemplate därför deklarera typen av dataobjekt med hjälp av attributet x:DataType
. Underlåtenhet att göra detta kan resultera i att DataTemplate ärver en felaktig x:DataType
från det överordnade området.
<ContentPage ...
x:DataType="local:AnimalsPageViewModel">
<!-- Binding to AnimalsPageViewModel.Animals -->
<CollectionView ItemsSource="{Binding Animals}">
<CollectionView.ItemTemplate>
<DataTemplate>
<!-- incorrect: compiler thinks you want to bind to AnimalsPageViewModel.Name -->
<Label Text="{Binding Name}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
I följande exempel visas korrekt inställning av x:DataType
på en DataTemplate:
<ContentPage ...
x:DataType="local:AnimalsPageViewModel">
<!-- Binding to AnimalsPageViewModel.Animals -->
<CollectionView ItemsSource="{Binding Animals}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="local:Animal">
<!-- correct: compiler knows you want to bind to Animal.Name -->
<Label Text="{Binding Name}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
Även om det här exemplet anger attributet x:DataType
till en strängliteral kan det också anges till en typ med x:Type
markeringstillägget. Mer information om markeringstillägget x:Type
finns i x:Type Markup Extension.
Kompilera bindningar som definierar egenskapen Source
Före .NET MAUI 9 hoppar XAML-kompilatorn över kompilering av bindningar som definierar egenskapen Source
i stället för BindingContext. Från .NET MAUI 9 kan dessa bindningar kompileras för att dra nytta av bättre körningsprestanda. Den här optimeringen är dock inte aktiverad som standard för att undvika att bryta befintlig appkod. Om du vill aktivera den här optimeringen anger du egenskapen $(MauiEnableXamlCBindingWithSourceCompilation)
build till true
i appens projektfil:
<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>
Kontrollera sedan att alla dina bindningar markerats med rätt x:DataType
och att de inte ärver felaktiga datatyper från det överordnade omfånget.
<HorizontalStackLayout BindingContext="{x:Reference slider}" x:DataType="Slider">
<Label Text="{Binding Value}" />
<Label Text="{Binding Text, Source={x:Reference entry}, x:DataType=Entry}" />
</HorizontalStackLayout>
Not
Om det finns en bindning med en Source
, men den ärver x:DataType
från den överordnade, kan det finnas en mismatch mellan x:DataType
och typen av Source
. I det här scenariot genereras en varning, och en övergång till en reflektionsbaserad bindning som löser upp bindningsvägen vid körning kommer att ske.
Kombinera kompilerade bindningar med klassiska bindningar i XAML
Bindningsuttryck kompileras endast för vyhierarkin som attributet x:DataType
definieras på. Omvänt gäller att alla vyer i en hierarki där attributet x:DataType
inte är definierat kommer att använda klassiska bindningar. Det går därför att kombinera kompilerade bindningar och klassiska bindningar på en sida. I föregående avsnitt använder till exempel vyerna i DataTemplate kompilerade bindningar, medan den BoxView som är inställd på den färg som valts i ListView inte gör det.
Noggrann strukturering av x:DataType
attribut kan därför leda till en sida med kompilerade och klassiska bindningar. Alternativt kan attributet x:DataType
omdefinieras när som helst i en vyhierarki till null
med hjälp av x:Null
-markupstillägget. Detta indikerar att alla bindningsuttryck i vyhierarkin använder klassiska bindningar. I följande exempel visas den här metoden:
<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>
Roten StackLayout anger attributet x:DataType
som den HslColorViewModel
typen, vilket indikerar att alla bindningsuttryck i rot- StackLayout vyhierarkin kommer att kompileras. Det inre StackLayout omdefinierar dock attributet x:DataType
till null
med x:Null
-markeringsuttrycket. Därför använder bindningsuttrycken i den inre StackLayout klassiska bindningar. Endast BoxViewanvänder kompilerade bindningar i rot- StackLayout vyhierarkin.
Mer information om x:Null
-markeringsuttrycket finns i x:Null Markup Extension.
Varningar för XAML-kompilerade bindningar
I följande tabell visas kompilatorvarningarna för kompilerade bindningar och hur du löser dem:
Kod | Meddelande | Reparera |
---|---|---|
XC0022 |
Bindning kan kompileras för att förbättra körtidsprestanda om x:DataType anges. |
Lägg till x:DataType i XAML för att ange vilken typ av aktuell BindingContext. Det är bästa praxis att lägga till x:DataType till alla element där bindningskontexten ändras. |
XC0023 |
Bindningar kan kompileras för att förbättra exekveringsprestanda om x:DataType inte uttryckligen null . |
Ersätt x:DataType="{x:Null}" med rätt typ. |
Kod | Meddelande |
---|---|
XC0022 |
Bindning kan kompileras för att förbättra prestanda om x:DataType anges. Åtgärda den här varningen genom att lägga till x:DataType i din XAML för att specificera typen på den nuvarande BindingContext. Det är bästa praxis att lägga till x:DataType till alla element där bindningskontexten ändras. |
XC0023 |
Bindning kan kompileras för att förbättra exekveringseffektiviteten om x:DataType inte uttryckligen null . Åtgärda varningen genom att ersätta x:DataType="{x:Null}" med rätt typ. |
XC0024 |
Bindningen kan kompileras felaktigt eftersom kommentaren x:DataType kommer från ett yttre område. Se till att du kommenterar alla DataTemplate XAML-element med rätt x:DataType . Åtgärda varningen genom att se till att alla DataTemplate element kommenteras med rätt x:DataType . |
XC0025 |
Bindningen kompilerades inte då den har en explicit inställd Source -egenskap och kompilering av bindningar med Source är inte aktiverad. Överväg att aktivera den här optimeringen genom att ange <MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation> i projektfilen och kontrollera att rätt x:DataType har angetts för den här bindningen. Åtgärda varningen genom att aktivera $(MauiEnableXamlCBindingWithSourceCompilation) build-egenskapen i projektfilen och kommentera alla bindningar med lämplig x:DataType . |
Du kan se till att dessa varningar inte ignoreras genom att ändra specifika varningar för att skapa fel med egenskapen $(WarningsAsErrors)
build:
<WarningsAsErrors>$(WarningsAsErrors);XC0022;XC0023</WarningsAsErrors>
Om du vill ignorera dessa varningar använder du egenskapen $(NoWarn)
build med specifika varningskoder:
<NoWarn>$(NoWarn);XC0022;XC0023</NoWarn>
Viktig
XC0022
- och XC0023
-varningar kommer alltid att ignoreras om inte $(MauiStrictXamlCompilation)
build-egenskapen är inställd på true
.
Om du anger $(TreatWarningsAsErrors)
build-egenskapen till true
i appens projektfil, men vill ignorera vissa XAML-kompilatorvarningar, använder du antingen egenskapen $(NoWarn)
build för att tysta dessa varningar eller $(WarningsNotAsErrors)
build-egenskapen för att minska allvarlighetsgraden för vissa specifika koder.
Som standard skapar .NET MAUI byggvarningar för XAML-bindningar som inte använder kompilerade bindningar. Du kan välja att kompilerade bindningsvarningar behandlas som fel genom att ställa in build-egenskaperna $(MauiStrictXamlCompilation)
och $(TreatWarningsAsErrors)
till true
i appens projektfil (*.csproj):
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
Not
Som standard är $(MauiStrictXamlCompilation)
build-egenskapen false
om du inte publicerar din app med fullständig trimning eller NativeAOT.
Kompilerade bindningar i kod
Bindningar som skrivs i kod använder vanligtvis strängvägar som löses vid körningstid med hjälp av reflection. Men SetBinding-tilläggsmetoden har också en överlagring som definierar bindningar med hjälp av ett Func
argument i stället för en strängsökväg:
MyLabel.SetBinding(Label.TextProperty, static (Entry entry) => entry.Text);
Alla metoder kan inte användas för att definiera en kompilerad bindning. Uttrycket måste vara ett enkelt egenskapsåtkomstuttryck. I följande exempel visas giltiga och ogiltiga bindningsuttryck:
// Valid: Property access
static (PersonViewModel vm) => vm.Name;
static (PersonViewModel vm) => vm.Address?.Street;
// Valid: Array and indexer access
static (PersonViewModel vm) => vm.PhoneNumbers[0];
static (PersonViewModel vm) => vm.Config["Font"];
// Valid: Casts
static (Label label) => (label.BindingContext as PersonViewModel).Name;
static (Label label) => ((PersonViewModel)label.BindingContext).Name;
// Invalid: Method calls
static (PersonViewModel vm) => vm.GetAddress();
static (PersonViewModel vm) => vm.Address?.ToString();
// Invalid: Complex expressions
static (PersonViewModel vm) => vm.Address?.Street + " " + vm.Address?.City;
static (PersonViewModel vm) => $"Name: {vm.Name}";
Varning
Ett CS0272-kompilatorfel inträffar om den angivna åtkomsten för en egenskap eller indexerare inte är tillgänglig. Om detta inträffar, öka accessorns åtkomstbarhet.
Dessutom anger BindingBase.Create-metoden bindningen direkt på objektet med en Func
och returnerar bindningsobjektinstansen:
myEntry.SetBinding(Entry.TextProperty, new MultiBinding
{
Bindings = new Collection<BindingBase>
{
Binding.Create(static (Entry entry) => entry.FontFamily, source: RelativeBindingSource.Self),
Binding.Create(static (Entry entry) => entry.FontSize, source: RelativeBindingSource.Self),
Binding.Create(static (Entry entry) => entry.FontAttributes, source: RelativeBindingSource.Self),
},
Converter = new StringConcatenationConverter()
});
Dessa kompilerade bindningsmetoder ger följande fördelar:
- Förbättrade databindningsprestanda genom att lösa bindningsuttryck vid kompilering i stället för vid körning.
- En bättre felsökningsupplevelse för utvecklare eftersom ogiltiga bindningar rapporteras som byggfel.
- Intellisense vid redigering.
Prestanda
Kompilerade bindningar förbättrar databindningsprestanda och prestandafördelarna varierar:
- En kompilerad bindning som använder egenskapsändringsmeddelande (dvs. en
OneWay
,OneWayToSource
ellerTwoWay
bindning) löses ungefär 8 gånger snabbare än en klassisk bindning. - En kompilerad bindning som inte använder egenskapsändringsmeddelande (dvs. en
OneTime
bindning) löses ungefär 20 gånger snabbare än en klassisk bindning. - Det går ungefär 5 gånger snabbare att ange BindingContext för en kompilerad bindning som använder egenskapsändringsmeddelanden (t.ex. en
OneWay
,OneWayToSource
ellerTwoWay
bindning) än att ange BindingContext på en klassisk bindning. - Att ange BindingContext på en kompilerad bindning som inte använder egenskapsändringsmeddelande (dvs. en
OneTime
bindning) är ungefär 7 gånger snabbare än att ange BindingContext på en klassisk bindning.
Dessa prestandaskillnader kan förstoras på mobila enheter, beroende på vilken plattform som används, vilken version av operativsystemet som används och den enhet som programmet körs på.