Condividi tramite


Creare estensioni di markup XAML

Sfogliare l'esempio. Esplorare l'esempio

A livello di sviluppatore, un'estensione di markup XAML .NET Multipiattaforma (.NET MAUI) è una classe che implementa l'interfaccia IMarkupExtension o IMarkupExtension<T> . È anche possibile definire estensioni di markup XAML personalizzate derivando da IMarkupExtension o IMarkupExtension<T>. Utilizzare il formato generico se l'estensione di markup ottiene un valore di un particolare tipo. Questo è il caso di diverse estensioni di markup MAUI .NET:

  • TypeExtension deriva da IMarkupExtension<Type>
  • ArrayExtension deriva da IMarkupExtension<Array>
  • DynamicResourceExtension deriva da IMarkupExtension<DynamicResource>
  • BindingExtension deriva da IMarkupExtension<BindingBase>

Tutte le classi che implementano IMarkupExtension o devono essere annotate con o RequireServiceAttribute AcceptEmptyServiceProviderAttribute.IMarkupExtension<T> Per altre informazioni, vedere Provider di servizi.

Le due IMarkupExtension interfacce definiscono un solo metodo, denominato ProvideValue:

public interface IMarkupExtension
{
    object ProvideValue(IServiceProvider serviceProvider);
}

public interface IMarkupExtension<out T> : IMarkupExtension
{
    new T ProvideValue(IServiceProvider serviceProvider);
}

Poiché IMarkupExtension<T> deriva da IMarkupExtension e include la new parola chiave in ProvideValue, contiene entrambi i ProvideValue metodi.

Spesso, le estensioni di markup XAML definiscono proprietà che contribuiscono al valore restituito e il ProvideValue metodo ha un singolo argomento di tipo IServiceProvider. Per altre informazioni sui provider di servizi, vedere Provider di servizi.

Creare un'estensione di markup

L'estensione di markup XAML seguente illustra come creare un'estensione di markup personalizzata. Consente di costruire un Color valore usando componenti di tonalità, saturazione e luminosità. Definisce quattro proprietà per i quattro componenti del colore, incluso un componente alfa inizializzato su 1. La classe deriva da IMarkupExtension<Color> per indicare un Color valore restituito:

public class HslColorExtension : IMarkupExtension<Color>
{
    public float H { get; set; }
    public float S { get; set; }
    public float L { get; set; }
    public float A { get; set; } = 1.0f;

    public Color ProvideValue(IServiceProvider serviceProvider)
    {
        return Color.FromHsla(H, S, L, A);
    }

    object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
    {
        return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
    }
}
[AcceptEmptyServiceProvider]
public class HslColorExtension : IMarkupExtension<Color>
{
    public float H { get; set; }
    public float S { get; set; }
    public float L { get; set; }
    public float A { get; set; } = 1.0f;

    public Color ProvideValue(IServiceProvider serviceProvider)
    {
        return Color.FromHsla(H, S, L, A);
    }

    object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
    {
        return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
    }
}

Questa estensione di markup è annotata con AcceptEmptyServiceProviderAttribute perché non usa un servizio del provider di servizi. Per altre informazioni, vedere Provider di servizi.

Poiché IMarkupExtension<T> deriva da IMarkupExtension, la classe deve contenere due ProvideValue metodi, uno che restituisce un Color oggetto e un altro che restituisce un objectoggetto , ma il secondo metodo può chiamare il primo metodo.

Utilizzare un'estensione di markup

Il codice XAML seguente illustra un'ampia gamma di approcci che possono essere usati per richiamare l'oggetto HslColorExtension per specificare il colore per un oggetto BoxView:

<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.HslColorDemoPage"
             Title="HSL Color Demo">
    <ContentPage.Resources>
        <Style TargetType="BoxView">
            <Setter Property="WidthRequest" Value="80" />
            <Setter Property="HeightRequest" Value="80" />
            <Setter Property="HorizontalOptions" Value="Center" />
            <Setter Property="VerticalOptions" Value="Center" />
        </Style>
    </ContentPage.Resources>

    <StackLayout>
        <BoxView>
            <BoxView.Color>
                <local:HslColorExtension H="0" S="1" L="0.5" A="1" />
            </BoxView.Color>
        </BoxView>
        <BoxView>
            <BoxView.Color>
                <local:HslColor H="0.33" S="1" L="0.5" />
            </BoxView.Color>
        </BoxView>
        <BoxView Color="{local:HslColorExtension H=0.67, S=1, L=0.5}" />
        <BoxView Color="{local:HslColor H=0, S=0, L=0.5}" />
        <BoxView Color="{local:HslColor A=0.5}" />
    </StackLayout>
</ContentPage>

In questo esempio, quando HslColorExtension è un tag XML, le quattro proprietà vengono impostate come attributi, ma quando viene visualizzata tra parentesi graffe, le quattro proprietà sono separate da virgole senza virgolette. I valori predefiniti per H, Se L sono 0 e il valore predefinito di A è 1, pertanto tali proprietà possono essere omesse se si desidera che siano impostate su valori predefiniti. L'ultimo esempio mostra un esempio in cui la luminosità è 0, che normalmente restituisce nero, ma il canale alfa è 0,5, quindi è metà trasparente e appare grigio sullo sfondo bianco della pagina:

Demo dei colori HSL.

Provider di servizi

Usando l'argomento IServiceProvider su ProvideValue, le estensioni di markup XAML possono ottenere l'accesso ai dati sul file XAML in cui vengono usati. Ad esempio, il IProvideValueTarget servizio consente di recuperare i dati relativi all'oggetto a cui viene applicata l'estensione di markup:

IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

L'interfaccia IProvideValueTarget definisce due proprietà e TargetObject TargetProperty. Quando queste informazioni vengono ottenute nella HslColorExtension classe , TargetObject è e TargetProperty è BoxView la Color proprietà di BoxView. Questa è la proprietà in cui è stata impostata l'estensione di markup XAML.

Tutte le classi che implementano IMarkupExtension o devono essere annotate con o RequireServiceAttribute AcceptEmptyServiceProviderAttribute:IMarkupExtension<T>

  • Per ogni uso di serviceProvider.GetService(typeof(T)) nel ProvideValue metodo , la classe deve essere annotata con [RequireService(typeof(T))]:

    [RequireService([typeof(IReferenceProvider), typeof(IProvideValueTarget)])]
    public class MyMarkupExtension : IMarkupExtension
    {
        public object ProvideValue(IServiceProvider serviceProvider)
        {
            ...
            var referenceProvider = serviceProvider.GetService<IReferenceProvider>();
            var valueProvider = serviceProvider.GetService<IProvideValueTarget>() as IProvideParentValues
                                    ?? throw new ArgumentException("serviceProvider does not provide an IProvideValueTarget");
            ...
        }
    }
    
  • Se l'estensione di markup non usa alcun servizio del provider di servizi, la classe deve essere annotata con [AcceptEmptyServiceProvider].

Queste annotazioni sono necessarie a causa di un'ottimizzazione del compilatore XAML che consente la generazione di codice più efficiente, che consente di ridurre le dimensioni dell'app e migliorare le prestazioni di runtime.