Freigeben über


Erste Schritte mit XAML

Beispiel durchsuchen. Durchsuchen Sie das Beispiel

In einer .NET Multiplattform-App-UI (.NET MAUI)-App wird XAML hauptsächlich verwendet, um den visuellen Inhalt einer Seite zu definieren und mit einer C#-Code-Behind-Datei zusammenzuarbeiten. Die CodeBehind-Datei bietet Code-Unterstützung für das Markup. Zusammen ergeben diese beiden Dateien eine neue Klassendefinition, die untergeordnete Elemente und die Initialisierung von Eigenschaften enthält. Innerhalb der XAML-Datei werden Klassen und Eigenschaften mit XML-Elementen und -Attributen referenziert, und es werden Verknüpfungen zwischen dem Markup und dem Code hergestellt.

Aufbau einer XAML-Datei

Eine neue .NET MAUI-App enthält drei XAML-Dateien und die zugehörigen Code-Behind-Dateien.

Screenshot der Struktur einer neuen .NET MAUI app.

Das erste Dateipaar ist App.xaml, eine XAML-Datei, und App.xaml.cs, eine C#- CodeBehind-Datei, die mit der XAML-Datei verknüpft ist. Sowohl App.xaml als auch App.xaml.cs tragen zu einer Klasse namens App bei, die sich von Application ableitet. Das zweite Dateipaar ist AppShell.xaml und AppShell.xaml.cs, die zu einer Klasse namens AppShell beitragen, die von Shell abgeleitet ist. Die meisten anderen Klassen mit XAML-Dateien tragen zu einer Klasse bei, die von ContentPage abgeleitet ist, und definieren die Benutzeroberfläche einer Seite. Dies gilt für die Dateien MainPage.xaml und MainPage.xaml.cs.

Die Datei MainPage.xaml hat die folgende Struktur:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyMauiApp.MainPage">
    ...
</ContentPage>

Die beiden XML-Namespace-Deklarationen (xmlns) verweisen auf URIs auf microsoft.com. Diese URIs haben jedoch keinen Inhalt und dienen im Wesentlichen als Versionsbezeichner.

Hinweis

Ab .NET 11 sind diese beiden Standardnamespacedeklarationen implizit und können aus Ihren XAML-Dateien weggelassen werden. Der Compiler fügt sie automatisch ein. Weitere Informationen finden Sie unter Implizite Namespacedeklarationen.

Die erste XML-Namespacedeklaration bedeutet, dass in der XAML-Datei definierte Tags ohne Präfix auf Klassen in .NET MAUI verweisen, z. B. ContentPage. Die zweite Namespace-Deklaration definiert ein Präfix von x. Dies wird für mehrere Elemente und Attribute verwendet, die XAML-spezifisch sind und die von anderen Implementierungen von XAML unterstützt werden. Diese Elemente und Attribute unterscheiden sich jedoch geringfügig, je nachdem, welches Jahr in den URI eingebettet ist. .NET MAUI unterstützt die XAML-Spezifikation 2009.

Am Ende des ersten Tags wird das Präfix x für ein Attribut namens Class verwendet. Da die Verwendung dieses Präfixes x für den XAML-Namespace praktisch universell ist, werden XAML-Attribute wie Class fast immer als x:Class bezeichnet. Das attribut x:Class gibt einen vollqualifizierten .NET Klassennamen an: die klasse MainPage im namespace MyMauiApp. Das bedeutet, dass diese XAML-Datei eine neue Klasse mit dem Namen MainPage im Namespace MyMauiApp definiert, die von ContentPage (dem Tag, in dem das Attribut x:Class erscheint) abgeleitet ist.

Das x:Class-Attribut kann nur im Root-Element einer XAML-Datei erscheinen, um eine abgeleitete C#-Klasse zu definieren. Dies ist die einzige neue Klasse, die in der XAML-Datei definiert ist. Alles andere, was in einer XAML-Datei erscheint, wird stattdessen einfach aus vorhandenen Klassen erstellt und initialisiert.

Die Datei MainPage.xaml.cs sieht ähnlich aus wie diese:

namespace MyMauiApp;

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }
}

