Skompilowane powiązania
Powiązania danych interfejsu użytkownika aplikacji wieloplatformowej platformy .NET (.NET MAUI) mają dwa główne problemy:
- Nie ma walidacji wyrażeń powiązań w czasie kompilacji. Zamiast tego powiązania są rozwiązywane w czasie wykonywania. W związku z tym wszelkie nieprawidłowe powiązania nie są wykrywane, dopóki środowisko uruchomieniowe nie będzie działać zgodnie z oczekiwaniami lub pojawią się komunikaty o błędach.
- Nie są one opłacalne. Powiązania są rozwiązywane w czasie wykonywania przy użyciu inspekcji obiektów ogólnego przeznaczenia (odbicia), a obciążenie związane z wykonywaniem tej czynności różni się od platformy do platformy.
Skompilowane powiązania zwiększają wydajność powiązań danych w aplikacjach .NET MAUI przez rozpoznawanie wyrażeń powiązań w czasie kompilacji, a nie w czasie wykonywania. Ponadto ta walidacja czasu kompilacji wyrażeń powiązania umożliwia lepsze środowisko rozwiązywania problemów dla deweloperów, ponieważ nieprawidłowe powiązania są zgłaszane jako błędy kompilacji.
Ważne
Skompilowane powiązania są wymagane zamiast powiązań opartych na ciągach w aplikacjach NativeAOT i w aplikacjach z włączonym pełnym przycinaniem. Aby uzyskać więcej informacji, zobacz Trim a .NET MAUI app and Native AOT deployment (Przycinanie aplikacji MAUI platformy .NET) i Native AOT deployment (Wdrażanie natywnego rozwiązania AOT).
Skompilowane powiązania w języku XAML
Aby użyć skompilowanych powiązań w języku XAML, ustaw x:DataType
atrybut na typ VisualElement obiektu, z którego VisualElement będą powiązane obiekty i jego elementy podrzędne. Zaleca się ustawienie atrybutu x:DataType
na tym samym poziomie w hierarchii widoków BindingContext , co jest ustawione. Ten atrybut można jednak ponownie zdefiniować w dowolnej lokalizacji w hierarchii widoków.
Ważne
Skompilowane powiązania wymagają użycia kompilacji XAML, która jest domyślnie włączona w programie .NET MAUI. Jeśli wyłączono kompilację XAML, musisz ją włączyć. Aby uzyskać więcej informacji, zobacz Kompilacja XAML.
Aby używać skompilowanych powiązań w języku XAML, x:DataType
atrybut musi być ustawiony na literał ciągu lub typ przy użyciu x:Type
rozszerzenia znaczników. W czasie kompilacji XAML wszelkie nieprawidłowe wyrażenia powiązania będą zgłaszane jako błędy kompilacji. Jednak kompilator XAML zgłosi tylko błąd kompilacji dla pierwszego nieprawidłowego wyrażenia powiązania, które napotka. Wszystkie prawidłowe wyrażenia powiązania zdefiniowane na VisualElement obiekcie lub jego elementach podrzędnych zostaną skompilowane, niezależnie od tego, czy BindingContext element jest ustawiony w języku XAML, czy kodzie. Kompilowanie wyrażenia powiązania generuje skompilowany kod, który pobierze wartość z właściwości w źródle i ustawi go we właściwości na obiekcie docelowym określonym w znaczniku. Ponadto w zależności od wyrażenia powiązania wygenerowany kod może obserwować zmiany w wartości właściwości źródłowej i odświeżyć właściwość docelową i może wypchnąć zmiany z obiektu docelowego z powrotem do źródła.
Ważne
Skompilowane powiązania są wyłączone dla wszystkich wyrażeń powiązań XAML, które definiują Source
właściwość. Jest to spowodowane tym, że Source
właściwość jest zawsze ustawiana przy użyciu x:Reference
rozszerzenia znaczników, którego nie można rozpoznać w czasie kompilacji.
Ponadto skompilowane powiązania w języku XAML są obecnie nieobsługiwane w wielu powiązaniach.
Domyślnie program .NET MAUI nie generuje ostrzeżeń kompilacji dla powiązań XAML, które nie używają skompilowanych powiązań. Można jednak zdecydować się na ostrzeżenia kompilowanych powiązań generowanych przez ustawienie $(MauiStrictXamlCompilation)
właściwości kompilacji na true
w pliku projektu aplikacji (*.csproj):
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
Domyślnie program .NET MAUI tworzy ostrzeżenia kompilacji dla powiązań XAML, które nie używają skompilowanych powiązań.
Aby uzyskać więcej informacji na temat ostrzeżeń dotyczących powiązań skompilowanych XAML, zobacz ostrzeżenia dotyczące skompilowanych powiązań XAML.
Używanie skompilowanych powiązań w języku XAML
W poniższym przykładzie pokazano użycie skompilowanych powiązań między widokami MAUI platformy .NET i właściwościami modelu 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>
Tworzy ContentPage wystąpienie HslColorViewModel
właściwości i inicjuje Color
właściwość w tagach elementu właściwości dla BindingContext właściwości. Atrybut ContentPage definiuje x:DataType
również jako typ modelu viewmodel, co oznacza, że wszystkie wyrażenia powiązania w ContentPage hierarchii widoków zostaną skompilowane. Można to zweryfikować, zmieniając dowolne wyrażenia powiązania, aby powiązać z nieistnieną właściwością viewmodel, co spowoduje błąd kompilacji. Chociaż w tym przykładzie x:DataType
atrybut jest ustawiany na literał ciągu, można go również ustawić na typ z x:Type
rozszerzeniem znaczników. Aby uzyskać więcej informacji na temat x:Type
rozszerzenia znaczników, zobacz x:Type Markup Extension (Rozszerzenie znaczników x:Type).
Ważne
Atrybut x:DataType
można ponownie zdefiniować w dowolnym momencie w hierarchii widoków.
BoxViewLabel Elementy i Slider widoki dziedziczą kontekst powiązania z elementu ContentPage. Te widoki to wszystkie obiekty docelowe powiązania odwołujące się do właściwości źródła w modelu widoku. BoxView.Color
W przypadku właściwości i Label.Text
właściwości powiązania danych to OneWay
— właściwości w widoku są ustawione na podstawie właściwości w modelu widoków. Slider.Value
Jednak właściwość używa TwoWay
powiązania. Umożliwia to ustawienie każdego Slider z modelu widoków, a także ustawienie modelu widoku z każdego Sliderelementu .
Po pierwszym uruchomieniu przykładu BoxViewLabel wszystkie elementy , i Slider elementy są ustawiane z modelu viewmodel na podstawie początkowej Color
właściwości ustawionej podczas tworzenia wystąpienia modelu viewmodel. Gdy suwaki są manipulowane, BoxView elementy i Label są odpowiednio aktualizowane:
Aby uzyskać więcej informacji na temat tego selektora kolorów, zobacz ViewModels i powiadomienia dotyczące zmiany właściwości.
Używanie skompilowanych powiązań w języku XAML w narzędziu DataTemplate
Powiązania w obiekcie DataTemplate są interpretowane w kontekście obiektu, który jest szablonowany. W związku z tym w przypadku używania skompilowanych powiązań w obiekcie DataTemplateDataTemplate należy zadeklarować typ obiektu danych przy użyciu atrybutu x:DataType
. Wykonanie tej czynności może spowodować DataTemplate dziedziczenie nieprawidłowego x:DataType
zakresu nadrzędnego:
<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>
W poniższym przykładzie pokazano prawidłowe ustawienie x:DataType
elementu w obiekcie 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>
Właściwość ListView.ItemsSource
jest ustawiona na właściwość statyczną NamedColor.All
. Klasa NamedColor
używa odbicia platformy .NET do wyliczania wszystkich statycznych pól publicznych w Colors klasie i przechowywania ich z nazwami w kolekcji dostępnej z właściwości statycznej All
. W związku z tym element ListView jest wypełniony wszystkimi NamedColor
wystąpieniami. Dla każdego elementu w elemencie ListViewkontekst powiązania dla elementu jest ustawiony na NamedColor
obiekt. BoxView Elementy i Label w obiekcie ViewCell są powiązane z NamedColor
właściwościami.
x:DataType
Definiuje DataTemplate atrybut, który ma być typemNamedColor
, wskazując, że wszystkie wyrażenia powiązania w DataTemplate hierarchii widoków zostaną skompilowane. Można to zweryfikować, zmieniając dowolne wyrażenia powiązania, aby powiązać z nieistnieną NamedColor
właściwością, co spowoduje błąd kompilacji. Chociaż w tym przykładzie x:DataType
atrybut jest ustawiany na literał ciągu, można go również ustawić na typ z x:Type
rozszerzeniem znaczników. Aby uzyskać więcej informacji na temat x:Type
rozszerzenia znaczników, zobacz x:Type Markup Extension (Rozszerzenie znaczników x:Type).
Po pierwszym uruchomieniu ListView przykładu element jest wypełniany wystąpieniami NamedColor
. Po wybraniu BoxView.Color
elementu w elemencie ListView właściwość jest ustawiana na kolor wybranego elementu w elemencie ListView:
Wybranie innych elementów w pliku ListView aktualizuje kolor elementu BoxView.
Kompilowanie powiązań definiujących Source
właściwość
Przed programem .NET MAUI 9 kompilator XAML pominą kompilację powiązań, które definiują Source
właściwość zamiast BindingContext. W programie .NET MAUI 9 te powiązania można skompilować, aby korzystać z lepszej wydajności środowiska uruchomieniowego. Jednak ta optymalizacja nie jest domyślnie włączona, aby uniknąć przerywania istniejącego kodu aplikacji. Aby włączyć tę optymalizację $(MauiEnableXamlCBindingWithSourceCompilation)
, ustaw właściwość kompilacji na true
w pliku projektu aplikacji:
<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>
Następnie upewnij się, że wszystkie powiązania są oznaczone adnotacjami poprawnymi x:DataType
i że nie dziedziczą niepoprawnych typów danych z zakresu nadrzędnego:
<HorizontalStackLayout BindingContext="{x:Reference slider}" x:DataType="Slider">
<Label Text="{Binding Value}" />
<Label Text="{Binding Text, Source={x:Reference entry}, x:DataType=Entry}" />
</HorizontalStackLayout>
Uwaga
W przypadkach, gdy istnieje powiązanie z elementem Source
, ale dziedziczy x:DataType
z elementu nadrzędnego, może istnieć niezgodność między x:DataType
elementem i typem Source
obiektu . W tym scenariuszu zostanie wygenerowane ostrzeżenie i nastąpi powrót do powiązania opartego na odbiciu, które rozwiąże ścieżkę powiązania w czasie wykonywania.
Łączenie skompilowanych powiązań z powiązaniami klasycznymi w języku XAML
Wyrażenia powiązań są kompilowane tylko dla hierarchii widoków, na których x:DataType
zdefiniowano atrybut. Z drugiej strony wszystkie widoki w hierarchii, w której x:DataType
atrybut nie jest zdefiniowany, będą używać powiązań klasycznych. W związku z tym można połączyć skompilowane powiązania i powiązania klasyczne na stronie. Na przykład w poprzedniej sekcji widoki w ramach DataTemplate używanych skompilowanych powiązań, a BoxView kolor wybrany w elememencie ListView nie jest ustawiony.
Staranne struktury atrybutów x:DataType
mogą zatem prowadzić do strony przy użyciu skompilowanych i klasycznych powiązań. Alternatywnie x:DataType
atrybut można ponownie zdefiniować w dowolnym momencie w hierarchii widoków do null
używania x:Null
rozszerzenia znaczników. Oznacza to, że wszystkie wyrażenia powiązań w hierarchii widoków będą używać powiązań klasycznych. W poniższym przykładzie pokazano to podejście:
<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>
Katalog główny StackLayout ustawia atrybut HslColorViewModel
jako x:DataType
typ, wskazując, że każde wyrażenie powiązania w hierarchii widoku głównego StackLayout zostanie skompilowane. Jednak wewnętrzna StackLayout definicja atrybutu x:DataType
null
za pomocą x:Null
wyrażenia znaczników. W związku z tym wyrażenia powiązania wewnętrzne StackLayout używają powiązań klasycznych. Tylko element BoxVieww hierarchii widoku głównego StackLayout używa skompilowanych powiązań.
Aby uzyskać więcej informacji o wyrażeniu x:Null
znaczników, zobacz x:Null Markup Extension (Rozszerzenie znaczników o wartości null).
Ostrzeżenia dotyczące powiązań skompilowanych w języku XAML
W poniższej tabeli wymieniono ostrzeżenia kompilatora dotyczące skompilowanych powiązań oraz sposób ich rozwiązywania:
Kod | Komunikat | Napraw |
---|---|---|
XC0022 |
Powiązanie można skompilować w celu zwiększenia wydajności środowiska uruchomieniowego, jeśli x:DataType zostanie określony. |
Dodaj x:DataType element do kodu XAML, aby określić typ bieżącego BindingContextelementu . Najlepszym rozwiązaniem jest dodanie x:DataType do wszystkich elementów, w których zmienia się kontekst powiązania. |
XC0023 |
Powiązanie można skompilować, aby zwiększyć wydajność środowiska uruchomieniowego, jeśli x:DataType nie jest jawnie null . |
Zastąp x:DataType="{x:Null}" ciąg właściwym typem. |
Kod | Komunikat |
---|---|
XC0022 |
Powiązanie można skompilować w celu zwiększenia wydajności środowiska uruchomieniowego, jeśli x:DataType zostanie określony. Aby naprawić to ostrzeżenie, dodaj x:DataType element do kodu XAML, aby określić typ bieżącego BindingContextelementu . Najlepszym rozwiązaniem jest dodanie x:DataType do wszystkich elementów, w których zmienia się kontekst powiązania. |
XC0023 |
Powiązanie można skompilować, aby zwiększyć wydajność środowiska uruchomieniowego, jeśli x:DataType nie jest jawnie null . Aby naprawić to ostrzeżenie, zastąp x:DataType="{x:Null}" ciąg odpowiednim typem. |
XC0024 |
Powiązanie może być kompilowane niepoprawnie, ponieważ adnotacja x:DataType pochodzi z zakresu zewnętrznego. Pamiętaj, aby dodać adnotację do wszystkich DataTemplate elementów XAML z poprawnym x:DataType elementem . Aby naprawić to ostrzeżenie, upewnij się, że wszystkie DataTemplate elementy są oznaczone adnotacjami z poprawnym x:DataType . |
XC0025 |
Powiązanie nie zostało skompilowane, ponieważ ma jawnie ustawioną Source właściwość i kompilację powiązań z Source nie jest włączona. Rozważ włączenie tej optymalizacji, ustawiając <MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation> element w pliku projektu i upewnij się, że dla tego powiązania określono poprawność x:DataType . Aby naprawić to ostrzeżenie, włącz $(MauiEnableXamlCBindingWithSourceCompilation) właściwość kompilacji w pliku projektu i dodaj adnotację do wszystkich powiązań przy użyciu odpowiedniego x:DataType elementu . |
Aby upewnić się, że te ostrzeżenia nie są ignorowane, rozważ zmianę określonych ostrzeżeń na błędy kompilacji z właściwością $(WarningsAsErrors)
kompilacji:
<WarningsAsErrors>$(WarningsAsErrors);XC0022;XC0023</WarningsAsErrors>
Aby zignorować te ostrzeżenia, użyj $(NoWarn)
właściwości kompilacji z określonymi kodami ostrzegawczymi:
<NoWarn>$(NoWarn);XC0022;XC0023</NoWarn>
Ważne
XC0022
i XC0023
ostrzeżenia będą zawsze pomijane, chyba że $(MauiStrictXamlCompilation)
właściwość kompilacji jest ustawiona na true
.
Jeśli właściwość kompilacji zostanie ustawiona $(TreatWarningsAsErrors)
na true
w pliku projektu aplikacji, ale chcesz zignorować niektóre ostrzeżenia kompilatora XAML, użyj $(NoWarn)
właściwości build, aby wyciszyć te ostrzeżenia lub $(WarningsNotAsErrors)
właściwość kompilacji, aby zmniejszyć ważność niektórych określonych kodów.
Domyślnie program .NET MAUI tworzy ostrzeżenia kompilacji dla powiązań XAML, które nie używają skompilowanych powiązań. Możesz zdecydować się na ostrzeżenia kompilowane powiązania traktowane jako błędy, ustawiając $(MauiStrictXamlCompilation)
właściwości i $(TreatWarningsAsErrors)
kompilacji na true
w pliku projektu aplikacji (*.csproj):
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
Uwaga
Domyślnie właściwość kompilacji $(MauiStrictXamlCompilation)
to false
chyba, że publikujesz aplikację przy użyciu pełnego przycinania lub NativeAOT.
Skompilowane powiązania w kodzie
Powiązania napisane w kodzie zwykle używają ścieżek ciągów rozpoznawanych w czasie wykonywania z odbiciem. SetBinding Jednak metoda rozszerzenia ma również przeciążenie, które definiuje powiązania przy użyciu argumentu Func
zamiast ścieżki ciągu:
MyLabel.SetBinding(Label.TextProperty, static (Entry entry) => entry.Text);
Nie wszystkie metody mogą służyć do definiowania skompilowanego powiązania. Wyrażenie musi być prostym wyrażeniem dostępu do właściwości. W poniższych przykładach pokazano prawidłowe i nieprawidłowe wyrażenia powiązania:
// 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}";
Ponadto BindingBase.Create metoda ustawia powiązanie bezpośrednio na obiekcie za pomocą Func
obiektu i zwraca wystąpienie obiektu powiązania:
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()
});
Te skompilowane podejścia do powiązań zapewniają następujące korzyści:
- Zwiększona wydajność powiązania danych przez rozpoznawanie wyrażeń powiązań w czasie kompilacji, a nie w czasie wykonywania.
- Lepsze środowisko rozwiązywania problemów dla deweloperów, ponieważ nieprawidłowe powiązania są zgłaszane jako błędy kompilacji.
- Funkcja IntelliSense podczas edytowania.
Wydajność
Skompilowane powiązania zwiększają wydajność powiązań danych, a korzyść z wydajności różni się:
- Skompilowane powiązanie korzystające z powiadomienia o zmianie właściwości (tj.
OneWay
OneWayToSource
, lubTwoWay
powiązania) jest rozpoznawane mniej więcej 8 razy szybciej niż powiązanie klasyczne. - Skompilowane powiązanie, które nie używa powiadomienia o zmianie właściwości (tj.
OneTime
powiązanie) jest rozpoznawane mniej więcej 20 razy szybciej niż powiązanie klasyczne. - BindingContext Ustawienie elementu na skompilowanym powiązaniu używającym powiadomienia o zmianie właściwości (tj.
OneWay
OneWayToSource
, lubTwoWay
powiązania) jest o około 5 razy szybsze niż ustawienie BindingContext dla powiązania klasycznego. - BindingContext Ustawienie elementu na skompilowanym powiązaniu, które nie używa powiadomienia o zmianie właściwości (tj.
OneTime
powiązanie) jest mniej więcej 7 razy szybsze niż ustawienie BindingContext elementu w powiązaniu klasycznym.
Te różnice wydajności można powiększyć na urządzeniach przenośnych, zależnie od używanej platformy, wersji używanego systemu operacyjnego i urządzenia, na którym działa aplikacja.