Freigeben über


XAML-Markuperweiterungen

Beispiel durchsuchen.Durchsuchen Sie das Beispiel

.NET Multi-platform App UI (.NET MAUI) XAML Markup-Erweiterungen ermöglichen es, Eigenschaften auf Objekte oder Werte zu setzen, die indirekt von anderen Quellen referenziert werden. Die XAML-Markup-Erweiterungen sind besonders wichtig für die gemeinsame Nutzung von Objekten und den Verweis auf Konstanten, die in der gesamten Anwendung verwendet werden, aber ihren größten Nutzen haben sie bei Datenbindungen.

Normalerweise verwenden Sie XAML, um Eigenschaften eines Objekts auf explizite Werte zu setzen, z. B. eine Zeichenkette, eine Zahl, ein Aufzählungselement oder eine Zeichenkette, die hinter den Kulissen in einen Wert umgewandelt wird. Manchmal müssen Eigenschaften jedoch stattdessen auf Werte verweisen, die an anderer Stelle definiert sind, oder die zur Laufzeit eine kleine Bearbeitung durch den Code erfordern. Für diese Zwecke sind XAML-Markup-Erweiterungen verfügbar.

XAML-Markup-Erweiterungen heißen so, weil sie durch Code in Klassen unterstützt werden, die die IMarkupExtension implementieren. Es ist auch möglich, eigene Markup-Erweiterungen zu schreiben.

In vielen Fällen sind XAML-Markup-Erweiterungen in XAML-Dateien sofort erkennbar, da sie als durch geschweifte Klammern { und } abgegrenzte Attributwerte erscheinen, aber manchmal erscheinen Markup-Erweiterungen in Markup auch als herkömmliche Elemente.

Wichtig

Markup-Erweiterungen können Eigenschaften haben, aber sie werden nicht wie XML-Attribute festgelegt. In einer Markup-Erweiterung werden die Eigenschaftseinstellungen durch Kommas getrennt, und innerhalb der geschweiften Klammern erscheinen keine Anführungszeichen.

Gemeinsame Ressourcen

Einige XAML-Seiten enthalten mehrere Ansichten, deren Eigenschaften auf dieselben Werte festgelegt sind. Zum Beispiel sind viele der Eigenschaftseinstellungen für diese Button-Objekte gleich:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             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="Center"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="24" />
        <Button Text="Do that!"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="24" />
        <Button Text="Do the other thing!"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                BorderWidth="3"
                Rotation="-15"
                TextColor="Red"
                FontSize="24" />
    </StackLayout>
</ContentPage>

Wenn eine dieser Eigenschaften geändert werden muss, ist es besser, die Änderung nur einmal und nicht dreimal vornehmen zu müssen. Wäre es Code, würden Sie wahrscheinlich Konstanten und statische schreibgeschützte Objekte verwenden, um diese Werte konsistent und einfach änderbar zu halten.

In XAML besteht eine beliebte Lösung darin, solche Werte oder Objekte in einem Ressourcenwörterbuch zu speichern. Die Klasse VisualElement definiert eine Eigenschaft namens Resources vom Typ ResourceDictionary, die ein Wörterbuch mit Schlüsseln vom Typ string und Werten vom Typ object ist. Sie können Objekte in diesem Wörterbuch ablegen und sie dann in XAML aus dem Markup referenzieren.

Um ein Ressourcenwörterbuch auf einer Seite zu verwenden, fügen Sie oben auf der Seite ein Paar Resources-Eigenschafts-Element-Tags ein und fügen innerhalb dieser Tags Ressourcen hinzu. Dem Ressourcenwörterbuch können Objekte und Werte verschiedener Typen hinzugefügt werden. Diese Typen müssen instanziierbar sein. Sie dürfen z. B. keine abstrakten Klassen sein. Diese Typen müssen außerdem einen öffentlichen Konstruktor ohne Parameter haben. Jedes Objekt erfordert einen Wörterbuchschlüssel, der mit dem Attribut x:Key angegeben wird:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">
    <ContentPage.Resources>
        <LayoutOptions x:Key="horzOptions"
                       Alignment="Center" />
        <LayoutOptions x:Key="vertOptions"
                       Alignment="Center" />
    </ContentPage.Resources>
    ...
</ContentPage>

In diesem Beispiel handelt es sich bei den beiden Ressourcen um Werte des Strukturtyps LayoutOptions, die jeweils einen eindeutigen Schlüssel und eine oder zwei festgelegte Eigenschaften haben. In Code und Markup ist es weitaus gebräuchlicher, die statischen Felder von LayoutOptions zu verwenden, aber hier ist es bequemer, die Eigenschaften festzulegen.

