Freigeben über


Kompilierte Bindungen

Beispiel durchsuchen. Durchsuchen Sie das Beispiel

Datenbindungen für .NET Multi-Platform App UI (.NET MAUI) weisen zwei Standard Probleme auf:

  1. Es gibt keine Validierung von Bindungsausdrücken zur Kompilierzeit. Stattdessen werden Bindungen zur Laufzeit aufgelöst. Daher werden ungültige Bindungen erst zur Laufzeit ermittelt, wenn die Anwendung nicht erwartungsgemäß funktioniert oder Fehlermeldungen angezeigt werden.
  2. Sie sind nicht kosteneffizient. Bindungen werden zur Laufzeit mithilfe Universeller Objektüberprüfung (Reflektion) aufgelöst. Der durch diese Methode entstehende Mehraufwand variiert von Plattform zu Plattform.

Kompilierte Bindungen verbessern die Datenbindungsleistung in .NET MAUI-Anwendungen, indem die Bindungsausdrücke zur Kompilierzeit anstatt zur Laufzeit aufgelöst werden. Darüber hinaus vereinfacht die Validierung von Bindungsausdrücken zur Kompilierzeit die Problembehandlung durch den Entwickler, da ungültige Bindungen als Buildfehler gemeldet werden.

Wichtig

Kompilierte Bindungen sind anstelle von Zeichenfolgenbasierten Bindungen in NativeAOT-Apps und in Apps mit aktivierter vollständiger Kürzung erforderlich. Weitere Informationen finden Sie unter Trim a .NET MAUI app and Native AOT deployment.

Kompilierte Bindungen in XAML

Um kompilierte XAML-Bindungen zu verwenden, setzen Sie ein x:DataType-Attribut auf einem VisualElement auf den Typ des Objekts, an das das VisualElement und untergeordnete Elemente gebunden werden sollen. Es wird empfohlen, das x:DataType-Attribut auf der gleichen Ebene in der Ansichtshierarchie festzulegen, auf der die BindingContext-Eigenschaft festgelegt ist. Dieses Attribut kann jedoch an jeder Position in einer Ansichtshierarchie neu definiert werden.

Wichtig

Kompilierte Bindungen erfordern die Verwendung der XAML-Kompilierung, die standardmäßig in .NET MAUI aktiviert ist. Wenn Sie die XAML-Kompilierung deaktiviert haben, müssen Sie sie aktivieren. Weitere Informationen finden Sie unter XAML Compilation (XAML-Kompilierung).

Um kompilierte Bindungen in XAML zu verwenden, muss das x:DataType-Attribut auf eine Zeichenfolge oder einen Typ mit der x:Type-Markuperweiterung festgelegt werden. Zur Kompilierzeit des XAML-Codes werden jegliche ungültige Bindungsausdrücke als Buildfehler gemeldet. Der XAML-Compiler meldet einen Buildfehler jedoch nur für den ungültigen Bindungsausdruck, der als erstes ermittelt wird. Alle gültigen Bindungsausdrücke, die im VisualElement-Element oder in dessen untergeordneten Elemente definiert sind, werden unabhängig davon, ob BindingContext in der XAML-Datei oder im Code festgelegt ist, kompiliert. Das Kompilieren eines Bindungsausdrucks generiert kompilierten Code, der einen Wert von einer Eigenschaft in der Quelle abruft und diesen für die Eigenschaft des Ziels festlegt, das im Markup angegeben ist. Je nach Bindungsausdruck wird außerdem der Wert der Eigenschaft source geändert und die Eigenschaft target aktualisiert. Möglicherweise werden Änderungen vom Ziel zurück an die Quelle übertragen.

Wichtig

Kompilierte Bindungen sind derzeit für alle XAML-Bindungsausdrücke deaktiviert, welche die Source Eigenschaft definieren. Der Grund dafür ist, dass die Source-Eigenschaft immer mit der Markuperweiterung x:Reference festgelegt wird, die zur Kompilierzeit nicht aufgelöst werden kann.

