Partager via


Bien démarrer avec XAML

Parcourez l’exemple. Parcourir l'exemple

Dans une application .NET Multi-platform App UI (.NET MAUI), XAML est principalement utilisé pour définir le contenu visuel d’une page et fonctionne avec un fichier code-behind C#. Le fichier code-behind fournit la prise en charge du code pour le balisage. Ensemble, ces deux fichiers contribuent à une nouvelle définition de classe qui inclut des vues enfants et l’initialisation des propriétés. Dans le fichier XAML, les classes et les propriétés sont référencées avec des éléments et des attributs XML, et les liens entre le balisage et le code sont établis.

Anatomie d’un fichier XAML

Une nouvelle application .NET MAUI contient trois fichiers XAML et les fichiers code-behind associés :

Capture d’écran de la structure d’une nouvelle application .NET MAUI.

La première paire de fichiers est App.xaml, un fichier XAML, et App.xaml.cs, un fichier code-behind C# associé au fichier XAML. App.xaml et App.xaml.cs contribuent à une classe nommée App qui dérive de Application. La deuxième paire de fichiers est AppShell.xaml et AppShell.xaml.cs, qui contribuent à une classe nommée AppShell dérivant de Shell. La plupart des autres classes des fichiers XAML contribuent à une classe qui dérive de ContentPage, et définissent l’interface utilisateur d’une page. Cela s’applique aux fichiers MainPage.xaml et MainPage.xaml.cs.

Le fichier MainPage.xaml a la structure suivante :

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

Les deux déclarations d’espace de noms XML (xmlns) font référence à des URI sur microsoft.com. Toutefois, ces URI n’ont pas de contenu et fonctionnent essentiellement en tant qu’identificateurs de version.

La première déclaration d’espace de noms XML signifie que les balises définies sans préfixe dans le fichier XAML font référence à des classes dans .NET MAUI, par exemple ContentPage. La seconde déclaration d’espace de noms utilise le préfixe x. Il est utilisé pour plusieurs éléments et attributs intrinsèques au code XAML lui-même et pris en charge par d’autres implémentations de XAML. Toutefois, ces éléments et attributs sont légèrement différents selon l’année incorporée dans l’URI. .NET MAUI prend en charge la spécification XAML 2009.

À la fin de la première balise, le préfixe x est utilisé pour un attribut nommé Class. Étant donné que l’utilisation de ce préfixe x est pratiquement universelle pour l’espace de noms XAML, les attributs XAML tels que Class sont presque toujours appelés x:Class. L’attribut x:Class spécifie un nom de classe .NET complet : la classe MainPage dans l’espace de noms MyMauiApp. Cela signifie que ce fichier XAML définit une nouvelle classe nommée MainPage dans l’espace de noms MyMauiApp qui dérive de ContentPage (balise dans laquelle l’attribut x:Class apparaît).

L’attribut x:Class ne peut apparaître que dans l’élément racine d’un fichier XAML pour définir une classe C# dérivée. Il s’agit de la seule nouvelle classe définie dans le fichier XAML. Tous les autres éléments apparaissant dans un fichier XAML sont simplement instanciés à partir de classes existantes et initialisés.

Le fichier MainPage.xaml.cs ressemble à ceci :

namespace MyMauiApp;

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

La classe MainPage dérive de ContentPage, et elle est une définition de classe partielle.

Lorsque Visual Studio crée le projet, un générateur de code source génère un nouveau code source C# qui contient la définition de la méthode InitializeComponent appelée depuis le constructeur MainPage et l’ajoute à l’objet de compilation.

Au moment du runtime, le code de la classe MauiProgram démarre l’application et exécute le constructeur de classe App, qui instancie AppShell. La classe AppShell instancie la première page de l’application à afficher, c’est-à-dire MainPage. Le constructeur MainPage appelle InitializeComponent, qui initialise tous les objets définis dans le XAML, les connecte tous ensemble dans les relations parent-enfant, attache des gestionnaires d’événements définis dans le code aux événements définis dans le fichier XAML et définit l’arborescence résultante des objets comme contenu de la page.

Remarque

La classe AppShell utilise l’interpréteur de commandes .NET MAUI pour définir la première page de l’application à afficher. Toutefois, l’interpréteur de commandes n’entre pas dans le cadre de cette introduction au code XAML. Pour plus d’informations, consultez Interpréteur de commandes .NET MAUI.

Définir le contenu de la page

Un ContentPage doit contenir un enfant unique, qui peut être une vue ou une disposition avec des vues enfants. L’enfant de la ContentPage est automatiquement défini comme valeur de la propriété ContentPage.Content.

L’exemple suivant montre une ContentPage contenant un Label :

<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>

Dans l’exemple ci-dessus, la relation entre les classes, les propriétés et XML doit être claire. Une classe .NET MAUI (telle que ContentPage ou Label) apparaît dans le fichier XAML en tant qu’élément XML. Les propriétés de cette classe, y compris Title sur ContentPage et sept propriétés de Label, apparaissent généralement en tant qu’attributs XML.

De nombreux raccourcis existent pour définir les valeurs de ces propriétés. Certaines propriétés sont des types de données de base. Par exemple, les propriétés Title et Text sont de type string et Rotation est de type double. La propriété HorizontalTextAlignment est de type TextAlignment, qui est une énumération. Pour une propriété de type énumération, il vous suffit de fournir un nom de membre.

