Condividi tramite


Introduzione a XAML

Browse sample.Sfogliare l'esempio. Esplorare l'esempio

In un'app .NET MAUI, interfaccia utente multipiattaforma, XAML viene utilizzato principalmente per definire il contenuto visivo di una pagina e lavora in tandem con un file code-behind C#. Il file code-behind fornisce supporto al codice per il markup. Insieme, questi due file contribuiscono a una nuova definizione di classe che include viste figlio e inizializzazione delle proprietà. All'interno del file XAML, alle classi e alle proprietà viene fatto riferimento con elementi e attributi XML e vengono stabiliti collegamenti tra markup e codice.

Anatomia di un file XAML

Una nuova app .NET MAUI contiene tre file XAML e i relativi file code-behind associati:

Screenshot della struttura di una nuova app .NET MAUI.

La prima associazione di file è App.xaml, un file XAML e App.xaml.cs, un file code-behind C# associato al file XAML. Sia App.xaml che App.xaml.cs contribuiscono a una classe denominata che deriva da . La seconda associazione di file è AppShell.xaml e AppShell.xaml.cs, che contribuiscono a una classe denominata AppShell che deriva da Shell. La maggior parte delle altre classi con file XAML contribuisce a una classe che deriva da ContentPagee definisce l'interfaccia utente di una pagina. Questo vale per i file MainPage.xaml e MainPage.xaml.cs .

Il file MainPage.xaml ha la seguente struttura:

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

Le due dichiarazioni dello spazio dei nomi XML (xmlns) fanno riferimento agli URI in microsoft.com. Tuttavia, non sono presenti contenuti in questi URI e funzionano fondamentalmente come identificatori di versione.

Nota

A partire da .NET 11, queste due dichiarazioni di spazio dei nomi standard sono implicite e possono essere omesse dai file XAML. Il compilatore li inserisce automaticamente. Per altre informazioni, vedere Dichiarazioni dello spazio dei nomi implicite.

La prima dichiarazione dello spazio dei nomi XML indica che i tag definiti all'interno del file XAML senza prefisso fanno riferimento alle classi in .NET MAUI, ad esempio ContentPage. La seconda dichiarazione dello spazio dei nomi definisce un prefisso di x. Viene usato per diversi elementi e attributi intrinseci di XAML e supportati da altre implementazioni di XAML. Tuttavia, questi elementi e attributi sono leggermente diversi a seconda dell'anno incorporato nell'URI. .NET MAUI supporta la specifica XAML 2009.