Darüber hinaus werden kompilierte XAML-Bindungen für Multibindungen derzeit nicht unterstützt.

Standardmäßig erzeugt .NET MAUI keine Buildwarnungen für XAML-Bindungen, die keine kompilierten Bindungen verwenden. Sie können jedoch festlegen, dass Warnungen zu kompilierten Bindungen ausgegeben werden, indem Sie die $(MauiStrictXamlCompilation)-Buildeigenschaft in der Projektdatei Ihrer App (*.csproj) auf true festlegen:

<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>

Standardmäßig erzeugt .NET MAUI Buildwarnungen für XAML-Bindungen, die keine kompilierten Bindungen verwenden.

Weitere Informationen zu Warnungen zu kompilierten XAML-Bindungen finden Sie unter Warnungen zu kompilierten XAML-Bindungen.

Verwenden kompilierter Bindungen in XAML

Das folgende Beispiel veranschaulicht die Verwendung kompilierter Bindungen zwischen .NET MAUI-Ansichten und Viewmodel-Eigenschaften:

<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>

Die ContentPage instanziiert die HslColorViewModel und initialisiert die Color Eigenschaft innerhalb von Eigenschaftselement-Tags für die BindingContext Eigenschaft. Dieser ContentPage Stamm definiert außerdem das x:DataType Attribut als ViewModel-Typ, der angibt, dass alle Bindungsausdrücke in der ContentPage Ansichtshierarchie kompiliert werden. Dies können Sie überprüfen, indem Sie einen der Bindungsausdrücke so ändern, dass er an eine nicht vorhandene ViewModel-Eigenschaft gebunden wird. Dies führt zu einem Buildfehler. In diesem Beispiel wird das x:DataType-Attribut auf ein Zeichenfolgenliteral festgelegt. Sie können es jedoch auch auf einen Typ mit der Markuperweiterung x:Type festlegen. Weitere Informationen zur Markuperweiterung x:Type finden Sie unter x:Type-Markuperweiterung.

Wichtig

Das x:DataType-Attribut kann jederzeit in einer Ansichtshierarchie neu definiert werden.

Die BoxView- und Label-Elemente sowie die Slider-Ansichten erben den Bindungskontext von ContentPage. Alle diese Ansichten sind Bindungsziele, die auf Quelleneigenschaften des ViewModels verweisen. Für die Eigenschaften BoxView.Color und Label.Text sind die Datenbindungen OneWay. Die Eigenschaften in der Ansicht werden über die Eigenschaften in der ViewModel-Klasse festgelegt. Die Eigenschaft Slider.Value verwendet jedoch eine TwoWay-Bindung. Dadurch kann jedes Slider-Element über ViewModel und die ViewModel-Klasse über jedes Slider-Element festgelegt werden.

Bei der ersten Ausführung der Anwendung werden alle BoxView, Label und SliderElemente über die ViewModel-Klasse basierend auf der ursprünglichen Color Eigenschaft festgelegt, die bei der Instanziierung von ViewModel festgelegt wurde. Wenn die Schieberegler bewegt werden, werden die Elemente BoxView und Label entsprechend aktualisiert.

Kompilierte Farbauswahl.

Weitere Informationen zu dieser Farbauswahl finden Sie unter Benachrichtigungen für Änderungen an ViewModels und Eigenschaften.

Verwenden von kompilierten XAML-Bindungen in einer DataTemplate

Bindungen in einer DataTemplate-Klasse werden abhängig vom Kontext des Objekts interpretiert, auf dem die Vorlage basiert. Daher muss die DataTemplate-Klasse den Typ ihres Datenobjekts mithilfe des DataTemplate-Attributs deklarieren, wenn kompilierte Bindungen in einer x:DataType-Klasse verwendet werden. Wenn dies nicht der Fall ist, kann dies dazu führen, dass ein DataTemplate falscher x:DataType Teil des übergeordneten Bereichs geerbt wird:

<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>

Das folgende Beispiel veranschaulicht das ordnungsgemäße Festlegen der Einstellung x:DataType für ein 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>

In diesem Beispiel wird das x:DataType-Attribut auf ein Zeichenfolgenliteral festgelegt. Sie können es jedoch auch auf einen Typ mit der Markuperweiterung x:Type festlegen. Weitere Informationen zur Markuperweiterung x:Type finden Sie unter x:Type-Markuperweiterung.

Kompilieren von Bindungen, die die Source Eigenschaft definieren

Vor .NET MAUI 9 würde der XAML-Compiler die Kompilierung von Bindungen überspringen, die die Source Eigenschaft anstelle der BindingContext. Von .NET MAUI 9 können diese Bindungen kompiliert werden, um eine bessere Laufzeitleistung zu erzielen. Diese Optimierung ist jedoch nicht standardmäßig aktiviert, um das Unterbrechen vorhandener App-Code zu vermeiden. Um diese Optimierung zu aktivieren, legen Sie die Buildeigenschaft in der $(MauiEnableXamlCBindingWithSourceCompilation) Projektdatei Ihrer App fest true :

<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>

Stellen Sie dann sicher, dass alle Ihre Bindungen mit dem richtigen x:DataType Versehen versehen sind und dass sie keine falschen Datentypen vom übergeordneten Bereich erben:

<HorizontalStackLayout BindingContext="{x:Reference slider}" x:DataType="Slider">
    <Label Text="{Binding Value}" />
    <Label Text="{Binding Text, Source={x:Reference entry}, x:DataType=Entry}" />
</HorizontalStackLayout>

Hinweis

In Fällen, in denen eine Bindung mit einer Source, aber sie erbt vom übergeordneten x:DataType Element, kann ein Konflikt zwischen dem x:DataType und dem Typ der .Source In diesem Szenario wird eine Warnung generiert und ein Fallback auf eine spiegelungsbasierte Bindung, die den Bindungspfad zur Laufzeit aufgelöst.

Kombinieren von kompilierten und klassischen XAML-Bindungen

Bindungsausdrücke werden nur für die Ansichtshierarchie kompiliert, für die das Attribut x:DataType definiert ist. Im Gegensatz dazu, verwenden alle Ansichten in einer Hierarchie, für die das Attribut x:DataType nicht definiert ist, klassische Bindungen. Daher ist es möglich, kompilierte Bindungen und klassische Bindungen auf einer Seite zu kombinieren. Zum Beispiel verwenden die Ansichten in der DataTemplate-Klasse im vorherigen Abschnitt kompilierte Bindungen, während die BoxView-Klasse, die auf die in ListView ausgewählte Farbe festgelegt ist, klassische Bindungen verwendet.

Mithilfe sorgfältiger Strukturierung von x:DataType-Attributen kann deshalb eine Seite mit kompilierten und klassischen Bindungen erstellt werden. Alternativ kann das Attribut x:DataType jederzeit und an beliebiger Position in einer Ansichtshierarchie mithilfe der Markuperweiterung null als x:Null definiert werden. Dadurch wird impliziert, dass alle Bindungsausdrücke in der Ansichtshierarchie klassische Bindungen nutzen. Das folgende Beispiel veranschaulicht diesen Ansatz:

<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>   

Der StackLayout-Stamm legt den Typ x:DataType für das Attribut HslColorViewModel fest, d.h., dass alle Bindungsausdrücke im StackLayout-Stamm der Ansichtshierarchie kompiliert werden. Das Attribut StackLayout wird jedoch von der inneren x:DataType-Klasse mithilfe des Markupausdrucks null mit dem Wert x:Null neu definiert. Daher verwenden Bindungsausdrücke in der inneren StackLayout-Klasse klassische Bindungen. Nur die BoxView-Klasse im StackLayout-Stamm der Ansichtshierarchie verwendet kompilierte Bindungen.

