Udostępnij za pośrednictwem


Skompilowane powiązania

Przeglądaj przykład. Przeglądanie przykładu

Powiązania danych interfejsu użytkownika aplikacji wieloplatformowej platformy .NET (.NET MAUI) mają dwa główne problemy:

  1. 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.
  2. 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:

Skompilowany selektor kolorów.

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:

Skompilowana lista kolorów.

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 Sourceobiektu . 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:DataTypeelementem .

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:DataTypeelementu .

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ą Funcobiektu 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. OneWayOneWayToSource, lub TwoWay 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. OneWayOneWayToSource, lub TwoWay 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.