Alla fine del primo tag, il x prefisso viene usato per un attributo denominato Class. Poiché l'uso di questo x prefisso è praticamente universale per lo spazio dei nomi XAML, gli attributi XAML come Class sono quasi sempre riferiti a x:Class. L'attributo x:Class specifica un nome di classe .NET completo: la classe MainPage nello spazio dei nomi MyMauiApp. Questo significa che questo file XAML definisce una nuova classe denominata MainPage nel namespace MyMauiApp, che eredita da ContentPage (il tag in cui appare l'attributo x:Class).

L'attributo x:Class può essere visualizzato solo nell'elemento radice di un file XAML per definire una classe C# derivata. Questa è l'unica nuova classe definita nel file XAML. Tutto il resto visualizzato in un file XAML viene invece semplicemente creato come istanze da classi esistenti e inizializzato.

Il file MainPage.xaml.cs è simile al seguente:

namespace MyMauiApp;

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

La MainPage classe deriva da ContentPage e costituisce una definizione di classe parziale.

In fase di esecuzione, il codice nella classe MauiProgram esegue il bootstrap dell'app ed esegue il costruttore della classe App, che crea un'istanza di AppShell. La classe AppShell istanzia la prima pagina dell'app da visualizzare, che è MainPage. Il costruttore chiama , che inizializza tutti gli oggetti definiti nel file XAML, li connette tutti insieme nelle relazioni padre-figlio, associa i gestori eventi definiti nel codice agli eventi impostati nel file XAML e imposta l'albero risultante degli oggetti come contenuto della pagina.

Nota

La classe AppShell usa .NET MAUI Shell per impostare la prima pagina dell'app da visualizzare. Tuttavia, Shell esula dall'ambito di questa introduzione a XAML. Per altre informazioni, vedere .NET MAUI Shell.

Impostare il contenuto della pagina

Un ContentPage oggetto deve contenere un singolo elemento figlio, che può essere una visualizzazione o un layout con visualizzazioni figlio. Il figlio dell'elemento ContentPage viene impostato automaticamente come valore della proprietà ContentPage.Content.

Nell'esempio seguente viene illustrato un oggetto ContentPage contenente un oggetto 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>

Generazione di codice XAML

Importante

Questa funzione richiede l'attivazione da parte dell'utente. Per usarlo, impostare l'gonfiatore XAML nel file di progetto in base alle istruzioni riportate di seguito. Facci sapere la vostra esperienza con questo (sia buona che cattiva) nel repository .NET MAUI.

A partire da .NET 10, hai l'opzione di generare C# invece di IL (linguaggio intermedio) usando la generazione del codice sorgente con Roslyn. Ciò migliora la possibilità di eseguire il debug di XAML creando i file di origine e impostando direttamente i punti di interruzione, velocizza le prestazioni di debug del rendering della pagina e migliora la coerenza del comportamento dell'app tra le modalità di compilazione di debug e rilascio.

Per abilitare la generazione dell'origine XAML per l'intero progetto, aggiungerla al file di progetto:

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

Per un controllo più dettagliato sui file XAML che usano la generazione di origine XAML, puoi configurare singoli file o modelli:

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

Puoi includere o escludere determinati file XAML configurando il modello nell'attributo Inflator . Se vuoi rifiutare esplicitamente determinati file o criteri, annullare l'impostazione (o impostare su "") Inflator per garantire le impostazioni predefinite corrette (il valore predefinito è l'inflazione di runtime in Debug, XamlC in versione)

Fare riferimento alla documentazione di configurazione del generatore di origine per l'uso di opzioni come EmitCompilerGeneratedFiles.

Spazio dei nomi XML globale (anteprima)

In .NET 10 è possibile facoltativamente utilizzare uno spazio dei nomi XAML globale per ridurre le dichiarazioni standard xmlns: nelle varie pagine.

Importante

Questa funzionalità è in anteprima. Per provarlo, abilitare le funzionalità di anteprima nel file di progetto. Il comportamento e le impostazioni predefinite possono cambiare.

Per attivare, aggiungere un GlobalXmlns.cs con attributi a livello di XmlnsDefinition assembly che mappano lo spazio dei nomi globale ai tuoi spazi dei nomi CLR, e fare riferimento al http://schemas.microsoft.com/dotnet/maui/global spazio dei nomi alla radice del tuo 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>

Opzionalmente, impostare i prefissi predefiniti:

using XmlnsPrefixAttribute = Microsoft.Maui.Controls.XmlnsPrefixAttribute;

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

Dichiarazioni dello spazio dei nomi implicite

A partire da .NET 11, le dichiarazioni dello spazio dei nomi XAML standard sono implicite per impostazione predefinita. Non è necessario alcun consenso esplicito. Il compilatore inserisce xmlns="http://schemas.microsoft.com/dotnet/2021/maui" automaticamente e xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml", in modo che i file XAML possano ometterli:

Before (.NET 10 e versioni precedenti)

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

Gli spazi dei nomi personalizzati richiedono comunque dichiarazioni esplicite di xmlns:. Per altre informazioni, vedere Dichiarazioni dello spazio dei nomi implicite.

Per abilitare l'esperienza più semplificata (spazi dei nomi predefiniti impliciti), aggiungere:

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

Ora il progetto includerà implicitamente questi 2 spazi dei nomi a cui siete abituati a vedere in ogni file XAML dal momento in cui .NET MAUI è stato rilasciato.

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

Nota

Poiché x: viene usato dall'gonfiatore XAML, devi comunque usare tale prefisso. Con questa modifica da sola, il codice XAML per una visualizzazione diventa molto più stretto.

Prima

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

Dopo

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

Nell'esempio precedente la relazione tra classi, proprietà e XML deve essere evidente. Nel file XAML, una classe .NET MAUI (ad esempio ContentPage o Label) appare come un elemento XML. Le proprietà di quella classe, incluse Title su ContentPage, e sette proprietà di Label di solito vengono visualizzate come attributi XML.

Esistono molti collegamenti per impostare i valori di queste proprietà. Alcune proprietà sono tipi di dati di base. Ad esempio, le proprietà Title e Text sono di tipo string, e Rotation è di tipo double. La proprietà HorizontalTextAlignment è di tipo TextAlignment, che è un'enumerazione. Per una proprietà di qualsiasi tipo di enumerazione, è sufficiente specificare un nome membro.

Per le proprietà di tipi più complessi, tuttavia, i convertitori vengono usati per l'analisi del codice XAML. Si tratta di classi in .NET MAUI che derivano da TypeConverter. Per l'esempio precedente, diversi convertitori di .NET MAUI vengono applicati automaticamente per convertire i valori stringa nel tipo corretto:

  • per la proprietà . Questo convertitore converte i nomi dei campi statici pubblici della LayoutOptions struttura in valori di tipo LayoutOptions.
  • per la proprietà . Questo convertitore converte i nomi dei campi statici pubblici della classe Colors, oppure dei valori RGB esadecimali, con o senza un canale alfa.

Quando si esegue un'app .NET MAUI, in genere viene visualizzato il MainPage. Per visualizzare una pagina diversa, è possibile impostarla come nuova pagina di avvio nel file AppShell.xaml oppure navigare verso la nuova pagina da .

Per implementare la navigazione, nel costruttore MainPage.xaml.cs è possibile creare un semplice Button e utilizzare il gestore eventi per passare a 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;
}

Quando si compila e si distribuisce la nuova versione di questa app, viene visualizzato un pulsante sullo schermo. Premendo si accede a HelloXamlPage:

Screenshot del testo dell'etichetta ruotato.Screenshot del testo dell'etichetta ruotato.

È possibile tornare a MainPage usando la barra di spostamento visualizzata in ogni piattaforma.

Nota

Un'alternativa a questo modello di navigazione consiste nell'usare .NET MAUI Shell. Per ulteriori informazioni, vedere la panoramica di .NET MAUI Shell.

Interazioni con XAML e codice

L'elemento figlio della maggior parte dei derivati è un layout, come una ContentPage, uno StackLayout, o un Grid, e il layout può contenere più elementi figlio. In XAML queste relazioni padre-figlio vengono stabilite con la normale gerarchia XML:

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

Questo file XAML è sintatticamente completo e produce l'interfaccia utente seguente:

Screenshot of multiple controls on a page.Screenshot di più controlli in una pagina.

Tuttavia, mentre è possibile interagire con Slider e Button, l'interfaccia utente non viene aggiornata. Deve Slider fare in modo che l'oggetto Label visualizzi il valore corrente e deve eseguire un'operazione Button .

La visualizzazione di un Slider valore tramite un Label oggetto può essere ottenuta interamente in XAML con un data binding. Tuttavia, è utile vedere prima la soluzione di codice. Anche in questo caso, la gestione del Button clic richiede sicuramente il codice. Proposto miglioramento: Ciò significa che il file del code-behind per XamlPlusCodePage deve contenere i gestori per l'evento ValueChanged del Slider e l'evento Clicked del 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");
        }
    }
}
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");
        }
    }
}