Die Klasse MainPage leitet sich von ContentPage ab und ist eine partielle Klassendefinition.

Zur Laufzeit startet der Code in der Klasse MauiProgram die Anwendung und führt den App-Klassenkonstruktor aus, der AppShell instanziiert. Die Klasse AppShell erstellt die erste Seite der anzuzeigenden App, die MainPage ist. Der MainPage-Konstruktor ruft InitializeComponent auf, der alle in der XAML-Datei definierten Objekte initialisiert, sie alle in übergeordneten und untergeordneten Beziehungen miteinander verbindet, im Code definierte Ereignishandler an die in der XAML-Datei festgelegten Ereignisse anhängt und der daraus resultierenden Baumstruktur von Objekten als Inhalt der Seite festlegt.

Hinweis

Die klasse AppShell verwendet .NET MAUI Shell, um die erste Seite der anzuzeigenden App festzulegen. Shell würde jedoch den Rahmen dieser Einführung in XAML sprengen. Weitere Informationen finden Sie unter .NET MAUI Shell.

Seiteninhalt festlegen

Eine ContentPage sollte ein einzelnes untergeordnetes Element enthalten, das eine Ansicht oder ein Layout mit untergeordneten Ansichten sein kann. Das untergeordnete Element der ContentPage wird automatisch als Wert der Eigenschaft ContentPage.Content festgelegt.

Das folgende Beispiel zeigt eine ContentPage, die ein Label enthält:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage"
             Title="Hello XAML Page">
    <Label Text="Hello, XAML!"
           VerticalOptions="Center"
           HorizontalTextAlignment="Center"
           Rotation="-15"
           FontSize="18"
           FontAttributes="Bold"
           TextColor="Blue" />
</ContentPage>

XAML-Quellgenerierung

Von Bedeutung

Diese Funktion erfordert eine aktive Anmeldung. Um ihn zu verwenden, legen Sie den XAML-Inflator in Ihrer Projektdatei gemäß den nachstehenden Anweisungen fest. Bitte teilen Sie uns Ihre Erfahrung mit diesem (gut oder schlecht) im .NET MAUI Repository mit.

Sie haben die Möglichkeit, ab .NET 10 mithilfe der Roslyn-Quellgenerierung C#-Code aus XAML anstelle von IL (Zwischensprache) zu generieren. Dadurch wird die Möglichkeit verbessert, XAML zu debuggen, indem die Quelldateien ausgegeben und Haltepunkte direkt in ihnen festgelegt werden. Die Debugging-Leistung des Seitenrenderings wird beschleunigt und die Konsistenz des App-Verhaltens zwischen Debug- und Release-Build-Modi verbessert.

Um die XAML-Quellgenerierung für das gesamte Projekt zu aktivieren, fügen Sie dies der Projektdatei hinzu:

<PropertyGroup>
   <MauiXamlInflator>SourceGen</MauiXamlInflator>
</PropertyGroup>

Für eine genauere Kontrolle darüber, welche XAML-Dateien die XAML-Quellgenerierung verwenden, können Sie einzelne Dateien oder Muster konfigurieren:

<ItemGroup>
    <MauiXaml Update="**/*.xaml" Inflator="SourceGen" />
</ItemGroup>

Sie können bestimmte XAML-Dateien einschließen oder ausschließen, indem Sie das Muster im Inflator Attribut konfigurieren. Wenn Sie bestimmte Dateien oder Muster ausschließen möchten, setzen Sie Inflator auf "" um sicherzustellen, dass die Standardwerte richtig gesetzt sind (der Standardwert ist die Laufzeitinflation bei Debug, XamlC im Release).

Referenzieren Sie die Konfigurationsdokumentation des Quellgenerators für die Verwendung von Optionen wie EmitCompilerGeneratedFiles.

Globaler XML-Namespace (Vorschau)

In .NET 10 können Sie optional einen globalen XAML-Namespace verwenden, um "Boilerplate"-Deklarationen auf Ihren Seiten zu reduzieren.

Von Bedeutung

