Teil 2. Grundlegende XAML-Syntax

Beispiel herunterladen Das Beispiel herunterladen

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 TextColorausprobieren 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, VerticalOptionsund FontAttributesFontSize 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:

Rasterlayout

Allein anhand der Syntax zu urteilen, scheinen diese Grid.RowAttribute , Grid.Column, Grid.RowSpanund Grid.ColumnSpan statische Felder oder Eigenschaften von Gridzu sein, Grid aber interessanterweise definiert nichts mit dem Namen Row, Column, , RowSpanoder ColumnSpan.

Grid Definiert stattdessen vier bindungsfähige Eigenschaften mit den Namen RowProperty, ColumnProperty, RowSpanPropertyund 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 Gridfestgelegt.

Wenn Sie diese angefügten Eigenschaften im Code verwenden möchten, stellt die Grid -Klasse statische Methoden mit dem Namen SetRow, GetColumnusw. 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 AbsoluteLayoutrealisiert 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:

Absolutes Layout

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 StackLayoutObjekte , Gridund AbsoluteLayout auf die Content -Eigenschaft von ContentPagefestgelegt, 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, AbsoluteLayoutund 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 Paddingsind, 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.