Teil 3. XAML-Markuperweiterungen

Beispiel herunterladen Das Beispiel herunterladen

XAML-Markuperweiterungen stellen ein wichtiges Feature in XAML dar, mit dem Eigenschaften auf Objekte oder Werte festgelegt werden können, auf die indirekt aus anderen Quellen verwiesen wird. XAML-Markuperweiterungen sind besonders wichtig für die Freigabe von Objekten und verweisen auf Konstanten, die in einer Anwendung verwendet werden, aber sie finden ihr größtes Hilfsprogramm in Datenbindungen.

XAML-Markuperweiterungen

Im Allgemeinen verwenden Sie XAML, um Eigenschaften eines Objekts auf explizite Werte festzulegen, z. B. eine Zeichenfolge, eine Zahl, ein Enumerationselement oder eine Zeichenfolge, die im Hintergrund in einen Wert konvertiert wird.

Manchmal müssen Eigenschaften jedoch stattdessen auf werte verweisen, die an anderer Stelle definiert sind, oder die zur Laufzeit ein wenig Verarbeitung durch Code erfordern. Für diese Zwecke sind XAML-Markuperweiterungen verfügbar.

Diese XAML-Markuperweiterungen sind keine Erweiterungen von XML. XAML ist vollständig legales XML. Sie werden als "Erweiterungen" bezeichnet, da sie durch Code in Klassen unterstützt werden, die implementieren IMarkupExtension. Sie können ihre eigenen benutzerdefinierten Markuperweiterungen schreiben.

In vielen Fällen sind XAML-Markuperweiterungen in XAML-Dateien sofort erkennbar, da sie als Attributeinstellungen angezeigt werden, die durch geschweifte Klammern getrennt sind: { und }, aber manchmal werden Markuperweiterungen im Markup als herkömmliche Elemente angezeigt.

Gemeinsam genutzte Ressourcen

Einige XAML-Seiten enthalten mehrere Ansichten, deren Eigenschaften auf die gleichen Werte festgelegt sind. Beispielsweise sind viele der Eigenschafteneinstellungen für diese Button Objekte identisch:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <StackLayout>
        <Button Text="Do this!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="24" />

        <Button Text="Do that!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="24" />

        <Button Text="Do the other thing!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="24" />

    </StackLayout>
</ContentPage>

Wenn eine dieser Eigenschaften geändert werden muss, ziehen Sie es möglicherweise vor, die Änderung nur einmal statt dreimal vorzunehmen. Wenn dies Code wäre, würden Sie wahrscheinlich Konstanten und statische schreibgeschützte Objekte verwenden, um diese Werte konsistent und einfach zu ändern.

In XAML besteht eine beliebte Lösung darin, solche Werte oder Objekte in einem Ressourcenwörterbuch zu speichern. Die VisualElement -Klasse definiert eine Eigenschaft mit dem Namen Resources vom Typ ResourceDictionary, bei der es sich um ein Wörterbuch mit Schlüsseln vom Typ string und Werten vom Typ handelt object. Sie können Objekte in dieses Wörterbuch einfügen und dann über das Markup darauf verweisen, alles in XAML.

Um ein Ressourcenwörterbuch auf einer Seite zu verwenden, schließen Sie ein Paar von Eigenschaftselementtags Resources ein. Es ist am bequemsten, diese oben auf der Seite zu platzieren:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>

    </ContentPage.Resources>
    ...
</ContentPage>

Es ist auch erforderlich, Tags explizit einzuschließen ResourceDictionary :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>
        <ResourceDictionary>

        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

Jetzt können Dem Ressourcenwörterbuch Objekte und Werte verschiedener Typen hinzugefügt werden. Diese Typen müssen instanziierbar sein. Sie können z. B. keine abstrakten Klassen sein. Diese Typen müssen auch über einen öffentlichen parameterlosen Konstruktor verfügen. Jedes Element erfordert einen mit dem x:Key -Attribut angegebenen Wörterbuchschlüssel. Beispiel:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>
        <ResourceDictionary>
            <LayoutOptions x:Key="horzOptions"
                           Alignment="Center" />

            <LayoutOptions x:Key="vertOptions"
                           Alignment="Center"
                           Expands="True" />
        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