Weitere Informationen über den Markupausdruck x:Null finden Sie unter x:Null Markup Extension (x:Null-Markuperweiterung).

Warnungen zu kompilierten XAML-Bindungen

In der folgenden Tabelle sind die Compilerwarnungen für kompilierte Bindungen und deren Behebung aufgeführt:

Code `Message` Fix
XC0022 Die Bindung kann kompiliert werden, um die Laufzeitleistung zu verbessern, falls x:DataType angegeben. Fügen Sie x:DataType Ihrem XAML-Code hinzu, um den Typ des aktuellen BindingContextAnzugeben. Es empfiehlt sich, allen Elementen hinzuzufügen x:DataType , in denen sich der Bindungskontext ändert.
XC0023 Die Bindung kann kompiliert werden, um die Laufzeitleistung zu verbessern, wenn x:DataType sie nicht explizit nullist. Ersetzen sie x:DataType="{x:Null}" durch den richtigen Typ.
Code `Message`
XC0022 Die Bindung kann kompiliert werden, um die Laufzeitleistung zu verbessern, falls x:DataType angegeben.

Um diese Warnung zu beheben, fügen Sie x:DataType Ihrem XAML-Code hinzu, um den Typ des aktuellen BindingContextanzugeben. Es empfiehlt sich, allen Elementen hinzuzufügen x:DataType , in denen sich der Bindungskontext ändert.
XC0023 Die Bindung kann kompiliert werden, um die Laufzeitleistung zu verbessern, wenn x:DataType sie nicht explizit nullist.

Ersetzen Sie zum Beheben dieser Warnung x:DataType="{x:Null}" den richtigen Typ.
XC0024 Die Bindung kann falsch kompiliert werden, da die x:DataType Anmerkung aus einem äußeren Bereich stammt. Stellen Sie sicher, dass Sie alle DataTemplate XAML-Elemente mit dem richtigen x:DataTypeVersehen versehen.

Um diese Warnung zu beheben, stellen Sie sicher, dass alle DataTemplate Elemente mit dem richtigen x:DataTypeKommentar versehen werden.
XC0025 Die Bindung wurde nicht kompiliert, da sie über eine explizit festgelegte Source Eigenschaft verfügt und die Kompilierung von Bindungen nicht Source aktiviert ist. Erwägen Sie, diese Optimierung zu aktivieren, indem Sie die <MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation> Projektdatei festlegen und sicherstellen, dass die richtige x:DataType Für diese Bindung angegeben ist.

Um diese Warnung zu beheben, aktivieren Sie die $(MauiEnableXamlCBindingWithSourceCompilation) Buildeigenschaft in Ihrer Projektdatei, und kommentieren Sie alle Bindungen mit den entsprechenden x:DataType.

Um sicherzustellen, dass diese Warnungen nicht ignoriert werden, sollten Sie bestimmte Warnungen ändern, um Fehler mit der $(WarningsAsErrors) Buildeigenschaft zu erstellen:

<WarningsAsErrors>$(WarningsAsErrors);XC0022;XC0023</WarningsAsErrors>

Verwenden Sie die $(NoWarn) Buildeigenschaft mit bestimmten Warnungscodes, um diese Warnungen zu ignorieren:

<NoWarn>$(NoWarn);XC0022;XC0023</NoWarn>

Wichtig

XC0022 und XC0023 Warnungen werden immer unterdrückt, es sei denn, die $(MauiStrictXamlCompilation) Buildeigenschaft ist auf true.

Wenn Sie die Buildeigenschaft $(TreatWarningsAsErrors) in der true Projektdatei Ihrer App festlegen, bestimmte XAML-Compilerwarnungen jedoch ignorieren möchten, verwenden Sie entweder die $(NoWarn) Buildeigenschaft, um diese Warnungen oder die $(WarningsNotAsErrors) Buildeigenschaft zu stillen, um den Schweregrad einiger bestimmter Codes zu verringern.

