Estensioni di markup XAML

Completato

Gran parte della definizione XAML viene risolta in fase di compilazione. Spesso si sa dove dovrebbero essere posizionati gli elementi, quali colori e tipi di carattere verranno usati e quali valori letterali dovrebbero essere assegnati alle proprietà.

Talvolta, tuttavia, è necessario impostare una proprietà su un valore che non è possibile determinare in fase di compilazione. Questi valori sono noti solo quando il programma è in esecuzione. In questi casi, è possibile creare un oggetto che fornisce un valore al codice XAML in fase di esecuzione. A tal fine, XAML supporta le estensioni di markup.

In questa unità si apprenderà come creare e usare le estensioni di markup.

Che cos'è un'estensione di markup?

Un'estensione di markup è una classe che viene usata in XAML per accedere ai valori di runtime. Si supponga di avere molte etichette definite nell'interfaccia utente XAML e di voler impostare la proprietà FontSize sullo stesso valore in tutta l'app per garantire la coerenza dello stile di tutte le etichette. È possibile impostare la proprietà FontSize usando XAML, come illustrato nell'esempio seguente:

<Label Text="Hello, World!"
            Grid.Row="0"
            SemanticProperties.HeadingLevel="Level1"
            FontSize="28"
            HorizontalOptions="CenterAndExpand"/>

Questa stessa impostazione può essere ripetuta per ogni etichetta, ma cosa accade se successivamente si decide di modificarne il valore? È necessario trovare ogni singola istanza della proprietà e apportare la modifica. Si supponga inoltre di non sapere quale valore usare. Potrebbe essere calcolato in fase di esecuzione in base a fattori come l'orientamento del dispositivo, la risoluzione dello schermo o altri elementi da tenere in considerazione. In questi casi è necessario ricorrere a qualcosa di più sofisticato di un valore letterale hardcoded. A questo punto risulta utile un'estensione di markup. Le estensioni di markup offrono flessibilità per quanto riguarda il modo di ottenere un valore da usare in XAML.

Creazione di un'estensione di markup

Un'estensione di markup è una classe che implementa l'interfaccia Microsoft.Maui.Controls.Xaml.IMarkupExtension. Questa interfaccia definisce un unico metodo, denominato ProvideValue, con la firma seguente:

public object ProvideValue(IServiceProvider serviceProvider)
{
    ...
}

Lo scopo di questo metodo è fornire un valore per il markup XAML. Si noti che il tipo restituito è object e quindi il valore può essere di qualsiasi tipo, a condizione che sia appropriato per la posizione in cui viene usato. Ad esempio, in un'estensione di markup che calcola e restituisce le dimensioni del carattere, il tipo restituito deve essere double.

Il parametro serviceProvider contiene informazioni contestuali sulla posizione in cui viene usata l'estensione di markup nel codice XAML. Tra le altre informazioni, identifica il controllo a cui viene applicata l'estensione.

È possibile mantenere semplice l'estensione di markup per la proprietà FontSize. Nell'esempio seguente la MainPage classe espone un double campo denominato MyFontSize. La classe GlobalFontSizeExtension implementa l'interfaccia IMarkupExtension e il metodo ProvideValue restituisce il valore della variabile MyFontSize:

namespace MyMauiApp;

public partial class MainPage : ContentPage
{
    public const double MyFontSize = 28;

    public MainPage()
    {
        InitializeComponent();
        ...
    }
    ...
}

public class GlobalFontSizeExtension : IMarkupExtension
{
    public object ProvideValue(IServiceProvider serviceProvider)
    {
        return MainPage.MyFontSize;
    }
}

Nota

Il campo MyFontSize deve essere un membro static della classe MainPage per potergli fare riferimento nel metodo ProvideValue in questo modo. È buona prassi che in questo caso anche la variabile sia una costante. Un valore const è static.

Il metodo ProvideValue potrebbe anche apportare modifiche al valore restituito, a seconda dell'orientamento e del fattore di forma del dispositivo.

Applicazione dell'estensione di markup a un controllo in XAML

Per usare l'estensione di markup nel codice XAML, aggiungere lo spazio dei nomi contenente la classe GlobalFontSizeExtension all'elenco degli spazi dei nomi nel tag ContentPage. Nell'esempio seguente, a questo spazio dei nomi è assegnato l'alias mycode:

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

Si usa l'estensione di markup per impostare la proprietà FontSize in questo modo. Si noti che, per convenzione, il nome di un'estensione di markup ha il suffisso Extension. XAML riconosce questo suffisso e non è necessario includerlo quando si chiama l'estensione dal codice XAML. Nell'esempio seguente ci si riferisce alla classe GlobalFontSizeExtension semplicemente come GlobalFontSize:

<Label Text="Hello, World!"
            Grid.Row="0"
            SemanticProperties.HeadingLevel="Level1"
            FontSize="{mycode:GlobalFontSize}"
            HorizontalOptions="CenterAndExpand"/>

È possibile applicare la stessa estensione di markup a tutto il codice XAML per qualsiasi controllo che deve specificare le dimensioni del carattere. In seguito, se si decide di modificare la dimensione del carattere, sarà sufficiente modificare la definizione della variabile MyFontSize nella classe MainPage.

Classe StaticExtension

L'estensione di markup GlobalFontSize è molto utile, ma è improbabile che sia necessario creare un'estensione di questo tipo. Il motivo è semplice. .NET MAUI fornisce già un'estensione più generalizzata che consente di fare riferimento a qualsiasi valore statico nel codice. Questa estensione è denominata in modo abbreviato StaticExtension o Static. Il codice seguente mostra la struttura di base di questa classe di estensione:

[ContentProperty ("Member")]
public class StaticExtension : IMarkupExtension
{
    public string Member {get; set;}
    public object ProvideValue (IServiceProvider serviceProvider)
    {
        ...
    }
}

Nota

Lo scopo delle estensioni di markup personalizzate è quello di consentire di gestire situazioni più complesse anziché il caso statico semplice. Ad esempio, può essere necessario modificare dinamicamente le dimensioni del carattere in base al fattore di forma del dispositivo.

Per usare questa classe nel codice XAML, si specifica il nome della variabile statica a cui si vuole fare riferimento nella proprietà Member e il metodo ProvideValue restituisce il valore in questa variabile. L'esempio seguente illustra come usarla:

<Label Text="Hello, World!"
            Grid.Row="0"
            SemanticProperties.HeadingLevel="Level1"
            FontSize="{x:Static Member=mycode:MainPage.MyFontSize}"
            HorizontalOptions="CenterAndExpand"/>

.NET MAUI fornisce un set di altre classi di estensione di markup, che è possibile usare per scenari come il data binding, il riferimento a risorse e stili dinamici e la gestione di matrici di dati.

Verifica delle conoscenze

1.

Quale estensione di markup consente di impostare una proprietà XAML su un valore statico definito in una classe code-behind?

2.

Quale interfaccia si usa per creare un'estensione di markup personalizzata?