Condividi tramite


Utilizzare estensioni di markup XAML

Esplora l'esempio. Esplora l'esempio

Le estensioni di markup XAML dell'interfaccia utente di app multipiattaforma .NET (.NET MAUI) consentono di migliorare la potenza e la flessibilità di XAML consentendo l'impostazione degli attributi degli elementi da un'ampia gamma di origini.

Ad esempio, si imposta in genere la proprietà Color di BoxView in questo modo:

<BoxView Color="Blue" />

Tuttavia, è preferibile impostare l'attributo Color da un valore archiviato in un dizionario risorse o dal valore di una proprietà statica di una classe creata o da una proprietà di tipo Color di un altro elemento nella pagina o costruito da valori di tonalità, saturazione e luminosità separati. Tutte queste opzioni sono possibili usando le estensioni di markup XAML.

Un'estensione di markup è un modo diverso per esprimere un attributo di un elemento. Le estensioni di markup XAML .NET MAUI sono in genere identificabili da un valore di attributo racchiuso tra parentesi graffe:

<BoxView Color="{StaticResource themeColor}" />

Qualsiasi valore dell'attributo tra parentesi graffe è sempre un'estensione di markup XAML. Tuttavia, è anche possibile fare riferimento alle estensioni di markup XAML senza l'uso di parentesi graffe.

Nota

Diverse estensioni di markup XAML fanno parte della specifica XAML 2009. Questi vengono visualizzati nei file XAML con il prefisso dello spazio dei nomi x personalizzato e vengono comunemente indicati con questo prefisso.

Oltre alle estensioni di markup descritte in questo articolo, le estensioni di markup seguenti sono incluse in .NET MAUI e descritte in altri articoli:

Estensione di markup x:Static

L'estensione di markup x:Static è supportata dalla classe StaticExtension. La classe ha una singola proprietà denominata Member di tipo string impostata sul nome di un membro di costante pubblica, proprietà statica, campo statico o enumerazione.

Un modo per usare x:Static consiste nel definire prima una classe con alcune costanti o variabili statiche, ad esempio questa classe AppConstants:

static class AppConstants
{
    public static double NormalFontSize = 18;
}

Il codice XAML seguente illustra l'approccio più verboso per creare un'istanza della classe StaticExtension tra i tag dell'elemento proprietà Label.FontSize:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sys="clr-namespace:System;assembly=netstandard"
             xmlns:local="clr-namespace:MarkupExtensions"
             x:Class="MarkupExtensions.StaticDemoPage"
             Title="x:Static Demo">
    <StackLayout Margin="10, 0">
        <Label Text="Label No. 1">
            <Label.FontSize>
                <x:StaticExtension Member="local:AppConstants.NormalFontSize" />
            </Label.FontSize>
        </Label>
        ···
    </StackLayout>
</ContentPage>

Il parser XAML consente anche di abbreviare la classe StaticExtension come x:Static:

<Label Text="Label No. 2">
    <Label.FontSize>
        <x:Static Member="local:AppConstants.NormalFontSize" />
    </Label.FontSize>
</Label>

Questa sintassi può essere ulteriormente semplificata inserendo la classe StaticExtension e l'impostazione del membro tra parentesi graffe. L'espressione risultante viene impostata direttamente sull'attributo FontSize:

<Label Text="Label No. 3"
       FontSize="{x:StaticExtension Member=local:AppConstants.NormalFontSize}" />

In questo esempio, all'interno delle parentesi graffe, non ci sono virgolette. La proprietà Member di StaticExtension non è più un attributo XML. È invece parte dell'espressione per l'estensione di markup.

Proprio come è possibile abbreviare x:StaticExtension per x:Static quando lo si usa come elemento oggetto, è anche possibile abbreviarlo nell'espressione tra parentesi graffe:

<Label Text="Label No. 4"
       FontSize="{x:Static Member=local:AppConstants.NormalFontSize}" />

La classe StaticExtension ha un attributo ContentProperty che fa riferimento alla proprietà Member, che contrassegna questa proprietà come proprietà di contenuto predefinita della classe. Per le estensioni di markup XAML espresse con parentesi graffe, è possibile eliminare la parte Member= dall'espressione:

<Label Text="Label No. 5"
       FontSize="{x:Static local:AppConstants.NormalFontSize}" />

Si tratta della forma più comune dell'estensione di markup x:Static.

Il tag radice dell'esempio XAML contiene anche una dichiarazione dello spazio dei nomi XML per lo spazio dei nomi .NET System. Questo permette di impostare la dimensione del carattere Label sul campo statico Math.PI. Ciò comporta testo piuttosto piccolo, quindi la proprietà Scale è impostata su Math.E:

<Label Text="&#x03C0; &#x00D7; E sized text"
       FontSize="{x:Static sys:Math.PI}"
       Scale="{x:Static sys:Math.E}"
       HorizontalOptions="Center" />

Lo screenshot seguente mostra l'output XAML:

x:Static demo.

Estensione di markup x:Reference

L'estensione di markup x:Reference è supportata dalla classe ReferenceExtension. La classe ha una singola proprietà denominata Name di tipo string impostata sul nome di un elemento nella pagina a cui è stato assegnato un nome con x:Name. Questa proprietà Name è la proprietà content di ReferenceExtension, quindi Name= non è necessaria quando x:Reference appare tra parentesi graffe. L'estensione di markup x:Reference viene usata esclusivamente con i data binding. Per altre informazioni sui data binding, vedere Data binding.

L'esempio XAML seguente mostra due usi di x:Reference con data binding, il primo in cui viene usato per impostare la proprietà Source dell'oggetto Binding e la seconda in cui viene usata per impostare la proprietà BindingContext per due data binding:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.ReferenceDemoPage"
             x:Name="page"
             Title="x:Reference Demo">    
    <StackLayout Margin="10, 0">        
        <Label x:DataType="ContentPage"
               Text="{Binding Source={x:Reference page},
                              StringFormat='The type of this page is {0}'}"
               FontSize="18"
               VerticalOptions="Center"
               HorizontalTextAlignment="Center" />
        <Slider x:Name="slider"
                Maximum="360"
                VerticalOptions="Center" />
        <Label x:DataType="Slider"
               BindingContext="{x:Reference slider}"
               Text="{Binding Value, StringFormat='{0:F0}&#x00B0; rotation'}"
               Rotation="{Binding Value}"
               FontSize="24"
               HorizontalOptions="Center"
               VerticalOptions="Center" />        
    </StackLayout>
</ContentPage>

In questo esempio entrambe le espressioni x:Reference usano la versione abbreviata del nome della classe ReferenceExtension ed eliminare la parte Name= dell'espressione. Nel primo esempio, l'estensione di markup x:Reference è incorporata nell'estensione di markup Binding e le proprietà Source e StringFormat sono separate da virgole.

Lo screenshot seguente mostra l'output XAML:

x:Reference demo.

Estensione di markup x:Type

L'estensione di markup x:Type è l'equivalente XAML della parola chiave typeof C#. È supportata dalla classe TypeExtension, che definisce una proprietà denominata TypeName di tipo string che deve essere impostata su un nome di classe o struttura. L'estensione di markup x:Type restituisce l'oggetto Type della classe o della struttura. TypeName è la proprietà del contenuto di TypeExtension, pertanto non è necessario TypeName= quando x:Type viene visualizzato con parentesi graffe.

L'estensione di markup x:Type viene comunemente usata con l'estensione di markup x:Array. Per altre informazioni, vedere estensione di markup x:Array.

L'esempio XAML seguente illustra l'uso dell'estensione di markup x:Type per creare un'istanza di oggetti MAUI .NET e aggiungerli a un StackLayout. Il codice XAML è costituito da tre elementi Button con le relative proprietà Command impostate su un Binding e le proprietà CommandParameter impostate su tipi di tre visualizzazioni MAUI .NET:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MarkupExtensions"
             x:Class="MarkupExtensions.TypeDemoPage"
             Title="x:Type Demo"
             x:DataType="local:TypeDemoPage">
    <StackLayout x:Name="stackLayout"
                 Padding="10, 0">
        <Button Text="Create a Slider"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Command="{Binding CreateCommand}"
                CommandParameter="{x:Type Slider}" />
        <Button Text="Create a Stepper"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Command="{Binding CreateCommand}"
                CommandParameter="{x:Type Stepper}" />
        <Button Text="Create a Switch"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Command="{Binding CreateCommand}"
                CommandParameter="{x:Type Switch}" />
    </StackLayout>
</ContentPage>

Il file code-behind definisce e inizializza la proprietà CreateCommand:

public partial class TypeDemoPage : ContentPage
{
    public ICommand CreateCommand { get; private set; }

    public TypeDemoPage()
    {
        InitializeComponent();

        CreateCommand = new Command<Type>((Type viewType) =>
        {
            View view = (View)Activator.CreateInstance(viewType);
            view.VerticalOptions = LayoutOptions.Center;
            stackLayout.Add(view);
        });

        BindingContext = this;
    }
}

Quando Button viene premuto, viene creata una nuova istanza dell'argomento CommandParameter e viene aggiunta al StackLayout. I tre oggetti Button quindi condividono la pagina con visualizzazioni create dinamicamente:

x:Type demo.

I tipi generici possono essere specificati con l'estensione di markup x:Type specificando il vincolo generico come argomento stringa con prefisso tra parentesi:

<x:Array Type="{x:Type local:MyType(local:MyObject)}">
    ...
</x:Array>

È possibile specificare più argomenti di tipo come argomenti stringa preceduti, delimitati da una virgola:

<x:Array Type="{x:Type local:MyType(local:MyObject,x:Boolean)}">
    ...
</x:Array>

Per altre informazioni sui generics in XAML, vedere Generics.

Estensione di markup x:Array

L'estensione di markup x:Array consente di definire una matrice nel markup. È supportato dalla classe ArrayExtension, che definisce due proprietà:

  • Type di tipo Type, che indica il tipo degli elementi nella matrice. Questa proprietà deve essere impostata su un'estensione di markup x:Type.
  • Items di tipo IList, ovvero una raccolta degli elementi stessi. Questa è la proprietà del contenuto di ArrayExtension.

L'estensione di markup x:Array non viene mai visualizzata tra parentesi graffe. Al contrario, x:Array tag di inizio e fine delimitano l'elenco di elementi.

L'esempio XAML seguente mostra come usare x:Array per aggiungere elementi a un ListView impostando la proprietà ItemsSource su una matrice:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.ArrayDemoPage"
             Title="x:Array Demo Page">
    <ListView Margin="10">
        <ListView.ItemsSource>
            <x:Array Type="{x:Type Color}">
                <Color>Aqua</Color>
                <Color>Black</Color>
                <Color>Blue</Color>
                <Color>Fuchsia</Color>
                <Color>Gray</Color>
                <Color>Green</Color>
                <Color>Lime</Color>
                <Color>Maroon</Color>
                <Color>Navy</Color>
                <Color>Olive</Color>
                <Color>Pink</Color>
                <Color>Purple</Color>
                <Color>Red</Color>
                <Color>Silver</Color>
                <Color>Teal</Color>
                <Color>White</Color>
                <Color>Yellow</Color>
            </x:Array>
        </ListView.ItemsSource>
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="Color">
                <ViewCell>
                    <BoxView Color="{Binding}"
                             Margin="3" />
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>  

In questo esempio, il ViewCell crea una semplice BoxView per ogni voce di colore:

x:Array demo.

Nota

Quando si definiscono matrici di tipi comuni come stringhe o numeri, usare i tag delle primitive del linguaggio XAML elencati in Argomenti Pass.

Estensione di markup x:Null

L'estensione di markup x:Null è supportata dalla classe NullExtension. Non ha proprietà ed è semplicemente l'equivalente XAML della parola chiave C# null.

L'esempio XAML seguente illustra come usare l'estensione di markup x:Null:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.NullDemoPage"
             Title="x:Null Demo">
    <ContentPage.Resources>
        <Style TargetType="Label">
            <Setter Property="FontSize" Value="48" />
            <Setter Property="FontFamily" Value="OpenSansRegular" />
        </Style>
    </ContentPage.Resources>

    <StackLayout Padding="10, 0">
        <Label Text="Text 1" />
        <Label Text="Text 2" />
        <Label Text="Text 3"
               FontFamily="{x:Null}" />
        <Label Text="Text 4" />
        <Label Text="Text 5" />
    </StackLayout>
</ContentPage>      

In questo esempio viene definito un Style implicito per Label che include un Setter che imposta la proprietà FontFamily su un tipo di carattere specifico. Tuttavia, il terzo Label evita l'uso del tipo di carattere definito nello stile implicito impostando il relativo FontFamily su x:Null:

demo x:Null.

Estensione markup di DataTemplate

L'estensione di markup DataTemplate consente di convertire un tipo in un DataTemplate. È supportata dalla classe DataTemplateExtension, che definisce una proprietà TypeName, di tipo string, impostata sul nome del tipo da convertire in un DataTemplate. La proprietà TypeName è la proprietà contenuto di DataTemplateExtension. Pertanto, per le espressioni di markup XAML espresse con parentesi graffe, è possibile eliminare la parte TypeName= dell'espressione.

Nota

Il parser XAML consente di abbreviatare la classe DataTemplateExtension come DataTemplate.

Un utilizzo tipico di questa estensione di markup si trova in un'applicazione Shell, come illustrato nell'esempio seguente:

<ShellContent Title="Monkeys"
              Icon="monkey.png"
              ContentTemplate="{DataTemplate views:MonkeysPage}" />

In questo esempio, MonkeysPage viene convertito da un ContentPage a un DataTemplate, impostato come valore della proprietà ShellContent.ContentTemplate. Ciò garantisce che MonkeysPage venga creato solo quando si verifica lo spostamento alla pagina, anziché all'avvio dell'applicazione.

Per altre informazioni sulle app shell, vedere Shell.