Standardmäßig erzeugt .NET MAUI Buildwarnungen für XAML-Bindungen, die keine kompilierten Bindungen verwenden. Sie können sich für kompilierte Bindungen entscheiden, die als Fehler behandelt werden, indem Sie die $(MauiStrictXamlCompilation) Eigenschaften und $(TreatWarningsAsErrors) Buildeigenschaften true in der Projektdatei Ihrer App (*.csproj) festlegen:

<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>

Hinweis

Standardmäßig ist $(MauiStrictXamlCompilation) die false Buildeigenschaft, es sei denn, Sie veröffentlichen Ihre App mit vollständiger Kürzung oder NativeAOT.

Kompilierte Bindungen im Code

Bindungen, die in Code geschrieben wurden, verwenden in der Regel Zeichenfolgenpfade, die zur Laufzeit mit Reflexion aufgelöst werden. Die SetBinding-Erweiterungsmethode hat jedoch auch eine Überladung, die Bindungen mithilfe eines Func-Arguments anstelle einer Zeichenfolge definiert:

MyLabel.SetBinding(Label.TextProperty, static (Entry entry) => entry.Text);

Nicht alle Methoden können verwendet werden, um eine kompilierte Bindung zu definieren. Der Ausdruck muss ein einfacher Eigenschaftszugriffsausdruck sein. Die folgenden Beispiele zeigen gültige und ungültige Bindungsausdrücke:

// 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}";

Warnung

Wenn auf den Set-Accessor für eine Eigenschaft oder einen Indexer nicht zugegriffen werden kann, tritt ein CS0272-Compilerfehler auf. Erhöhen Sie in diesem Fall die Zugänglichkeit des Accessors.

Darüber hinaus legt die BindingBase.Create-Methode die Bindung direkt auf dem Objekt mit einem Func fest und gibt die Instanz des Bindungsobjekts zurück:

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()
});

Diese kompilierten Bindungsansätze bieten die folgenden Vorteile:

  • Verbesserte Leistung bei der Datenbindung durch Auflösung von Bindungsausdrücken zur Kompilierungszeit statt zur Laufzeit.
  • Eine bessere Erfahrung bei der Fehlerbehebung für Entwickelnde, da ungültige Bindungen als Build-Fehler gemeldet werden.
  • IntelliSense beim Bearbeiten.

Leistung

Kompilierte Bindungen verbessern die Leistung der Datenbindung mit variierenden Leistungsvorteilen.

  • Eine kompilierte Bindung, die eine Eigenschaftsänderungsbenachrichtigung verwendet (z.B. eine OneWay-, OneWayToSource- oder TwoWay-Bindung), wird ungefähr achtmal so schnell wie eine klassische Bindung aufgelöst.
  • Eine kompilierte Bindung, die keine Eigenschaftsänderungsbenachrichtigung verwendet (z.B. eine OneTime-Bindung) wird ungefähr 20-mal so schnell wie eine klassische Bindung aufgelöst.
  • Das Festlegen der BindingContext-Eigenschaft für eine kompilierte Bindung, die eine Eigenschaftsänderungsbenachrichtigung verwendet (z.B. eine OneWay-, OneWayToSource- oder TwoWay-Bindung), wird ungefähr fünfmal so schnell wie eine auf BindingContext festgelegte klassische Bindung aufgelöst.
  • Das Festlegen der BindingContext-Eigenschaft für eine kompilierte Bindung, die keine Eigenschaftsänderungsbenachrichtigung verwendet (z.B. eine OneTime-Bindung), wird ungefähr siebenmal so schnell wie eine auf BindingContext festgelegte klassische Bindung aufgelöst.

Diese Leistungsunterschiede können bei mobilen Geräten abhängig von der verwendeten Plattform, der Version des verwendeten Betriebssystems und dem Gerät, auf dem die Anwendung ausgeführt wird, gesteigert werden.