Teil 2: Grundlegende XAML-Syntax
XAML ist hauptsächlich für die Instanziierung und Initialisierung von Objekten gedacht. Oft müssen jedoch Eigenschaften für komplexe Objekte festgelegt werden, die sich nicht einfach als XML-Strings darstellen lassen, und manchmal müssen Eigenschaften, die von einer Klasse definiert wurden, für eine untergeordnete Klasse festgelegt werden. Diese beiden Anforderungen erfordern die grundlegenden XAML-Syntaxmerkmale von Eigenschaftselementen und angehängten Eigenschaften.
Eigenschaftselemente
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 zum Festlegen einer Eigenschaft in XAML. Um diese Alternative zu TextColor
versuchen, löschen Sie zuerst die vorhandene TextColor
Einstellung:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large" />
Öffnen Sie das Leere-Element-Tag Label
, indem Sie es in Start- und Endtags trennen:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
</Label>
Fügen Sie in diesen Tags Start- und Endtags hinzu, die aus dem Klassennamen und einem Eigenschaftsnamen bestehen, der durch einen Punkt getrennt ist:
<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 funktional gleichwertig, verwenden aber nicht die beiden Methoden für dieselbe Eigenschaft, da dies effektiv das Festlegen der Eigenschaft zweimal sein würde und möglicherweise mehrdeutig sein könnte.
Mit dieser neuen Syntax können einige praktische Terminologie eingeführt werden:
Label
ist ein Objektelement. Es handelt sich um ein Xamarin.Forms Objekt, das als XML-Element ausgedrückt wird.Text
,VerticalOptions
,FontAttributes
undFontSize
sind Eigenschaftsattribute. Sie sind Eigenschaften, die als XML-Attribute ausgedrückt werden Xamarin.Forms .- In diesem endgültigen Codeausschnitt
TextColor
wurde es zu einem Eigenschaftselement. Es handelt sich um eine Xamarin.Forms Eigenschaft, aber es handelt sich jetzt um ein XML-Element.
Die Definition von Eigenschaftselementen scheint zunächst eine Verletzung der XML-Syntax zu sein, aber nicht. Der Punkt hat keine besondere Bedeutung in XML. 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 besteht darin, dass im Tag nichts anderes angezeigt werden Label.TextColor
kann. Der Wert der Eigenschaft wird immer als Inhalt zwischen den Start- und Endtags des Eigenschaftselements definiert.
Sie können 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>
Sie können auch 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 Eigenschaftselement wie ein unnötiger langer Ersatz für etwas vergleichsweise einfaches aussehen, und in diesen Beispielen ist das sicherlich der Fall.
Eigenschaftselementsyntax wird jedoch wesentlich, wenn der Wert einer Eigenschaft zu komplex ist, um als einfache Zeichenfolge ausgedrückt zu werden. Innerhalb der Eigenschaftselement-Tags können Sie ein anderes Objekt instanziieren und dessen Eigenschaften festlegen. Sie können z. B. eine Eigenschaft explizit festlegen, z VerticalOptions
. B. auf einen LayoutOptions
Wert mit Eigenschafteneinstellungen:
<Label>
...
<Label.VerticalOptions>
<LayoutOptions Alignment="Center" />
</Label.VerticalOptions>
</Label>
Ein weiteres Beispiel: Die Grid
beiden Eigenschaften haben den Namen RowDefinitions
und ColumnDefinitions
. Diese beiden Eigenschaften sind vom Typ RowDefinitionCollection
und ColumnDefinitionCollection
, die Auflistungen und RowDefinition
ColumnDefinition
Objekte sind. Zum Festlegen dieser Auflistungen müssen Sie die Eigenschaftselementsyntax verwenden.
Dies ist der Anfang der XAML-Datei für eine GridDemoPage
Klasse mit den Eigenschaftselementtags für die RowDefinitions
und ColumnDefinitions
Sammlungen:
<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 gekürzte Syntax zum Definieren von Zellen mit automatischer Größe, Zellen mit Pixelbreiten und -höhen sowie Sterneinstellungen.
Angefügte Eigenschaften
Sie haben gerade gesehen, dass für die Grid
Eigenschaftenelemente und RowDefinitions
ColumnDefinitions
Auflistungen die Zeilen und Spalten definiert werden müssen. Es muss jedoch auch eine Möglichkeit für den Programmierer geben, die Zeile und Spalte anzugeben, in der sich jedes untergeordnete Element der Grid
Datei befindet.
Innerhalb des Tags für jedes untergeordnete Element der Grid
Von Ihnen angegebenen Zeile und Spalte dieses untergeordneten Elements mit den folgenden Attributen:
Grid.Row
Grid.Column
Die Standardwerte dieser Attribute sind 0. Sie können auch angeben, ob ein untergeordnetes Element mehrere Zeilen oder Spalten mit diesen Attributen umfasst:
Grid.RowSpan
Grid.ColumnSpan
Diese beiden Attribute weisen Standardwerte von 1 auf.
Hier 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 Grid.Column
von 0 sind nicht erforderlich, werden jedoch in der Regel für Klarheitszwecke berücksichtigt.
Es sieht so aus:
Die Beurteilung ausschließlich aus der Syntax, diesen Grid.Row
, , Grid.Column
Grid.RowSpan
, und Grid.ColumnSpan
Attributen scheinen statische Felder oder Eigenschaften von Grid
, aber interessant genug, Grid
definiert nichts benanntRow
, , Column
RowSpan
, oder ColumnSpan
.
Grid
Definiert stattdessen vier bindbare Eigenschaften namens 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 durch die Klasse Grid
definiert, aber auf untergeordnete Elemente der Klasse Grid
gesetzt.
Wenn Sie diese angefügten Eigenschaften im Code verwenden möchten, stellt die Grid
Klasse statische Methoden namens SetRow
, GetColumn
usw. bereit. In XAML werden diese angefügten Eigenschaften jedoch als Attribute in den untergeordneten Elementen der Grid
Verwendung einfacher Eigenschaftennamen festgelegt.
Angefügte Eigenschaften sind in XAML-Dateien immer als Attribute erkennbar, die sowohl eine Klasse als auch einen Eigenschaftsnamen enthalten, die durch einen Punkt getrennt sind. Sie werden angehängte Eigenschaften genannt, weil sie von einer Klasse (in diesem Fall Grid
) definiert werden, aber an andere Objekte (in diesem Fall untergeordnete Elemente der Grid
) angehängt sind. Während des Layouts kann Grid
die Werte dieser angehängten Eigenschaften abfragen, um zu wissen, wo jedes untergeordnete Element platziert werden soll.
Die AbsoluteLayout
Klasse definiert zwei angefügte Eigenschaften namens LayoutBounds
und LayoutFlags
. Hier ist ein Checkerboardmuster, das mithilfe der proportionalen Positionierungs- und Größenanpassungsfeatures 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 etwas ähnliches könnten Sie die Weisheit der Verwendung von XAML in Frage stellen. Sicherlich schlägt die Wiederholung und Regelmäßigkeit des LayoutBounds
Rechtecks vor, dass es im Code besser realisiert werden könnte.
Das ist sicherlich ein berechtigtes Anliegen, und es besteht kein Problem beim Ausgleich der Verwendung von Code und Markup beim Definieren Ihrer Benutzeroberflächen. Es ist einfach, einige der visuellen Elemente in XAML zu definieren und dann den Konstruktor der CodeBehind-Datei zu verwenden, um einige weitere visuelle Elemente hinzuzufügen, die in Schleifen besser generiert werden können.
Content-Eigenschaften
In den vorherigen Beispielen werden die StackLayout
Objekte Grid
und AbsoluteLayout
die Eigenschaft des ContentPage
Layouts auf die Content
Eigenschaft festgelegt, und die untergeordneten Elemente dieser Layouts sind tatsächlich Elemente in der Children
Auflistung. Content
Diese und Children
Eigenschaften befinden sich in der XAML-Datei jedoch nirgendwo.
Sie können die Content
Eigenschaften Children
und Eigenschaften 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 ist: Warum sind diese Eigenschaftselemente in der XAML-Datei nicht erforderlich?
Für die Verwendung in XAML definierte Xamarin.Forms Elemente dürfen im Attribut der Klasse eine Eigenschaft gekennzeichnet ContentProperty
sein. Wenn Sie den Kurs in der ContentPage
Onlinedokumentation Xamarin.Forms nachschlagen, wird dieses Attribut angezeigt:
[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage
Dies bedeutet, dass die Content
Eigenschaftselementtags nicht erforderlich sind. Alle XML-Inhalte, die zwischen den Start- und Endtags ContentPage
angezeigt werden, werden der Content
Eigenschaft zugewiesen.
StackLayout
AbsoluteLayout
, Grid
, und RelativeLayout
alle abgeleitet von Layout<View>
, und wenn Sie in der Xamarin.Forms Dokumentation nachschlagenLayout<T>
, wird ein weiteres ContentProperty
Attribut angezeigt:
[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...
Dadurch kann der Inhalt des Layouts automatisch ohne explizite Children
Eigenschaftselementtags der Children
Auflistung hinzugefügt werden.
Andere Klassen weisen ContentProperty
auch Attributdefinitionen auf. Die Inhaltseigenschaft von Label
ist zum Beispiel Text
. Überprüfen Sie die API-Dokumentation für andere.
Plattformunterschiede mit OnPlatform
In Einzelseitenanwendungen ist es üblich, die Padding
Eigenschaft auf der Seite festzulegen, um zu vermeiden, dass die iOS-Statusleiste überschrieben wird. Im Code können Sie die Device.RuntimePlatform
Eigenschaft für diesen Zweck verwenden:
if (Device.RuntimePlatform == Device.iOS)
{
Padding = new Thickness(0, 20, 0, 0);
}
Sie können in XAML auch ähnliche Aktionen ausführen, indem Sie die OnPlatform
Klassen verwenden On
. Fügen Sie zuerst 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 hinzu OnPlatform
. OnPlatform
ist eine generische Klasse. In diesem Fall müssen Sie das generische Typargument angeben, Thickness
bei dem es sich um den Eigenschaftentyp Padding
handelt. Glücklicherweise gibt es ein XAML-Attribut speziell, um generische Argumente zu definieren, die aufgerufen werden 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 mit dem Namen Platforms
eines On
IList
Objekts. 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 für jede Eigenschaft die Platform
Eigenschaft und die Value
Eigenschaft auf Markup für die Thickness
Eigenschaft fest:
<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 Inhaltseigenschaft OnPlatform
lautet 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 des On
Typs IList<string>
ist, sodass Sie mehrere Plattformen einschließen können, wenn die Werte gleich 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 Padding
festgelegt 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 dafür 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 pro Plattform anzupassen. Sie bietet die gleiche Funktionalität wie die Klassen OnPlatform
und On
, jedoch mit einer prägnanteren Darstellung. Weitere Informationen finden Sie unter OnPlatform-Markuperweiterung.
Zusammenfassung
Mit Eigenschaftenelementen und angefügten Eigenschaften wurde ein Großteil der grundlegenden XAML-Syntax erstellt. Manchmal müssen Sie jedoch Eigenschaften auf Objekte indirekt festlegen, z. B. aus einem Ressourcenverzeichnis. Dieser Ansatz wird im nächsten Teil, Teil 3, behandelt. XAML-Markuperweiterungen.