Teil 2. Grundlegende XAML-Syntax
XAML ist hauptsächlich für die Instanziierung und Initialisierung von Objekten konzipiert. Häufig müssen Eigenschaften jedoch auf komplexe Objekte festgelegt werden, die nicht einfach als XML-Zeichenfolgen dargestellt werden können, und manchmal müssen Eigenschaften, die von einer Klasse definiert werden, für eine untergeordnete Klasse festgelegt werden. Diese beiden Anforderungen erfordern die wesentlichen XAML-Syntaxfeatures von Eigenschaftenelementen und angefügten Eigenschaften.
Eigenschaftenelemente
In XAML werden Eigenschaften von Klassen normalerweise als XML-Attribute festgelegt:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large"
TextColor="Aqua" />
Es gibt jedoch eine alternative Möglichkeit, eine Eigenschaft in XAML festzulegen. Wenn Sie diese Alternative mit TextColor
ausprobieren möchten, löschen Sie zuerst die vorhandene TextColor
Einstellung:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large" />
Öffnen Sie das Tag leerer Elemente Label
, indem Sie es in Start- und Endtags unterteilen:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
</Label>
Fügen Sie innerhalb dieser Tags Start- und Endtags hinzu, die aus dem Klassennamen und einem durch einen Punkt getrennten Eigenschaftsnamen bestehen:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>
</Label.TextColor>
</Label>
Legen Sie den Eigenschaftswert wie folgt als Inhalt dieser neuen Tags fest:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>
Diese beiden Methoden zum Angeben der TextColor
Eigenschaft sind funktionell gleichwertig, verwenden aber nicht die beiden Möglichkeiten für dieselbe Eigenschaft, da die Eigenschaft dadurch effektiv zweimal festgelegt würde und möglicherweise mehrdeutig ist.
Mit dieser neuen Syntax kann eine praktische Terminologie eingeführt werden:
Label
ist ein Objektelement. Es ist ein Xamarin.Forms Objekt, das als XML-Element ausgedrückt wird.Text
,VerticalOptions
undFontAttributes
FontSize
sind Eigenschaftsattribute. Es handelt sich um Eigenschaften, die als XML-Attribute ausgedrückt werden Xamarin.Forms .- In diesem endgültigen
TextColor
Codeausschnitt wurde ein Eigenschaftselement. Es ist eine Xamarin.Forms Eigenschaft, aber es ist jetzt ein XML-Element.
Die Definition von Eigenschaftselementen scheint zunächst eine Verletzung der XML-Syntax zu sein, ist es aber nicht. Der Punkt hat in XML keine besondere Bedeutung. Bei einem XML-Decoder Label.TextColor
handelt es sich einfach um ein normales untergeordnetes Element.
In XAML ist diese Syntax jedoch sehr speziell. Eine der Regeln für Eigenschaftselemente ist, dass nichts anderes im Label.TextColor
Tag angezeigt werden kann. Der Wert der -Eigenschaft wird immer als Inhalt zwischen den Start- und Endtags des Eigenschaftselements definiert.
Sie können die Eigenschaftselementsyntax für mehrere Eigenschaften verwenden:
<Label Text="Hello, XAML!"
VerticalOptions="Center">
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>
Alternativ können Sie die Eigenschaftenelementsyntax für alle Eigenschaften verwenden:
<Label>
<Label.Text>
Hello, XAML!
</Label.Text>
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
<Label.VerticalOptions>
Center
</Label.VerticalOptions>
</Label>
Zunächst mag die Syntax von Eigenschaftselementen wie ein unnötiger langwieriger Ersatz für etwas vergleichsweise einfaches aussehen, und in diesen Beispielen ist dies sicherlich der Fall.
Die Syntax von Eigenschaftselementen wird jedoch wichtig, wenn der Wert einer Eigenschaft zu komplex ist, um als einfache Zeichenfolge ausgedrückt zu werden. Innerhalb der Eigenschaftselementtags können Sie ein anderes Objekt instanziieren und dessen Eigenschaften festlegen. Beispielsweise können Sie eine Eigenschaft VerticalOptions
explizit auf einen LayoutOptions
Wert mit Eigenschafteneinstellungen festlegen:
<Label>
...
<Label.VerticalOptions>
<LayoutOptions Alignment="Center" />
</Label.VerticalOptions>
</Label>
Ein weiteres Beispiel: Das Grid
verfügt über zwei Eigenschaften mit dem Namen RowDefinitions
und ColumnDefinitions
. Diese beiden Eigenschaften sind vom Typ RowDefinitionCollection
und ColumnDefinitionCollection
, bei denen es sich um Sammlungen von RowDefinition
- und ColumnDefinition
-Objekten handelt. Sie müssen eigenschaftenelementsyntax verwenden, um diese Auflistungen festzulegen.
Hier ist der Anfang der XAML-Datei für eine GridDemoPage
Klasse, die die Eigenschaftselementtags für die RowDefinitions
Auflistung und ColumnDefinitions
zeigt:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
...
</Grid>
</ContentPage>
Beachten Sie die abgekürzte Syntax zum Definieren von Zellen mit automatischer Größe, Zellen mit Pixelbreiten und -höhen sowie star Einstellungen.
Angefügte Eigenschaften
Sie haben gerade gesehen, dass für die Grid
-Auflistungen und ColumnDefinitions
-Auflistungen Eigenschaftenelemente RowDefinitions
erforderlich sind, um die Zeilen und Spalten zu definieren. Es muss jedoch auch eine Möglichkeit für den Programmierer geben, die Zeile und Spalte anzugeben, in der sich die einzelnen untergeordneten Elemente befinden Grid
.
Innerhalb des Tags für jedes untergeordnete Element von Grid
geben Sie die Zeile und Spalte dieses untergeordneten Elements mit den folgenden Attributen an:
Grid.Row
Grid.Column
Die Standardwerte dieser Attribute sind 0. Sie können auch angeben, ob sich ein untergeordnetes Element über mehrere Zeilen oder Spalten mit den folgenden Attributen erstreckt:
Grid.RowSpan
Grid.ColumnSpan
Diese beiden Attribute weisen die Standardwerte 1 auf.
Dies ist die vollständige Datei GridDemoPage.xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Label Text="Autosized cell"
Grid.Row="0" Grid.Column="0"
TextColor="White"
BackgroundColor="Blue" />
<BoxView Color="Silver"
HeightRequest="0"
Grid.Row="0" Grid.Column="1" />
<BoxView Color="Teal"
Grid.Row="1" Grid.Column="0" />
<Label Text="Leftover space"
Grid.Row="1" Grid.Column="1"
TextColor="Purple"
BackgroundColor="Aqua"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
<Label Text="Span two rows (or more if you want)"
Grid.Row="0" Grid.Column="2" Grid.RowSpan="2"
TextColor="Yellow"
BackgroundColor="Blue"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
<Label Text="Span two columns"
Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
TextColor="Blue"
BackgroundColor="Yellow"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
<Label Text="Fixed 100x100"
Grid.Row="2" Grid.Column="2"
TextColor="Aqua"
BackgroundColor="Red"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
</Grid>
</ContentPage>
Die Grid.Row
Einstellungen von Grid.Column
0 sind nicht erforderlich, werden jedoch aus Gründen der Übersichtlichkeit in der Regel einbezogen.
So sieht es aus:
Allein anhand der Syntax zu urteilen, scheinen diese Grid.Row
Attribute , Grid.Column
, Grid.RowSpan
und Grid.ColumnSpan
statische Felder oder Eigenschaften von Grid
zu sein, Grid
aber interessanterweise definiert nichts mit dem Namen Row
, Column
, , RowSpan
oder ColumnSpan
.
Grid
Definiert stattdessen vier bindungsfähige Eigenschaften mit den Namen RowProperty
, ColumnProperty
, RowSpanProperty
und ColumnSpanProperty
. Hierbei handelt es sich um spezielle Typen von bindungsfähigen Eigenschaften, die als angefügte Eigenschaften bezeichnet werden. Sie werden von der Grid
-Klasse definiert, aber auf untergeordnete Elemente von Grid
festgelegt.
Wenn Sie diese angefügten Eigenschaften im Code verwenden möchten, stellt die Grid
-Klasse statische Methoden mit dem Namen SetRow
, GetColumn
usw. bereit. In XAML werden diese angefügten Eigenschaften jedoch als Attribute in den untergeordneten Eigenschaften festgelegt, die Grid
einfache Eigenschaftennamen verwenden.
Angefügte Eigenschaften sind in XAML-Dateien immer als Attribute erkennbar, die sowohl eine Klasse als auch einen durch einen Punkt getrennten Eigenschaftennamen enthalten. Sie werden als angefügte Eigenschaften bezeichnet, da sie von einer Klasse (in diesem Fall Grid
) definiert, aber an andere Objekte (in diesem Fall untergeordnete Objekte von Grid
) angefügt sind. Während des Layouts können die Grid
Werte dieser angefügten Eigenschaften abgefragt werden, um zu wissen, wo die einzelnen untergeordneten Elemente platziert werden sollen.
Die AbsoluteLayout
-Klasse definiert zwei angefügte Eigenschaften mit dem Namen LayoutBounds
und LayoutFlags
. Hier sehen Sie ein Schachbrettmuster, das mithilfe der proportionalen Positionierungs- und Größeneigenschaften von AbsoluteLayout
realisiert wird:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.AbsoluteDemoPage"
Title="Absolute Demo Page">
<AbsoluteLayout BackgroundColor="#FF8080">
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />
</AbsoluteLayout>
</ContentPage>
Und so sieht die Ausgabe aus:
Für so etwas könnten Sie die Weisheit der Verwendung von XAML in Frage stellen. Sicherlich legt die Wiederholung und Regelmäßigkeit des LayoutBounds
Rechtecks nahe, dass es im Code besser realisiert werden könnte.
Dies ist sicherlich ein berechtigtes Anliegen, und es gibt kein Problem, die Verwendung von Code und Markup beim Definieren Ihrer Benutzeroberflächen auszugleichen. Es ist einfach, einige der Visuals in XAML zu definieren und dann den Konstruktor der CodeBehind-Datei zu verwenden, um weitere Visuals hinzuzufügen, die besser in Schleifen generiert werden können.
Content-Eigenschaften
In den vorherigen Beispielen sind die StackLayout
Objekte , Grid
und AbsoluteLayout
auf die Content
-Eigenschaft von ContentPage
festgelegt, und die untergeordneten Elemente dieser Layouts sind tatsächlich Elemente in der Children
Auflistung. Content
Diese Eigenschaften und Children
Eigenschaften befinden sich jedoch nirgendwo in der XAML-Datei.
Sie können die Content
Eigenschaften und Children
sicherlich als Eigenschaftselemente einschließen, z. B. im XamlPlusCode-Beispiel :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.XamlPlusCodePage"
Title="XAML + Code Page">
<ContentPage.Content>
<StackLayout>
<StackLayout.Children>
<Slider VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged" />
<Label x:Name="valueLabel"
Text="A simple Label"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Click Me!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout.Children>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Die eigentliche Frage lautet: Warum sind diese Eigenschaftselemente in der XAML-Datei nicht erforderlich?
Für Elemente, die in Xamarin.Forms für die Verwendung in XAML definiert sind, darf eine Eigenschaft im Attribut für die ContentProperty
-Klasse gekennzeichnet sein. Wenn Sie die ContentPage
-Klasse in der Onlinedokumentation Xamarin.Forms suchen, sehen Sie folgendes Attribut:
[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage
Dies bedeutet, dass die Content
Eigenschaftselementtags nicht erforderlich sind. Es wird davon ausgegangen, dass alle XML-Inhalte, die zwischen den Start- und Endtags ContentPage
angezeigt werden, der Content
-Eigenschaft zugewiesen werden.
StackLayout
, Grid
, AbsoluteLayout
und RelativeLayout
alle leiten von abLayout<View>
, und wenn Sie in der Xamarin.Forms Dokumentation nachschlagenLayout<T>
, sehen Sie ein anderes ContentProperty
Attribut:
[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...
Dadurch können Inhalte des Layouts automatisch ohne explizite Children
Eigenschaftselementtags zur Children
Auflistung hinzugefügt werden.
Andere Klassen verfügen auch über ContentProperty
Attributdefinitionen. Die Inhaltseigenschaft von Label
ist z. B Text
. . Weitere Informationen finden Sie in der API-Dokumentation.
Plattformunterschiede zu OnPlatform
In Einzelseitenanwendungen ist es üblich, die -Eigenschaft auf der Padding
Seite festzulegen, um zu vermeiden, dass die iOS-status leiste überschrieben wird. Im Code können Sie die Device.RuntimePlatform
-Eigenschaft zu diesem Zweck verwenden:
if (Device.RuntimePlatform == Device.iOS)
{
Padding = new Thickness(0, 20, 0, 0);
}
Sie können auch etwas Ähnliches in XAML mit den OnPlatform
Klassen und On
ausführen. Schließen Sie zunächst Eigenschaftenelemente für die Padding
Eigenschaft am oberen Rand der Seite ein:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
</ContentPage.Padding>
...
</ContentPage>
Fügen Sie innerhalb dieser Tags ein -Tag ein OnPlatform
. OnPlatform
ist eine generische Klasse. Sie müssen das generische Typargument angeben, in diesem Fall Thickness
, bei dem es sich um den Typ der Padding
Eigenschaft handelt. Glücklicherweise gibt es ein XAML-Attribut speziell zum Definieren generischer Argumente namens x:TypeArguments
. Dies sollte mit dem Typ der Eigenschaft übereinstimmen, die Sie festlegen:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
OnPlatform
verfügt über eine Eigenschaft namens Platforms
, die eine IList
von On
-Objekten ist. Verwenden Sie Eigenschaftselementtags für diese Eigenschaft:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>
</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Fügen Sie nun Elemente hinzu On
. Legen Sie jeweils die Platform
Eigenschaft und die Eigenschaft fest, die Value
für die Thickness
-Eigenschaft markups angegeben werden soll:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android" Value="0, 0, 0, 0" />
<On Platform="UWP" Value="0, 0, 0, 0" />
</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Dieses Markup kann vereinfacht werden. Die content-Eigenschaft von OnPlatform
ist Platforms
, sodass diese Eigenschaftselementtags entfernt werden können:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android" Value="0, 0, 0, 0" />
<On Platform="UWP" Value="0, 0, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Die Platform
Eigenschaft von On
ist vom Typ IList<string>
, sodass Sie mehrere Plattformen einschließen können, wenn die Werte identisch sind:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android, UWP" Value="0, 0, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Da Android und UWP auf den Standardwert festgelegt Padding
sind, kann dieses Tag entfernt werden:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Dies ist die Standardmethode zum Festlegen einer plattformabhängigen Padding
Eigenschaft in XAML. Wenn die Value
Einstellung nicht durch eine einzelne Zeichenfolge dargestellt werden kann, können Sie Eigenschaftenelemente für sie definieren:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS">
<On.Value>
0, 20, 0, 0
</On.Value>
</On>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>
Hinweis
Die OnPlatform
Markuperweiterung kann auch in XAML verwendet werden, um die Darstellung der Benutzeroberfläche plattformbezogen anzupassen. Es bietet die gleiche Funktionalität wie die OnPlatform
Klassen und On
, aber mit einer präziseren Darstellung. Weitere Informationen finden Sie unter OnPlatform-Markuperweiterung.
Zusammenfassung
Mit Eigenschaftselementen und angefügten Eigenschaften wurde ein Großteil der grundlegenden XAML-Syntax eingerichtet. Manchmal müssen Sie Eigenschaften jedoch indirekt auf Objekte festlegen, z. B. aus einem Ressourcenwörterbuch. Dieser Ansatz wird im nächsten Teil, Teil 3, behandelt . XAML-Markuperweiterungen.