Toutefois, avec les propriétés de types plus complexes, des convertisseurs sont utilisés pour analyser le code XAML. Il s’agit de classes dans .NET MAUI qui dérivent de TypeConverter. Pour l’exemple ci-dessus, plusieurs convertisseurs .NET MAUI sont automatiquement appliqués pour convertir des valeurs de chaîne vers leur type correct :

  • LayoutOptionsConverter pour la propriété VerticalOptions. Ce convertisseur convertit les noms des champs statiques publics de la structure LayoutOptions en valeurs de type LayoutOptions.
  • ColorTypeConverter pour la propriété TextColor. Ce convertisseur convertit les noms des champs statiques publics des valeurs RVB hexadécimales ou de la classe Colors, avec ou sans canal alpha.

Lorsque vous exécutez une application .NET MAUI, c’est la MainPage qui s’affiche généralement. Pour afficher une autre page, vous pouvez définir cette page en tant que nouvelle page de démarrage dans le fichier AppShell.xaml ou accéder à la nouvelle page à partir de MainPage.

Pour implémenter la navigation, dans le constructeur MainPage.xaml.cs, vous pouvez créer un Button simple et utiliser le gestionnaire d’événements pour accéder à HelloXamlPage :

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;
}

Lorsque vous compilez et déployez la nouvelle version de cette application, un bouton s’affiche à l’écran. La sélection de ce bouton permet d’accéder à HelloXamlPage :

Capture d’écran du texte de libellé avec rotation.

Vous pouvez revenir à MainPage à l’aide de la barre de navigation qui s’affiche sur chaque plateforme.

Remarque

Une alternative à ce modèle de navigation consiste à utiliser l’interpréteur de commandes .NET MAUI. Pour plus d’informations, consultez Vue d’ensemble de l’interpréteur de commandes .NET MAUI.

Interactions entre XAML et le code

L’enfant de la plupart des dérivés de ContentPage est une disposition, telle qu’une StackLayout ou une Grid, et la disposition peut contenir plusieurs enfants. Dans le XAML, ces relations parent-enfant sont établies avec une hiérarchie XML normale :

<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>

La syntaxe de ce fichier XAML est complète et produit l’interface utilisateur suivante :

Capture d’écran de plusieurs contrôles sur une page.

Toutefois, même si vous pouvez interagir avec le Slider et le Button, l’interface utilisateur n’est pas mise à jour. Le Slider doit permettre au Label d’afficher la valeur actuelle et le Button doit avoir une fonction.

L’affichage d’une valeur Slider à l’aide d’un Label peut se faire entièrement dans le XAML avec une liaison de données. Toutefois, il est utile de voir d’abord la solution de code. La gestion du clic sur le Button nécessite de toute façon du code. Cela signifie que le fichier code-behind pour XamlPlusCodePage doit contenir des gestionnaires pour l’événement ValueChanged du Slider et l’événement Clicked du Button :

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");
        }
    }
}

De retour dans le fichier XAML, les balises Slider et Button doivent inclure des attributs pour les événements ValueChanged et Clicked qui font référence à ces gestionnaires :

<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>

Notez que l’affectation d’un gestionnaire à un événement a la même syntaxe que l’affectation d’une valeur à une propriété. De plus, pour que le gestionnaire d’événements ValueChanged du Slider utilise le Label pour afficher la valeur actuelle, le gestionnaire doit référencer cet objet à partir du code. Par conséquent, le Label doit avoir un nom, spécifié dans l’attribut x:Name. Le préfixe x de l’attribut x:Name indique que cet attribut est intrinsèque au code XAML. Le nom que vous donnez à l’attribut x:Name répond aux mêmes règles que les noms de variables C#. Par exemple, il doit commencer par une lettre ou un trait de soulignement et ne contenir aucun espace incorporé.

Le gestionnaire d’événements ValueChanged peut maintenant définir le Label pour afficher la nouvelle valeur Slider, disponible à partir des arguments d’événement :

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

Le gestionnaire peut également obtenir l’objet Slider qui génère cet événement à partir de l’argument sender et obtenir la propriété Value à partir de là :

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

Le résultat est que toute manipulation du Slider entraîne l’affichage de sa valeur dans le Label :

Capture d’écran de plusieurs contrôles sur une page, avec la valeur Slider affichée.

Dans l’exemple ci-dessus, le Button simule une réponse à un événement Clicked en affichant une alerte avec le Text du bouton. Par conséquent, le gestionnaire d’événements peut convertir l’argument sender en un Button, puis accéder à ses propriétés :

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

La méthode OnButtonClicked est définie en tant que async, car la méthode DisplayAlert est asynchrone et doit être précédée de l’opérateur await, qui revient une fois la méthode terminée. Étant donné qu’avec cette méthode, le Button déclenche l’événement à partir de l’argument sender, le même gestionnaire peut être utilisé pour plusieurs boutons.

Étapes suivantes

XAML est principalement conçu pour instancier et initialiser des objets. Cependant, les propriétés doivent souvent être définies sur des objets complexes qui ne peuvent pas facilement être représentés en tant que chaînes XML, et parfois les propriétés définies par une classe doivent être définies sur une classe enfant. Dans ces deux cas, les fonctionnalités de syntaxe XAML essentielle sont nécessaires pour les éléments de propriété et les propriétés jointes.