Nel file XAML i Slider tag e Button devono includere attributi per gli ValueChanged eventi e Clicked che fanno riferimento a questi gestori:

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

Si noti che l'assegnazione di un gestore a un evento ha la stessa sintassi dell'assegnazione di un valore a una proprietà. Inoltre, affinché il ValueChanged gestore eventi dell'oggetto Slider usi Label per visualizzare il valore corrente, il gestore deve fare riferimento a tale oggetto dal codice. Pertanto, il Label richiede un nome, specificato con l'attributo x:Name. Il x prefisso dell'attributo x:Name indica che questo attributo è intrinseco a XAML. Il nome assegnato all'attributo x:Name ha le stesse regole dei nomi delle variabili C#. Ad esempio, deve iniziare con una lettera o un carattere di sottolineatura e non contenere spazi incorporati.

Il gestore eventi ValueChanged può ora impostare il Label per visualizzare il nuovo valore di Slider, disponibile dagli argomenti dell'evento:

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

In alternativa, il gestore può ottenere l'oggetto Slider che genera questo evento dall'argomento sender e ottenere la proprietà Value da tale oggetto.

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

Il risultato è che qualsiasi manipolazione dell'oggetto Slider determina la visualizzazione del relativo valore in Label:

Screenshot of multiple controls on a page, with Slider value displayed.Screenshot di più controlli in una pagina con il valore Slider visualizzato.

Nell'esempio precedente il Button simula una risposta a un evento Clicked visualizzando un avviso con il Text del pulsante. Pertanto, il gestore eventi può eseguire il cast dell'argomento sender a un Button, quindi accedere alle sue proprietà:

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

Il OnButtonClicked metodo viene definito come async poiché il DisplayAlert metodo è asincrono e deve essere preceduto dall'operatore await, che restituisce allorquando il metodo termina. Poiché questo metodo ottiene l'oggetto che genera l'evento dall'argomento sender, lo stesso gestore può essere utilizzato per più pulsanti.

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

Il OnButtonClicked metodo viene definito come async poiché il DisplayAlert metodo è asincrono e deve essere preceduto dall'operatore await, che restituisce allorquando il metodo termina. Poiché questo metodo ottiene l'oggetto che genera l'evento dall'argomento sender, lo stesso gestore può essere utilizzato per più pulsanti.

Passaggi successivi

XAML è progettato principalmente per la creazione di istanze e l'inizializzazione di oggetti. Spesso, tuttavia, le proprietà devono essere impostate su oggetti complessi che non possono essere facilmente rappresentati come stringhe XML e talvolta le proprietà definite da una classe devono essere impostate su una classe figlio. Queste due esigenze richiedono le funzionalità di sintassi XAML essenziali degli elementi delle proprietà e delle proprietà associate.