Partager via


Créer des extensions de balisage XAML

Parcourez l’exemple. Parcourir l'exemple

Au niveau du développeur, une extension de balisage XAML .NET Multi-platform App UI (.NET MAUI) est une classe qui implémente l’interface IMarkupExtension ou IMarkupExtension<T>. Il est également possible de définir vos propres extensions de balisage XAML personnalisées en vous appuyant sur IMarkupExtension ou IMarkupExtension<T>. Utilisez la forme courante si l’extension de balisage renvoie une valeur d’un type particulier. Cela peut se produire avec certaines extensions de balisage MAUI .NET :

  • TypeExtension dérive de IMarkupExtension<Type>.
  • ArrayExtension dérive de IMarkupExtension<Array>.
  • DynamicResourceExtension dérive de IMarkupExtension<DynamicResource>.
  • BindingExtension dérive de IMarkupExtension<BindingBase>.

Toutes les classes qui implémentent IMarkupExtension ou IMarkupExtension<T> doivent être annotées avec RequireServiceAttribute ou AcceptEmptyServiceProviderAttribute. Pour plus d’informations, consultez Fournisseurs de services.

Les deux interfaces IMarkupExtension ne définissent qu’une méthode chacune, nommée ProvideValue :

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

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

Étant donné que IMarkupExtension<T> dérive de IMarkupExtension et inclut le mot clé new sur ProvideValue, elle contient les deux méthodes ProvideValue.

Souvent, les extensions de balisage XAML définissent des propriétés qui contribuent à la valeur renvoyée, et la méthode ProvideValue a un seul argument de type IServiceProvider. Pour plus d’informations sur les fournisseurs de services, consultez Fournisseurs de services.

Créer une extension de balisage

L’extension de balisage XAML suivante montre comment créer votre propre extension de balisage. Vous pouvez ainsi construire une valeur Color à l’aide de composants de teinte, de saturation et de luminosité. Quatre propriétés correspondent aux quatre composants de la couleur, dont un composant alpha défini sur 1. La classe dérive de IMarkupExtension<Color> pour renvoyer une valeur Color :

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

Cette extension de balisage est annotée avec AcceptEmptyServiceProviderAttribute car elle n’utilise aucun service du fournisseur de services. Pour plus d’informations, consultez Fournisseurs de services.

Étant donné que IMarkupExtension<T> dérive de IMarkupExtension, la classe doit contenir deux méthodes ProvideValue, une qui retourne une Color et une autre qui retourne un object, mais la seconde méthode peut appeler la première.

Consommer une extension de balisage

Le code XAML suivant illustre une variété d’approches qui peuvent être utilisées pour appeler l’extension HslColorExtension afin de définir la couleur d’une 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>

Dans cet exemple, lorsque HslColorExtension est une balise XML, les quatre propriétés sont définies en tant qu’attributs, mais lorsque l’extension apparaît entre accolades, les quatre propriétés sont séparées par des virgules sans guillemets. Les valeurs par défaut de H, S et L sont 0, et la valeur par défaut de A est 1, de sorte que ces propriétés peuvent être omises si vous souhaitez qu’elles soient définies sur les valeurs par défaut. Le dernier exemple montre un cas où la luminosité est définie sur 0, ce qui produit normalement du noir, mais le canal alpha est défini sur 0,5, de sorte que le rendu est semi-transparent et apparaît gris sur l’arrière-plan blanc de la page :

Démonstration de couleur TSL.

Fournisseurs de services

En utilisant l’argument IServiceProvider pour ProvideValue, les extensions de balisage XAML peuvent accéder aux données relatives au fichier XAML dans lequel elles sont utilisées. Par exemple, le service IProvideValueTarget vous permet de récupérer des données sur l’objet auquel l’extension de balisage est appliquée :

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

L’interface IProvideValueTarget définit deux propriétés, TargetObject et TargetProperty. Lorsque ces informations sont obtenues dans la classe HslColorExtension, TargetObject est la BoxView et TargetProperty est la propriété Color de BoxView. Il s’agit de la propriété sur laquelle l’extension de balisage XAML a été définie.

Toutes les classes qui implémentent IMarkupExtension ou IMarkupExtension<T> doivent être annotées avec RequireServiceAttribute ou AcceptEmptyServiceProviderAttribute :

  • Pour chaque utilisation de serviceProvider.GetService(typeof(T)) dans la méthode ProvideValue, la classe doit être annotée avec [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");
            ...
        }
    }
    
  • Si l’extension de balisage n’utilise aucun service du fournisseur de services, la classe doit être annotée avec [AcceptEmptyServiceProvider].

Ces annotations sont nécessaires en raison d’une optimisation du compilateur XAML qui permet de générer un code plus efficace, ce qui contribue à réduire la taille de l’application et à améliorer les performances de runtime.