Hinweis

Optionale ResourceDictionary-Tags können als untergeordnetes Element der Resources-Tags eingefügt werden.

Die Ressourcen können dann von den Button-Objekten konsumiert werden, indem Sie die XAML-Markup-Erweiterung StaticResource verwenden, um ihre HorizontalOptions- und VerticalOptions-Eigenschaften festzulegen:

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

Die Markup-Erweiterung StaticResource wird immer mit geschweiften Klammern abgegrenzt und enthält den Wörterbuchschlüssel. Der Name StaticResource unterscheidet sie von DynamicResource, die ebenfalls von .NET MAUI unterstützt wird. DynamicResource ist für Wörterbuchschlüssel, die mit Werten verknüpft sind, die sich zur Laufzeit ändern können, während StaticResource nur einmal auf Elemente aus dem Wörterbuch zugreift, wenn die Elemente auf der Seite aufgebaut werden. Immer wenn der XAML-Parser auf eine Markup-Erweiterung StaticResource stößt, sucht er in der visuellen Struktur nach oben und verwendet das erste ResourceDictionary, das diesen Schlüssel enthält.

Es ist notwendig, die Eigenschaften BorderWidth, Rotation und FontSize als Doubles im Wörterbuch zu speichern. XAML definiert praktischerweise Tags für gängige Datentypen wie x:Double und x:Int32:

<ContentPage.Resources>
        <LayoutOptions x:Key="horzOptions"
                       Alignment="Center" />
        <LayoutOptions x:Key="vertOptions"
                       Alignment="Center" />
        <x:Double x:Key="borderWidth">3</x:Double>
        <x:Double x:Key="rotationAngle">-15</x:Double>
        <x:Double x:Key="fontSize">24</x:Double>        
</ContentPage.Resources>

Diese drei zusätzlichen Ressourcen können auf die gleiche Weise referenziert werden wie die LayoutOptions-Werte:

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

Für Ressourcen vom Typ Color können Sie dieselben Zeichenkettendarstellungen verwenden, die Sie auch bei der direkten Zuweisung von Attributen dieses Typs verwenden. Bei der Erstellung der Ressource werden die in .NET MAUI enthaltenen Typkonverter aufgerufen. Außerdem besteht die Möglichkeit, die Klasse OnPlatform innerhalb des Ressourcenwörterbuchs zu verwenden, um verschiedene Werte für die Plattformen zu definieren. Das folgende Beispiel verwendet diese Klasse für die Einstellung verschiedener Textfarben:

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

Die OnPlatform-Ressource erhält ein x:Key-Attribut, weil sie ein Objekt im Wörterbuch ist, und ein x:TypeArguments-Attribut, weil es sich um eine generische Klasse handelt. Die Attribute iOS und Android werden bei der Initialisierung des Objekts in Color-Werte umgewandelt.

Das folgende Beispiel zeigt die drei Schaltflächen, die auf sechs gemeinsame Werte zugreifen:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SharedResourcesPage"
             Title="Shared Resources Page">
    <ContentPage.Resources>
        <LayoutOptions x:Key="horzOptions"
                       Alignment="Center" />
        <LayoutOptions x:Key="vertOptions"
                       Alignment="Center" />
        <x:Double x:Key="borderWidth">3</x:Double>
        <x:Double x:Key="rotationAngle">-15</x:Double>
        <x:Double x:Key="fontSize">24</x:Double>    
        <OnPlatform x:Key="textColor"
                    x:TypeArguments="Color">
            <On Platform="iOS" Value="Red" />
            <On Platform="Android" Value="Aqua" />
            <On Platform="WinUI" Value="#80FF80" />
        </OnPlatform>
    </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>

Der folgende Screenshot zeigt das einheitliche Styling:

Screenshot der gestalteten Steuerelemente.

Üblicherweise wird die Resources-Sammlung oben auf der Seite definiert, aber Sie können Resources-Sammlungen auch auf anderen Elementen auf der Seite haben. Das folgende Beispiel zeigt beispielsweise Ressourcen, die zu einem StackLayout hinzugefügt wurden:

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

Eine der häufigsten Arten von Objekten, die in Ressourcenwörterbüchern gespeichert werden, ist das .NET MAUI Style, das eine Sammlung von Eigenschaftseinstellungen definiert. Weitere Informationen über Stile finden Sie unter Anwendungen mit XAML gestalten.

Hinweis

Der Zweck eines Ressourcenwörterbuchs ist die gemeinsame Nutzung von Objekten. Daher ist es nicht sinnvoll, Steuerelemente wie Label oder Button in ein Ressourcenwörterbuch aufzunehmen. Visuelle Elemente können nicht gemeinsam genutzt werden, da die gleiche Instanz nicht zweimal auf einer Seite erscheinen kann.