Bei diesen beiden Elementen handelt es sich um Werte des Strukturtyps LayoutOptions, für die jeweils ein eindeutiger Schlüssel und eine oder zwei Eigenschaften festgelegt sind. In Code und Markup ist es viel häufiger, die statischen Felder von LayoutOptionszu verwenden, aber hier ist es bequemer, die Eigenschaften festzulegen.

Nun müssen die HorizontalOptions Eigenschaften und VerticalOptions dieser Schaltflächen auf diese Ressourcen festgelegt werden, und dies geschieht mit der StaticResource XAML-Markuperweiterung:

<Button Text="Do this!"
        HorizontalOptions="{StaticResource horzOptions}"
        VerticalOptions="{StaticResource vertOptions}"
        BorderWidth="3"
        Rotation="-15"
        TextColor="Red"
        FontSize="24" />

Die StaticResource Markuperweiterung ist immer durch geschweifte Klammern getrennt und enthält den Wörterbuchschlüssel.

Der Name StaticResource unterscheidet sie von DynamicResource, die Xamarin.Forms ebenfalls unterstützt. DynamicResource ist für Wörterbuchschlüssel, die Werten zugeordnet sind, die sich während der Laufzeit ändern können, während StaticResource elemente aus dem Wörterbuch nur einmal zugegriffen werden, wenn die Elemente auf der Seite erstellt werden.

Für die BorderWidth -Eigenschaft ist es erforderlich, ein Double im Wörterbuch zu speichern. XAML definiert Tags bequem für gängige Datentypen wie x:Double und x:Int32:

<ContentPage.Resources>
    <ResourceDictionary>
        <LayoutOptions x:Key="horzOptions"
                       Alignment="Center" />

        <LayoutOptions x:Key="vertOptions"
                       Alignment="Center"
                       Expands="True" />

        <x:Double x:Key="borderWidth">
            3
        </x:Double>
    </ResourceDictionary>
</ContentPage.Resources>

Sie müssen es nicht in drei Zeilen setzen. Dieser Wörterbucheintrag für diesen Drehwinkel nimmt nur eine Zeile ein:

<ContentPage.Resources>
    <ResourceDictionary>
        <LayoutOptions x:Key="horzOptions"
                       Alignment="Center" />

        <LayoutOptions x:Key="vertOptions"
                       Alignment="Center"
                       Expands="True" />

         <x:Double x:Key="borderWidth">
            3
         </x:Double>

        <x:Double x:Key="rotationAngle">-15</x:Double>
    </ResourceDictionary>
</ContentPage.Resources>

Auf diese beiden Ressourcen kann auf die gleiche Weise wie auf die LayoutOptions Werte verwiesen werden:

<Button Text="Do this!"
        HorizontalOptions="{StaticResource horzOptions}"
        VerticalOptions="{StaticResource vertOptions}"
        BorderWidth="{StaticResource borderWidth}"
        Rotation="{StaticResource rotationAngle}"
        TextColor="Red"
        FontSize="24" />

Für Ressourcen vom Typ Colorkönnen Sie dieselben Zeichenfolgendarstellungen verwenden, die Sie beim direkten Zuweisen von Attributen dieser Typen verwenden. Die Typkonverter werden aufgerufen, wenn die Ressource erstellt wird. Dies ist eine Ressource vom Typ Color:

<Color x:Key="textColor">Red</Color>

Häufig legen Programme eine FontSize Eigenschaft auf einen Member der NamedSize Enumeration fest, z Large. B. . Die FontSizeConverter -Klasse arbeitet im Hintergrund, um sie mithilfe der Device.GetNamedSized -Methode in einen plattformabhängigen Wert zu konvertieren. Beim Definieren einer Schriftgradressource ist es jedoch sinnvoller, einen numerischen Wert zu verwenden, der hier als Typ x:Double dargestellt wird:

<x:Double x:Key="fontSize">24</x:Double>

Jetzt werden alle Eigenschaften außer Text durch Ressourceneinstellungen definiert:

<Button Text="Do this!"
        HorizontalOptions="{StaticResource horzOptions}"
        VerticalOptions="{StaticResource vertOptions}"
        BorderWidth="{StaticResource borderWidth}"
        Rotation="{StaticResource rotationAngle}"
        TextColor="{StaticResource textColor}"
        FontSize="{StaticResource fontSize}" />

Es ist auch möglich, OnPlatform innerhalb des Ressourcenwörterbuchs verschiedene Werte für die Plattformen zu definieren. Hier erfahren Sie, wie ein OnPlatform Objekt Teil des Ressourcenwörterbuchs für verschiedene Textfarben sein kann:

<OnPlatform x:Key="textColor"
            x:TypeArguments="Color">
    <On Platform="iOS" Value="Red" />
    <On Platform="Android" Value="Aqua" />
    <On Platform="UWP" Value="#80FF80" />
</OnPlatform>

Beachten Sie, dass OnPlatform sowohl ein x:Key Attribut abruft, da es sich um ein Objekt im Wörterbuch handelt, als auch ein x:TypeArguments Attribut, da es sich um eine generische Klasse handelt. Die iOSAttribute , Androidund UWP werden in Werte konvertiert Color , wenn das Objekt initialisiert wird.

Hier ist die endgültige vollständige XAML-Datei mit drei Schaltflächen, die auf sechs freigegebene Werte zugreifen:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">

    <ContentPage.Resources>
        <ResourceDictionary>
            <LayoutOptions x:Key="horzOptions"
                           Alignment="Center" />

            <LayoutOptions x:Key="vertOptions"
                           Alignment="Center"
                           Expands="True" />

            <x:Double x:Key="borderWidth">3</x:Double>

            <x:Double x:Key="rotationAngle">-15</x:Double>

            <OnPlatform x:Key="textColor"
                        x:TypeArguments="Color">
                <On Platform="iOS" Value="Red" />
                <On Platform="Android" Value="Aqua" />
                <On Platform="UWP" Value="#80FF80" />
            </OnPlatform>

            <x:Double x:Key="fontSize">24</x:Double>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>
        <Button Text="Do this!"
                HorizontalOptions="{StaticResource horzOptions}"
                VerticalOptions="{StaticResource vertOptions}"
                BorderWidth="{StaticResource borderWidth}"
                Rotation="{StaticResource rotationAngle}"
                TextColor="{StaticResource textColor}"
                FontSize="{StaticResource fontSize}" />

        <Button Text="Do that!"
                HorizontalOptions="{StaticResource horzOptions}"
                VerticalOptions="{StaticResource vertOptions}"
                BorderWidth="{StaticResource borderWidth}"
                Rotation="{StaticResource rotationAngle}"
                TextColor="{StaticResource textColor}"
                FontSize="{StaticResource fontSize}" />

        <Button Text="Do the other thing!"
                HorizontalOptions="{StaticResource horzOptions}"
                VerticalOptions="{StaticResource vertOptions}"
                BorderWidth="{StaticResource borderWidth}"
                Rotation="{StaticResource rotationAngle}"
                TextColor="{StaticResource textColor}"
                FontSize="{StaticResource fontSize}" />

    </StackLayout>
</ContentPage>

Die Screenshots überprüfen die konsistente Formatierung und die plattformabhängige Formatierung:

Formatierte Steuerelemente

Obwohl es am häufigsten ist, die Resources Auflistung oben auf der Seite zu definieren, denken Sie daran, dass die Resources Eigenschaft durch VisualElementdefiniert ist und Sie Sammlungen für andere Elemente auf der Seite haben Resources können. Versuchen Sie z. B., eine zu der StackLayout in diesem Beispiel hinzuzufügen:

<StackLayout>
    <StackLayout.Resources>
        <ResourceDictionary>
            <Color x:Key="textColor">Blue</Color>
        </ResourceDictionary>
    </StackLayout.Resources>
    ...
</StackLayout>

Sie werden feststellen, dass die Textfarbe der Schaltflächen jetzt blau ist. Wenn der XAML-Parser auf eine StaticResource Markuperweiterung trifft, durchsucht er grundsätzlich die visuelle Struktur und verwendet die erste ResourceDictionary , die diesen Schlüssel enthält.

Einer der am häufigsten in Ressourcenwörterbüchern gespeicherten Objekttypen ist der , der Xamarin.FormsStyleeine Auflistung von Eigenschafteneinstellungen definiert. Stile werden im Artikel Formatvorlagen erläutert.

Manchmal fragen sich Entwickler, die noch nicht mit XAML vertraut sind, ob sie ein visuelles Element wie Label oder Button in einem ResourceDictionaryeinfügen können. Obwohl es sicher möglich ist, macht es nicht viel Sinn. Der Zweck von ResourceDictionary besteht darin, Objekte gemeinsam zu nutzen. Ein visuelles Element kann nicht freigegeben werden. Derselbe instance kann nicht zweimal auf einer einzelnen Seite angezeigt werden.

Die x:Static-Markuperweiterung

Trotz der Ähnlichkeiten ihrer Namen und x:StaticStaticResource sind sehr unterschiedlich. StaticResource gibt ein Objekt aus einem Ressourcenwörterbuch zurück, während x:Static auf eines der folgenden Zugänge zugegriffen wird:

  • ein öffentliches statisches Feld
  • eine öffentliche statische Eigenschaft
  • ein öffentliches Konstantenfeld
  • ein Enumerationsmember.

Die StaticResource Markuperweiterung wird von XAML-Implementierungen unterstützt, die ein Ressourcenwörterbuch definieren, während x:Static ein systeminterner Bestandteil von XAML ist, wie das x Präfix zeigt.

Hier sind einige Beispiele, die veranschaulichen, wie x:Static explizit auf statische Felder und Enumerationsmember verwiesen werden kann:

<Label Text="Hello, XAML!"
       VerticalOptions="{x:Static LayoutOptions.Start}"
       HorizontalTextAlignment="{x:Static TextAlignment.Center}"
       TextColor="{x:Static Color.Aqua}" />

Bisher ist das nicht sehr beeindruckend. x:Static Die Markuperweiterung kann jedoch auch aus Ihrem eigenen Code auf statische Felder oder Eigenschaften verweisen. Hier sehen Sie beispielsweise eine AppConstants Klasse, die einige statische Felder enthält, die Sie möglicherweise auf mehreren Seiten in einer Anwendung verwenden möchten:

using System;
using Xamarin.Forms;

namespace XamlSamples
{
    static class AppConstants
    {
        public static readonly Thickness PagePadding;

        public static readonly Font TitleFont;

        public static readonly Color BackgroundColor = Color.Aqua;

        public static readonly Color ForegroundColor = Color.Brown;

        static AppConstants()
        {
            switch (Device.RuntimePlatform)
            {
                case Device.iOS:
                    PagePadding = new Thickness(5, 20, 5, 0);
                    TitleFont = Font.SystemFontOfSize(35, FontAttributes.Bold);
                    break;

                case Device.Android:
                    PagePadding = new Thickness(5, 0, 5, 0);
                    TitleFont = Font.SystemFontOfSize(40, FontAttributes.Bold);
                    break;

                case Device.UWP:
                    PagePadding = new Thickness(5, 0, 5, 0);
                    TitleFont = Font.SystemFontOfSize(50, FontAttributes.Bold);
                    break;
            }
        }
    }
}

Um auf die statischen Felder dieser Klasse in der XAML-Datei zu verweisen, müssen Sie in der XAML-Datei angeben, wo sich diese Datei befindet. Dazu verwenden Sie eine XML-Namespacedeklaration.