Dieses Feature befindet sich in der Vorschau. Aktivieren Sie die Vorschaufeatures in Ihrer Projektdatei, um es zu testen. Verhalten und Standardwerte können sich ändern.

Um sich zu beteiligen, fügen Sie ein GlobalXmlns.cs mit Attributen auf Assembly-Ebene XmlnsDefinition hinzu, die den globalen Namespace mit Ihren CLR-Namespaces verknüpfen, und verweisen Sie auf den http://schemas.microsoft.com/dotnet/maui/global Namespace im Wurzelelement Ihres XAML.

// GlobalXmlns.cs
using Microsoft.Maui.Controls;

[assembly: XmlnsDefinition("http://schemas.microsoft.com/dotnet/maui/global", "MyApp.Views")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/dotnet/maui/global", "MyApp.Controls")]
<!-- Root element uses the global namespace -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/maui/global"
                         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                         x:Class="MyApp.MainPage">
        <TagView x:DataType="Tag" />
        <!-- No xmlns prefixes for TagView/Tag when globally mapped -->
        <!-- Add explicit xmlns prefixes only when disambiguation is needed -->

</ContentPage>

Legen Sie optional Standardpräfixe fest:

using XmlnsPrefixAttribute = Microsoft.Maui.Controls.XmlnsPrefixAttribute;

[assembly: XmlnsPrefix("MyApp.Controls", "controls")]

Implizite Namespacedeklarationen

Ab .NET 11 sind die standardmäßigen XAML-Namespacedeklarationen implizit – es ist keine Zustimmung erforderlich. Der Compiler fügt automatisch xmlns="http://schemas.microsoft.com/dotnet/2021/maui" und xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" ein, sodass Ihre XAML-Dateien diese weglassen können.

Vor (.NET 10 und früher)

<ContentPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="MyApp.Pages.MyContentPage">
</ContentPage>

After (.NET 11)

<ContentPage x:Class="MyApp.Pages.MyContentPage">
</ContentPage>

Benutzerdefinierte Namespaces erfordern weiterhin explizite xmlns: Deklarationen. Weitere Informationen finden Sie unter Implizite Namespacedeklarationen.

Um die optimiertste Oberfläche zu aktivieren (implizite Standardnamespaces), fügen Sie Folgendes hinzu:

<PropertyGroup>
    <DefineConstants>$(DefineConstants);MauiAllowImplicitXmlnsDeclaration</DefineConstants>
    <EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup>

Jetzt enthält Ihr Projekt implizit diese 2 Namespaces, die Sie gewohnt sind, in jeder XAML-Datei zu sehen, seit .NET MAUI zum ersten Mal ausgeliefert wurde.

xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

Hinweis

Da x: vom XAML-Inflator verwendet wird, müssen Sie das Präfix weiterhin nutzen. Mit dieser Änderung wird Ihr XAML für eine Ansicht viel kompakter.

Vorher

<ContentPage 
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="MyApp.Pages.MyContentPage">
</ContentPage>

Nach

<ContentPage x:Class="MyApp.Pages.MyContentPage">
</ContentPage>

Aus dem obigen Beispiel sollte die Beziehung zwischen Klassen, Eigenschaften und XML ersichtlich sein. Eine .NET MAUI Klasse (z. B. ContentPage oder Label) wird in der XAML-Datei als XML-Element angezeigt. Eigenschaften dieser Klasse – einschließlich Title auf ContentPage und sieben Eigenschaften von Label – erscheinen normalerweise als XML-Attribute.

Es gibt viele Tastenkombinationen, um die Werte dieser Eigenschaften festzulegen. Einige Eigenschaften sind grundlegende Datentypen. Zum Beispiel sind die Eigenschaften Title und Text vom Typ string, und Rotation ist vom Typ double. Die Eigenschaft HorizontalTextAlignment ist vom Typ TextAlignment, bei dem es sich um eine Enumeration handelt. Für eine Eigenschaft eines Enumerationstyps ist nur die Angabe eines Mitgliedsnamens erforderlich.

Für Eigenschaften komplexerer Typen werden jedoch Konverter zur Analyse von XAML verwendet. Dies sind Klassen in .NET MAUI, die von TypeConverter abgeleitet sind. Im obigen Beispiel werden mehrere .NET MAUI-Konverter automatisch angewendet, um Zeichenfolgenwerte in ihren richtigen Typ zu konvertieren:

  • LayoutOptionsConverter für die Eigenschaft VerticalOptions. Dieser Konverter wandelt die Namen von öffentlichen statischen Feldern der LayoutOptions-Struktur in Werte des Typs LayoutOptions um.
  • ColorTypeConverter für die Eigenschaft TextColor. Dieser Konverter wandelt die Namen von öffentlichen statischen Feldern der Colors-Klasse in hexadezimale RGB-Werte mit oder ohne Alphakanal um.

Wenn Sie eine .NET MAUI-App ausführen, wird normalerweise die MainPage angezeigt. Wenn Sie eine andere Seite sehen möchten, können Sie diese entweder in der Datei AppShell.xaml als neue Startseite festlegen oder von MainPage aus zur neuen Seite navigieren.

Um die Navigation zu implementieren, können Sie im Konstruktor MainPage.xaml.cs eine einfache Button erstellen und den Ereignishandler verwenden, um zu HelloXamlPage zu navigieren:

public MainPage()
{
    InitializeComponent();

    Button button = new Button
    {
        Text = "Navigate!",
        HorizontalOptions = LayoutOptions.Center,
        VerticalOptions = LayoutOptions.Center
    };

    button.Clicked += async (sender, args) =>
    {
        await Navigation.PushAsync(new HelloXamlPage());
    };

    Content = button;
}

Wenn Sie die neue Version dieser App kompilieren und bereitstellen, erscheint eine Schaltfläche auf dem Bildschirm. Durch Drücken dieser Schaltfläche gelangen Sie zu HelloXamlPage:

Screenshot des gedrehten Beschriftungstexts.

Über die Navigationsleiste, die auf jeder Plattform erscheint, gelangen Sie zurück zur MainPage.

Hinweis

Eine Alternative zu diesem Navigationsmodell ist die Verwendung .NET MAUI Shell. Weitere Informationen finden Sie unter .NET MAUI Shell overview.

Interaktionen zwischen XAML und Code

Das Kind der meisten ContentPage-Derivate ist ein Layout, wie etwa ein StackLayout oder ein Grid, und das Layout kann mehrere Kinder enthalten. In XAML werden die Beziehungen zwischen über- und untergeordneten Elementen über die normale XML-Hierarchie hergestellt:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <StackLayout>
        <Slider VerticalOptions="Center" />
        <Label Text="A simple Label"
               FontSize="18"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <Button Text="Click Me!"
                HorizontalOptions="Center"
                VerticalOptions="Center" />
    </StackLayout>
</ContentPage>

Diese XAML-Datei ist syntaktisch vollständig und erzeugt die folgende Benutzeroberfläche:

Screenshot mehrerer Steuerelemente auf einer Seite.

Während Sie jedoch mit Slider und Button interagieren können, wird die Benutzeroberfläche nicht aktualisiert. Der Slider sollte bewirken, dass der Label den aktuellen Wert anzeigt, und der Button sollte eine Aktion ausführen.

Die Anzeige eines Slider-Wertes mit einem Label kann vollständig in XAML mit einer Datenbindung erreicht werden. Es ist jedoch hilfreich, sich zuerst die Lösung des Codes anzusehen. Der Klick auf Button erfordert jedoch definitiv Code. Das bedeutet, dass die Code-Behind-Datei für XamlPlusCodePage Handler für das Ereignis ValueChanged von Slider und das Ereignis Clicked von Button enthalten muss:

namespace XamlSamples
{
    public partial class XamlPlusCodePage
    {
        public XamlPlusCodePage()
        {
            InitializeComponent();
        }

        void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        {
            valueLabel.Text = args.NewValue.ToString("F3");
        }

        async void OnButtonClicked(object sender, EventArgs args)
        {
            Button button = (Button)sender;
            await DisplayAlert("Clicked!", "The button labeled '" + button.Text + "' has been clicked", "OK");
        }
    }
}
namespace XamlSamples
{
    public partial class XamlPlusCodePage
    {
        public XamlPlusCodePage()
        {
            InitializeComponent();
        }

        void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        {
            valueLabel.Text = args.NewValue.ToString("F3");
        }

        async void OnButtonClicked(object sender, EventArgs args)
        {
            Button button = (Button)sender;
            await DisplayAlertAsync("Clicked!", "The button labeled '" + button.Text + "' has been clicked", "OK");
        }
    }
}

In der XAML-Datei müssen die Tags Slider und Button Attribute für die Ereignisse ValueChanged und Clicked enthalten, die auf diese Handler verweisen:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <StackLayout>
        <Slider VerticalOptions="Center"
                ValueChanged="OnSliderValueChanged" />
        <Label x:Name="valueLabel"
               Text="A simple Label"
               FontSize="18"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <Button Text="Click Me!"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Clicked="OnButtonClicked" />
    </StackLayout>
</ContentPage>

Beachten Sie, dass die Zuweisung eines Handlers zu einem Ereignis dieselbe Syntax hat wie die Zuweisung eines Wertes zu einer Eigenschaft. Damit der Ereignishandler ValueChanged des Slider das Label zur Anzeige des aktuellen Werts verwenden kann, muss der Handler das Objekt im Code referenzieren. Dazu benötigt das Label einen Namen, der mit dem Attribut x:Name angegeben wird. Das Präfix x des Attributs x:Name zeigt an, dass es sich bei diesem Attribut um ein XAML-eigenes Attribut handelt. Für den Namen, den Sie dem Attribut x:Name zuweisen, gelten dieselben Regeln wie für C#-Variablennamen. Es muss beispielsweise mit einem Buchstaben oder einem Unterstrich beginnen und darf keine Leerzeichen enthalten.

Der Ereignishandler ValueChanged kann nun das Label so einstellen, dass es den neuen Slider-Wert anzeigt, der in den Ereignisargumenten verfügbar ist:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = args.NewValue.ToString("F3");
}