x:Statische Markuperweiterung

Neben der Markup-Erweiterung StaticResource gibt es auch eine Markup-Erweiterung x:Static. StaticResource gibt ein Objekt aus einem Ressourcenwörterbuch zurück, während x:Static auf ein öffentliches statisches Feld, eine öffentliche statische Eigenschaft, ein öffentliches konstantes Feld oder ein Enumerationsmember zugreift.

Hinweis

Die Markup-Erweiterung StaticResource wird von XAML-Implementierungen unterstützt, die ein Ressourcen-Wörterbuch definieren, während x:Static ein fester Bestandteil von XAML ist, wie das Präfix x zeigt.

Das folgende Beispiel zeigt, wie x:Static explizit auf statische Felder und Enumerationsmember verweisen kann:

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

Die Hauptanwendung der Markup-Erweiterung x:Static ist der Verweis auf statische Felder oder Eigenschaften in Ihrem eigenen Code. Hier ist zum Beispiel eine AppConstants-Klasse, die einige statische Felder enthält, die Sie vielleicht auf mehreren Seiten in einer App verwenden möchten:

namespace XamlSamples
{
    static class AppConstants
    {
        public static readonly Color BackgroundColor = Colors.Aqua;
        public static readonly Color ForegroundColor = Colors.Brown;
    }
}

Um die statischen Felder dieser Klasse in einer XAML-Datei zu referenzieren, müssen Sie eine XML-Namespace-Deklaration verwenden, um anzugeben, wo sich diese Datei befindet. Jede weitere XML-Namespace-Deklaration definiert ein neues Präfix. Um auf Klassen zuzugreifen, die sich im Root-Namespace der Anwendung befinden, wie z. B. AppConstants, können Sie das Präfix local verwenden. Die Namespace-Deklaration muss den CLR-Namespace-Namen (Common Language Runtime) angeben, der auch als .NET-Namespace-Name bekannt ist. Dies ist der Name, der in einer C# namespace-Definition oder in einer using-Direktive erscheint:

xmlns:local="clr-namespace:XamlSamples"

Sie können auch XML-Namespace-Deklarationen für .NET-Namespaces definieren. Hier ist zum Beispiel ein sys-Präfix für den Standard-.NET-Namespace System, der sich in der netstandard-Assembly befindet. Da es sich um eine andere Assembly handelt, müssen Sie auch den Namen der Assembly angeben, in diesem Fall netstandard:

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

Hinweis

Auf das Schlüsselwort clr-namespace folgt ein Doppelpunkt und dann der Name des .NET-Namespace, gefolgt von einem Semikolon, dem Schlüsselwort assembly, einem Gleichheitszeichen und dem Namen der Assembly.

Die statischen Felder können dann nach der Deklaration des XML-Namespace konsumiert werden:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             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="5,25,5,0">
    <StackLayout>
       <Label Text="Hello, XAML!"
              TextColor="{x:Static local:AppConstants.BackgroundColor}"
              BackgroundColor="{x:Static local:AppConstants.ForegroundColor}"
              FontAttributes="Bold"
              FontSize="30"
              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>

In diesem Beispiel werden die BoxView-Dimensionen auf Math.PI und Math.E festgelegt, aber um den Faktor 100 skaliert:

Screenshot der Steuerelemente, die die x:Static-Markuperweiterung verwenden.

Markup-Erweiterungen

Mehrere Markup-Erweiterungen sind XAML inhärent und werden in .NET MAUI XAML unterstützt. Einige davon werden nicht sehr häufig verwendet, sind aber für die folgenden Fälle unerlässlich:

  • Wenn eine Eigenschaft standardmäßig einen Nicht-null-Wert hat, Sie sie aber auf null festlegen möchten, setzen Sie sie auf die Markup-Erweiterung {x:Null}.
  • Wenn eine Eigenschaft den Typ Type hat, können Sie sie mit der Markup-Erweiterung {x:Type someClass} einem Type-Objekt zuweisen.
  • Sie können Arrays in XAML mit der Markup-Erweiterung x:Array definieren. Diese Markup-Erweiterung hat ein erforderliches Attribut namens Type, das den Typ der Elemente im Array angibt.

Weitere Informationen über XAML-Markup-Erweiterungen finden Sie unter XAML-Markup-Erweiterungen verwenden.

Nächste Schritte

.NET MAUI-Datenbindungen ermöglichen die Verknüpfung von Eigenschaften zweier Objekte, sodass eine Änderung in dem einen eine Änderung in dem anderen Objekt bewirkt.