Beachten Sie, dass die XAML-Dateien, die als Teil der XAML-Standardvorlage Xamarin.Forms erstellt wurden, zwei XML-Namespacedeklarationen enthalten: eine für den Zugriff auf Xamarin.Forms Klassen und eine andere für den Verweis auf Tags und Attribute, die in XAML integriert sind:

xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

Sie benötigen zusätzliche XML-Namespacedeklarationen, um auf andere Klassen zuzugreifen. Jede zusätzliche XML-Namespacedeklaration definiert ein neues Präfix. Um auf Klassen zuzugreifen, die lokal für die freigegebene .NET Standard-Bibliothek der Anwendung vorhanden sind, z AppConstants. B. , verwenden XAML-Programmierer häufig das Präfix local. Die Namespacedeklaration muss den CLR-Namespacenamen (Common Language Runtime) angeben, der auch als .NET-Namespacename bezeichnet wird. Dabei handelt es sich um den Namen, der in einer C#- namespace Definition oder in einer using Direktive angezeigt wird:

xmlns:local="clr-namespace:XamlSamples"

Sie können auch XML-Namespacedeklarationen für .NET-Namespaces in jeder Assembly definieren, auf die die .NET Standard-Bibliothek verweist. Hier sehen Sie beispielsweise ein sys Präfix für den .NET-Standardnamespace System , der sich in der netstandard-Assembly befindet. Da es sich um eine weitere Assembly handelt, müssen Sie auch den Assemblynamen angeben, in diesem Fall netstandard:

xmlns:sys="clr-namespace:System;assembly=netstandard"

Beachten Sie, dass auf den Schlüsselwort (keyword) clr-namespace ein Doppelpunkt und dann der Name des .NET-Namespace gefolgt ist, gefolgt von einem Semikolon, dem Schlüsselwort (keyword) assembly, einem Gleichheitszeichen und dem Assemblynamen.

Ja, es folgt clr-namespace ein Doppelpunkt, aber das Gleichheitszeichen folgt assembly. Die Syntax wurde bewusst auf diese Weise definiert: Die meisten XML-Namespacedeklarationen verweisen auf einen URI, der einen URI-Schemanamen wie beginnt, dem httpimmer ein Doppelpunkt folgt. Der clr-namespace Teil dieser Zeichenfolge soll diese Konvention imitieren.

Beide Namespacedeklarationen sind im StaticConstantsPage-Beispiel enthalten. Beachten Sie, dass die BoxView Dimensionen auf Math.PI und Math.Efestgelegt sind, aber um den Faktor 100 skaliert werden:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             xmlns:sys="clr-namespace:System;assembly=netstandard"
             x:Class="XamlSamples.StaticConstantsPage"
             Title="Static Constants Page"
             Padding="{x:Static local:AppConstants.PagePadding}">

    <StackLayout>
       <Label Text="Hello, XAML!"
              TextColor="{x:Static local:AppConstants.BackgroundColor}"
              BackgroundColor="{x:Static local:AppConstants.ForegroundColor}"
              Font="{x:Static local:AppConstants.TitleFont}"
              HorizontalOptions="Center" />

      <BoxView WidthRequest="{x:Static sys:Math.PI}"
               HeightRequest="{x:Static sys:Math.E}"
               Color="{x:Static local:AppConstants.ForegroundColor}"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand"
               Scale="100" />
    </StackLayout>
</ContentPage>

Die Größe des resultierenden Ergebnisses BoxView im Verhältnis zum Bildschirm ist plattformabhängig:

Steuerelemente mit x:Static Markup Extension

Andere Standardmarkuperweiterungen