Alternativ kann der Handler das Slider-Objekt, das dieses Ereignis erzeugt, aus dem sender-Argument abrufen und die Eigenschaft Value von diesem abrufen:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = ((Slider)sender).Value.ToString("F3");
}

Das Ergebnis ist, dass jede Manipulation des Slider dazu führt, dass sein Wert in Label angezeigt wird:

Screenshot mehrerer Steuerelemente auf einer Seite, wobei der Schiebereglerwert angezeigt wird.

Im obigen Beispiel simuliert die Button eine Reaktion auf ein Clicked-Ereignis, indem sie eine Meldung mit dem Text der Schaltfläche anzeigt. Daher kann der Ereignisbehandler das sender-Argument in eine Button umwandeln und dann auf dessen Eigenschaften zugreifen:

async void OnButtonClicked(object sender, EventArgs args)
{
    Button button = (Button)sender;
    await DisplayAlert("Clicked!", "The button labeled '" + button.Text + "' has been clicked", "OK");
}

Die OnButtonClicked-Methode ist als async definiert, weil die DisplayAlert-Methode asynchron ist und mit dem Operator await gestartet werden sollte, der zurückgibt, wann die Methode beendet ist. Da diese Methode die Button, die das Ereignis auslöst, aus dem sender-Argument bezieht, kann derselbe Handler für mehrere Schaltflächen verwendet werden.

async void OnButtonClicked(object sender, EventArgs args)
{
    Button button = (Button)sender;
    await DisplayAlertAsync("Clicked!", "The button labeled '" + button.Text + "' has been clicked", "OK");
}

Die OnButtonClicked-Methode ist als async definiert, weil die DisplayAlertAsync-Methode asynchron ist und mit dem Operator await gestartet werden sollte, der zurückgibt, wann die Methode beendet ist. Da diese Methode die Button, die das Ereignis auslöst, aus dem sender-Argument bezieht, kann derselbe Handler für mehrere Schaltflächen verwendet werden.

Nächste Schritte

XAML ist hauptsächlich für die Erstellung 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 wesentlichen XAML-Syntaxfeatures von Eigenschaftselementen und angefügten Eigenschaften.