Einfache Xamarin.Forms-Bindungen
Bei einer Xamarin.Forms-Datenbindung wird ein Eigenschaftenpaar zwischen zwei Objekten verknüpft, von denen mindestens eines ein Benutzeroberflächenobjekt ist. Diese beiden Objekte sind das Ziel und die Quelle:
- Das Ziel ist das Objekt (und die Eigenschaft), auf dem die Datenbindung festgelegt wird.
- Die Quelle ist das Objekt (und die Eigenschaft), auf die von der Datenbindung verwiesen wird.
Dieser Unterschied kann mitunter verwirrend sein: Im einfachsten Fall fließen Daten von der Quelle zum Ziel. Das bedeutet, dass der Wert der Zieleigenschaft über den Wert der Quelleigenschaft festgelegt wird. In einigen Fällen können Daten jedoch auch vom Ziel zur Quelle fließen oder sogar in beide Richtungen. Merken Sie sich, dass das Ziel immer das Objekt ist, auf dem die Datenbindung festgelegt wird, auch wenn es der Ursprung der Daten ist und keine Daten empfängt.
Bindungen mit Bindungskontext
Datenbindungen werden zwar normalerweise komplett in XAML angegeben, ist es dennoch empfehlenswert, sich Datenbindungen im Code anzusehen. Die Seite Basic Code Binding (Einfache Codebindung) enthält eine XAML-Datei mit einem Label
- und einem Slider
-Objekt:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicCodeBindingPage"
Title="Basic Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="48"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Dieser Slider
ist auf einen Bereich zwischen 0 und 360 festgelegt. Dieses Programm soll das Label
drehen, indem es den Slider
anpasst.
Ohne Datenbindungen würden Sie das ValueChanged
-Ereignis des Slider
auf einen Ereignishandler festlegen, der auf die Value
-Eigenschaft des Slider
zugreift und den Wert auf die Rotation
-Eigenschaft des Label
festlegt. Durch eine Datenbindung wird diese Aufgabe automatisiert. Der Ereignishandler und der darin enthaltene Code sind nicht mehr erforderlich.
Sie können eine Bindung auf einer Instanz einer beliebigen Klasse festlegen, die von BindableObject
abgeleitet wurde. Dazu zählen Element
-, VisualElement
-, View
- und View
-Derivate. Die Bindung wird immer auf dem Zielobjekt festgelegt. Die Bindung verweist auf das Quellobjekt. Verwenden Sie die beiden folgenden Member der Zielklasse, um die Datenbindung herzustellen:
- Die
BindingContext
-Eigenschaft gibt das Quellobjekt an. - Die
SetBinding
-Methode gibt die Ziel- und Quelleigenschaft an.
In diesem Beispiel ist das Label
das Bindungsziel, und der Slider
ist die Bindungsquelle. Änderungen der Slider
-Quelle wirken sich auf die Drehung des Label
-Ziels aus. Daten fließen von der Quelle zum Ziel.
Die von BindableObject
definierte SetBinding
-Methode weist ein Argument vom Typ BindingBase
auf, von dem die Binding
-Klasse abgeleitet wird. Es gibt aber auch andere SetBinding
-Methoden, die von der BindableObjectExtensions
-Klasse definiert werden. Die CodeBehind-Datei im Beispiel Basic Code Binding (Einfache Codebindung) verwendet eine einfachere SetBinding
-Erweiterungsmethode aus dieser Klasse.
public partial class BasicCodeBindingPage : ContentPage
{
public BasicCodeBindingPage()
{
InitializeComponent();
label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
}
}
Das Label
ist das Bindungsziel. Deshalb wird diese Eigenschaft dort festgelegt, und dort wird die Methode aufgerufen. Die BindingContext
-Eigenschaft gibt die Bindungsquelle an, der Slider
.
Die SetBinding
-Methode wird auf dem Bindungsziel aufgerufen, gibt aber sowohl die Ziel- als auch die Quelleigenschaft an. Die Zieleigenschaft wird als BindableProperty
-Objekt angegeben: Label.RotationProperty
. Die Quelleigenschaft wird als Zeichenfolge angegeben und gibt die Value
-Eigenschaft des Slider
an.
Die SetBinding
-Methode macht eine der wichtigsten Regeln der Datenbindung deutlich:
Die Zieleigenschaft muss von einer bindbaren Eigenschaft unterstützt werden.
Diese Regel impliziert, dass das Zielobjekt eine Instanz einer Klasse sein muss, die von BindableObject
abgeleitet wird. Im Artikel zu bindbaren Eigenschaften finden Sie eine Übersicht über bindbare Objekte und Eigenschaften.
Es gibt keine entsprechende Regel für die Quelleigenschaft, die als Zeichenfolge angegeben wird. Intern wird die Reflektion verwendet, um auf die tatsächliche Eigenschaft zuzugreifen. In diesem Fall wird die Value
-Eigenschaft jedoch auch von einer bindbaren Eigenschaft unterstützt.
Der Code kann bis zu einem gewissen Grad vereinfacht werden: Die bindbare Eigenschaft RotationProperty
wird von VisualElement
definiert und von Label
und ContentPage
geerbt, weshalb der Klassenname im SetBinding
-Aufruf nicht erforderlich ist:
label.SetBinding(RotationProperty, "Value");
Das Einbeziehen des Klassennamens ist jedoch eine gute Möglichkeit, das Zielobjekt anzugeben.
Wenn Sie Slider
anpassen, rotiert Label
dementsprechend:
Die Seite Basic XAML Binding (Einfache XAML-Bindung) stimmt fast vollständig mit der Seite Basic Code Binding (Einfache Codebindung) überein. Der einzige Unterschied besteht darin, dass die gesamte Codebindung in XAML definiert wird:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicXamlBindingPage"
Title="Basic XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Die Datenbindung wird genau wie im Code auf dem Zielobjekt festgelegt, in diesem Fall Label
. Es wurden zwei XAML-Markuperweiterungen verwendet. Diese können leicht durch die geschweiften Klammern erkannt werden:
- Die Markuperweiterung
x:Reference
ist erforderlich, um auf das Quellobjekt zu verweisen, auf denSlider
mit dem Namenslider
. - Die Markuperweiterung
Binding
verknüpft dieRotation
-Eigenschaft desLabel
mit derValue
-Eigenschaft desSlider
.
Weitere Informationen zu XAML-Markuperweiterungen finden Sie unter XAML Markup Extensions (XAML-Markuperweiterungen). Die Markuperweiterung x:Reference
wird von der ReferenceExtension
-Klasse unterstützt. Binding
wird von der BindingExtension
-Klasse unterstützt. Wie in den XML-Namespacepräfixen angegeben, ist x:Reference
Teil der XAML 2009-Spezifikation, und Binding
ist Teil von Xamarin.Forms. Beachten Sie, dass innerhalb der geschweiften Klammern keine Anführungszeichen verwendet wurden.
Beim Festlegen des x:Reference
-Objekts vergisst man schnell die Markuperweiterung BindingContext
. Die Eigenschaft wird häufig fälschlicherweise direkt wie folgt auf den Namen der Bindungsquelle festgelegt:
BindingContext="slider"
Das ist jedoch nicht korrekt. Dieses Markup legt die Eigenschaft BindingContext
auf ein string
-Objekt fest, dessen Zeichen „Slider“ ausschreiben.
Beachten Sie, dass die Quelleigenschaft mit der Path
-Eigenschaft des BindingExtension
-Objekts angegeben wird, was der Path
-Eigenschaft der Binding
-Klasse entspricht.
Das Markup auf der Seite Basic XAML Binding (Einfache XAML-Bindung) kann vereinfacht werden: Für XAML-Markuperweiterungen wie x:Reference
und Binding
können Inhaltseigenschaftsattribute definiert werden. Für XAML-Markuperweiterungen bedeutet das, dass der Eigenschaftenname nicht verwendet werden muss. Die Eigenschaft Name
ist die Inhaltseigenschaft von x:Reference
, und die Path
-Eigenschaft ist die Inhaltseigenschaft von Binding
. Das bedeutet, dass sie nicht im Ausdruck verwendet werden müssen:
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference slider}"
Rotation="{Binding Value}" />
Bindungen ohne Bindungskontext
Die Eigenschaft BindingContext
ist ein wichtiger Bestandteil von Datenbindungen. Sie ist jedoch nicht immer notwendig. Stattdessen kann das Quellobjekt im SetBinding
-Aufruf oder der Binding
-Markuperweiterung angegeben werden.
Dies wird im Beispiel Alternative Code Binding (Alternative Codebindung) veranschaulicht. Die XAML-Datei ähnelt dem Beispiel Basic Code Binding (Einfache Codebindung). Der einzige Unterschied besteht darin, dass der Slider
so definiert wird, dass er die Scale
-Eigenschaft des Label
steuert. Aus diesem Grund wird der Slider
Bereich für einen Bereich von -2 bis 2 festgelegt:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeCodeBindingPage"
Title="Alternative Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Die CodeBehind-Datei stellt die Bindung mit der SetBinding
-Methode her, die von BindableObject
definiert wird. Das Argument ist ein Konstruktor für die Binding
-Klasse:
public partial class AlternativeCodeBindingPage : ContentPage
{
public AlternativeCodeBindingPage()
{
InitializeComponent();
label.SetBinding(Label.ScaleProperty, new Binding("Value", source: slider));
}
}
Der Konstruktor Binding
verfügt über sechs Parameter, weshalb der Parameter source
mit einem benannten Argument angegeben wird. Das Argument ist das slider
-Objekt.
Wenn Sie dieses Programm ausführen, passiert etwas Unerwartetes:
Wenn die Seite angezeigt wird, sieht sie zunächst wie der iOS-Bildschirm links aus. Wo ist das Label
?
Dieses Problem wird ausgelöst, weil der Slider
einen Anfangswert von 0 (null) hat. Dadurch wird die Scale
-Eigenschaft des Label
auch auf 0 (null) festgelegt, also der Standardwert von 1 überschrieben. Deshalb ist das Label
zunächst nicht sichtbar. Wie Sie auf dem Android-Screenshot sehen können, können Sie den Slider
anpassen, damit das Label
wieder angezeigt wird. Dass es aber zunächst nicht angezeigt wurde, ist verwirrend.
Im nächsten Artikel erfahren Sie, wie Sie dieses Problem umgehen, indem Sie den Slider
über den Standardwert der Scale
-Eigenschaft initialisieren.
Hinweis
Die VisualElement
-Klasse definiert auch die Eigenschaften ScaleX
und ScaleY
, die das VisualElement
horizontal und vertikal skalieren können.
Die Seite Alternative XAML Binding (Alternative XAML-Bindung) zeigt die entsprechende Bindung in XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeXamlBindingPage"
Title="Alternative XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value}" />
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Hier verfügt die Markuperweiterung Binding
über zwei festgelegte Eigenschaften, Source
und Path
, die durch ein Komma getrennt sind. Sie können auch in eine Zeile geschrieben werden, wenn Sie dies bevorzugen:
Scale="{Binding Source={x:Reference slider}, Path=Value}" />
Die Eigenschaft Source
wird auf eine eingebettete x:Reference
-Markuperweiterung festgelegt. Dabei wird die gleiche Syntax wie beim Festlegen des BindingContext
verwendet. Beachten Sie, dass innerhalb der geschweiften Klammern keine Anführungszeichen verwendet werden und dass die beiden Eigenschaften durch ein Komma getrennt werden müssen.
Die Inhaltseigenschaft der Markuperweiterung Binding
ist Path
, aber Path=
-Teil der Markuperweiterung kann nur weg gelassen werden, wenn sie die erste Eigenschaft im Ausdruck ist. Tauschen Sie die beiden Eigenschaften, um den Path=
-Teil weglassen zu können:
Scale="{Binding Value, Source={x:Reference slider}}" />
Obwohl XAML-Markuperweiterungen normalerweise durch geschweifte Klammern getrennt werden, können sie auch als Objektelemente ausgedrückt werden:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<Label.Scale>
<Binding Source="{x:Reference slider}"
Path="Value" />
</Label.Scale>
</Label>
Jetzt sind die Eigenschaften Source
und Path
normale XAML-Attribute: Die Werte befinden sich in Anführungszeichen, und die Attribute sind nicht durch Kommas getrennt. Die Markuperweiterung x:Reference
kann auch ein Objektelement werden:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<Label.Scale>
<Binding Path="Value">
<Binding.Source>
<x:Reference Name="slider" />
</Binding.Source>
</Binding>
</Label.Scale>
</Label>
Diese Syntax ist unüblich, aber manchmal nötig, wenn komplexe Objekte involviert sind.
In den besprochenen Beispielen wurde die BindingContext
-Eigenschaft und die Source
-Eigenschaft von Binding
auf eine x:Reference
-Markuperweiterung festgelegt, um auf eine andere Ansicht auf der Seite zu verweisen. Die beiden Eigenschaften weisen den Typ Object
auf, und sie können auf ein beliebiges Objekt festgelegt werden, das Eigenschaften enthält, die für Bindungsquellen geeignet sind.
In den nächsten Artikeln lernen Sie, dass Sie die Eigenschaften BindingContext
oder Source
auf eine x:Static
-Markuperweiterung festlegen können, um auf die Werte einer statischen Eigenschaft oder eines statischen Felds zu verweisen. Sie können die Eigenschaften auch auf die StaticResource
-Markuperweiterung festlegen, um auf ein Objekt, das in einem Ressourcenverzeichnis gespeichert ist, oder direkt auf ein Objekt zu verweisen, das meist (aber nicht immer) eine ViewModel-Instanz ist.
Die BindingContext
-Eigenschaft kann auch auf ein Binding
-Objekt festgelegt werden, sodass die Eigenschaften Source
und Path
von Binding
den Bindungskontext definieren.
Vererbung von Bindungskontexten
In diesem Artikel haben Sie gelernt, dass Sie das Quellobjekt mit der Eigenschaft BindingContext
oder der Source
-Eigenschaft des Binding
-Objekts angeben können. Wenn beide Eigenschaften festgelegt sind, hat die Source
-Eigenschaft des Binding
-Objekts Vorrang vor der BindingContext
-Eigenschaft.
Die BindingContext
-Eigenschaft hat ein sehr wichtiges Merkmal:
Das Festlegen der Eigenschaft BindingContext
wird über die visuelle Struktur vererbt.
Wie Sie sehen, kann dies sehr praktisch sein, um Bindungsausdrücke zu vereinfachen, und in einigen Fällen – insbesondere in Model-View-ViewModel (MVVM)-Szenarien – ist es unerlässlich.
Das Beispiel Binding Context Inheritance (Bindungskontextvererbung) veranschaulicht die Vererbung des Bindungskontexts auf einfache Weise:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BindingContextInheritancePage"
Title="BindingContext Inheritance">
<StackLayout Padding="10">
<StackLayout VerticalOptions="FillAndExpand"
BindingContext="{x:Reference slider}">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="EndAndExpand"
Rotation="{Binding Value}" />
<BoxView Color="#800000FF"
WidthRequest="180"
HeightRequest="40"
HorizontalOptions="Center"
VerticalOptions="StartAndExpand"
Rotation="{Binding Value}" />
</StackLayout>
<Slider x:Name="slider"
Maximum="360" />
</StackLayout>
</ContentPage>
Die BindingContext
-Eigenschaft des StackLayout
-Objekts wird auf das Objekt slider
festgelegt. Dieser Bindungskontext wird sowohl vom Label
als auch von BoxView
geerbt. Deren Rotation
-Eigenschaften werden auf die Value
-Eigenschaft des Slider
festgelegt:
Im nächsten Artikel erfahren Sie, wie sich der Bindungsmodus auf den Datenfluss zwischen Ziel- und Quellobjekten auswirken kann.
Verwandte Links
Zugehörige Videos
Auf Channel 9 und auf YouTube finden Sie weitere Videos zu Xamarin.