Mehrere Markuperweiterungen sind systemintern für XAML und werden in Xamarin.Forms XAML-Dateien unterstützt. Einige davon werden nicht sehr häufig verwendet, sind aber unerlässlich, wenn Sie sie benötigen:

  • Wenn eine Eigenschaft standardmäßig über einen Nicht-Wert null verfügt, sie aber auf nullfestlegen möchten, legen Sie sie auf die {x:Null} Markuperweiterung fest.
  • Wenn eine Eigenschaft vom Typ Typeist, können Sie sie einem Type Objekt mithilfe der Markuperweiterung {x:Type someClass}zuweisen.
  • Sie können Arrays in XAML mithilfe der x:Array Markuperweiterung definieren. Diese Markuperweiterung verfügt über ein erforderliches Attribut namens Type , das den Typ der Elemente im Array angibt.
  • Die Binding Markuperweiterung wird in Teil 4 erläutert. Grundlagen der Datenbindung.
  • Die RelativeSource Markuperweiterung wird unter Relative Bindungen erläutert.

Die ConstraintExpression-Markuperweiterung

Markuperweiterungen können Eigenschaften aufweisen, sind aber nicht wie XML-Attribute festgelegt. In einer Markuperweiterung werden Eigenschafteneinstellungen durch Kommas getrennt, und in den geschweiften Klammern werden keine Anführungszeichen angezeigt.

Dies kann mit der Xamarin.Forms Markuperweiterung mit dem Namen ConstraintExpressionveranschaulicht werden, die mit der RelativeLayout -Klasse verwendet wird. Sie können den Speicherort oder die Größe einer untergeordneten Ansicht als Konstante oder relativ zu einer übergeordneten oder einer anderen benannten Ansicht angeben. Mit der Syntax von ConstraintExpression können Sie die Position oder Größe einer Ansicht festlegen, indem Sie eine Factor mal eine Eigenschaft einer anderen Ansicht plus ein - Constantverwenden. Alles, was komplexer ist, erfordert Code.

Hier ist ein Beispiel angegeben:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.RelativeLayoutPage"
             Title="RelativeLayout Page">

    <RelativeLayout>

        <!-- Upper left -->
        <BoxView Color="Red"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}" />
        <!-- Upper right -->
        <BoxView Color="Green"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=1,
                                            Constant=-40}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}" />
        <!-- Lower left -->
        <BoxView Color="Blue"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=Constant,
                                            Constant=0}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=1,
                                            Constant=-40}" />
        <!-- Lower right -->
        <BoxView Color="Yellow"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=1,
                                            Constant=-40}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=1,
                                            Constant=-40}" />

        <!-- Centered and 1/3 width and height of parent -->
        <BoxView x:Name="oneThird"
                 Color="Red"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=0.33}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=0.33}"
                 RelativeLayout.WidthConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Width,
                                            Factor=0.33}"
                 RelativeLayout.HeightConstraint=
                     "{ConstraintExpression Type=RelativeToParent,
                                            Property=Height,
                                            Factor=0.33}"  />

        <!-- 1/3 width and height of previous -->
        <BoxView Color="Blue"
                 RelativeLayout.XConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=X}"
                 RelativeLayout.YConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=Y}"
                 RelativeLayout.WidthConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=Width,
                                            Factor=0.33}"
                 RelativeLayout.HeightConstraint=
                     "{ConstraintExpression Type=RelativeToView,
                                            ElementName=oneThird,
                                            Property=Height,
                                            Factor=0.33}"  />
    </RelativeLayout>
</ContentPage>

Die vielleicht wichtigste Lektion, die Sie aus diesem Beispiel ziehen sollten, ist die Syntax der Markuperweiterung: In den geschweiften Klammern einer Markuperweiterung dürfen keine Anführungszeichen angezeigt werden. Beim Eingeben der Markuperweiterung in eine XAML-Datei ist es natürlich, die Werte der Eigenschaften in Anführungszeichen einzuschließen. Widerstehen Sie der Versuchung!

Im Folgenden wird das Programm ausgeführt:

Relatives Layout mithilfe von Einschränkungen

Zusammenfassung

Die hier gezeigten XAML-Markuperweiterungen bieten wichtige Unterstützung für XAML-Dateien. Die vielleicht wertvollste XAML-Markuperweiterung ist Bindingjedoch , die im nächsten Teil dieser Reihe, Teil 4, behandelt wird . Grundlagen der Datenbindung.