Kompilierte Bindungen in Xamarin.Forms
Kompilierte Bindungen werden schneller aufgelöst als klassische, wodurch die Leistung der Datenbindung in Xamarin.Forms-Anwendungen verbessert wird.
Datenbindungen weisen zwei Hauptprobleme auf:
- 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.
- 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 Xamarin.Forms-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.
Sie können kompilierte Bindungen wie folgt verwenden:
- Aktivieren Sie die XAML-Kompilierung. Weitere Informationen zur XAML-Kompilierung finden Sie unter XAML Compilation (XAML-Kompilierung).
- Legen Sie ein
x:DataType
-Attribut für einVisualElement
auf den Typ des Objekts fest, an dasVisualElement
und dessen untergeordnete Elemente gebunden werden.
Hinweis
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.
Wenn Sie kompilierte Bindungen verwenden möchten, muss das Attribut x:DataType
auf ein Zeichenfolgenliteral oder einen Typ festgelegt sein, der die Markuperweiterung x:Type
verwendet. 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 Bindungsausdrücke deaktiviert, die 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.
Verwenden kompilierter Bindungen
Die Seite Compiled Color Selector (Kompilierte Farbauswahl) veranschaulicht die Verwendung von kompilierten Bindungen zwischen Xamarin.Forms-Ansichten und ViewModel-Eigenschaften:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorSelectorPage"
Title="Compiled Color Selector">
...
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<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>
Der StackLayout
-Stamm instanziiert das HslColorViewModel
-Objekt und initialisiert die Color
-Eigenschaft innerhalb der Eigenschaftselementtags für die BindingContext
-Eigenschaft. Dieser StackLayout
-Stamm definiert außerdem das x:DataType
-Attribut als ViewModel-Typ, der angibt, dass alle Bindungsausdrücke in der Ansichtshierarchie des StackLayout
-Stamms 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 StackLayout
. 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 Slider
-Elemente über die ViewModel-Klasse basierend auf der ursprünglichen Color
-Eigenschaft festgelegt, die bei der Instanziierung von ViewModel festgelegt wurde. Dies wird im folgenden Screenshot veranschaulicht:
Wenn die Schieberegler bewegt werden, werden die Elemente BoxView
und Label
entsprechend aktualisiert.
Weitere Informationen zu dieser Farbauswahl finden Sie unter ViewModels and Property-Change Notifications (Benachrichtigungen für Änderungen an ViewModels und Eigenschaften).
Verwenden von kompilierten Bindungen in einer DataTemplate-Klasse
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 x:DataType
-Attributs deklarieren, wenn kompilierte Bindungen in einer DataTemplate
-Klasse verwendet werden.
Die Seite Compiled Color List (Kompilierte Farbliste) veranschaulicht die Verwendung kompilierter Bindungen in einer DataTemplate
-Klasse:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
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>
Für die Eigenschaft ListView.ItemsSource
wird die statische Eigenschaft NamedColor.All
festgelegt. Die NamedColor
-Klasse nutzt die .NET-Reflektion, um alle statischen öffentlichen Felder in der Color
-Struktur aufzuführen und sie mitsamt ihrer Namen in einer Sammlung zu speichern, auf die über die statische Eigenschaft All
zugegriffen werden kann. Aus diesem Grund wird ListView
mit allen Instanzen von NamedColor
aufgefüllt. Der Bindungskontext aller Elemente in der ListView
-Klasse wird auf ein NamedColor
-Objekt festgelegt. Die Elemente BoxView
und Label
in der ViewCell
-Klasse werden an NamedColor
-Eigenschaften gebunden.
Beachten Sie, dass DataTemplate
den Typ NamedColor
für das x:DataType
-Attribut definiert, d.h., dass alle Bindungsausdrücke in der Ansichtshierarchie DataTemplate
kompiliert werden. Dies können Sie überprüfen, indem Sie einen der Bindungsausdrücke so ändern, dass eine nicht vorhandene NamedColor
-Eigenschaft gebunden wird, was zu einem Buildfehler führt. 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.
Wenn die Anwendung zum ersten Mal ausgeführt wird, wird die ListView
-Klasse mit NamedColor
-Instanzen aufgefüllt. Wenn ein Element in der ListView
-Klasse ausgewählt wird, wird die Farbe des ausgewählten Elements für die BoxView.Color
-Eigenschaft in der ListView
-Klasse festgelegt:
Wenn andere Elemente in der ListView
-Klasse ausgewählt werden, wird die Farbe der BoxView
-Klasse aktualisiert.
Kombinieren von kompilierten und klassischen 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 x:Null
als null
definiert werden. Dadurch wird impliziert, dass alle Bindungsausdrücke in der Ansichtshierarchie klassische Bindungen nutzen. Die Seite Mixed Bindings (Gemischte Bindungen) veranschaulicht diese Vorgehensweise:
<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 HslColorViewModel
für das Attribut x:DataType
fest, d.h., dass alle Bindungsausdrücke im StackLayout
-Stamm der Ansichtshierarchie kompiliert werden. Das Attribut x:DataType
wird jedoch von der inneren StackLayout
-Klasse mithilfe des Markupausdrucks x:Null
mit dem Wert 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).
Leistung
Kompilierte Bindungen verbessern die Leistung der Datenbindung mit variierenden Leistungsvorteilen. Unittests zeigen folgende Ergebnisse:
- Eine kompilierte Bindung, die eine Eigenschaftsänderungsbenachrichtigung verwendet (z.B. eine
OneWay
-,OneWayToSource
- oderTwoWay
-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. eineOneWay
-,OneWayToSource
- oderTwoWay
-Bindung), wird ungefähr fünfmal so schnell wie eine aufBindingContext
festgelegte klassische Bindung aufgelöst. - Das Festlegen der
BindingContext
-Eigenschaft für eine kompilierte Bindung, die keine Eigenschaftsänderungsbenachrichtigung verwendet (z.B. eineOneTime
-Bindung), wird ungefähr siebenmal so schnell wie eine aufBindingContext
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.