Partager via


Création d’extensions de balisage XAML

Au niveau programmatique, une extension de balisage XAML est une classe qui implémente l’interface ou IMarkupExtension<T> l’interfaceIMarkupExtension. Vous pouvez explorer le code source des extensions de balisage standard décrites ci-dessous dans le répertoire MarkupExtensions du Xamarin.Forms référentiel GitHub.

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. Voici le cas avec plusieurs extensions de Xamarin.Forms balisage :

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

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.

Très souvent, les extensions de balisage XAML définissent des propriétés qui contribuent à la valeur de retour. (L’exception évidente est NullExtension, dans laquelle ProvideValue il suffit de renvoyer null.) La ProvideValue méthode a un seul argument de type IServiceProvider qui sera abordé plus loin dans cet article.

Extension de balisage pour spécifier la couleur

L’extension de balisage XAML suivante vous permet de construire une Color valeur à l’aide de composants hue, saturation et 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 double H { set; get; }

    public double S { set; get; }

    public double L { set; get; }

    public double A { set; get; } = 1.0;

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

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

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

La page de démonstration de couleur HSL affiche différentes façons d’apparaître HslColorExtension dans un fichier XAML pour spécifier la couleur d’un BoxView:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MarkupExtensions"
             x:Class="MarkupExtensions.HslColorDemoPage"
             Title="HSL Color Demo">

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="BoxView">
                <Setter Property="WidthRequest" Value="80" />
                <Setter Property="HeightRequest" Value="80" />
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            </Style>
        </ResourceDictionary>
    </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>

Notez que lorsqu’il HslColorExtension s’agit d’une balise XML, les quatre propriétés sont définies en tant qu’attributs, mais lorsqu’elles apparaissent 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 HSL

Extension de balisage pour l’accès aux bitmaps

L’argument à ProvideValue est un objet qui implémente l’interface IServiceProvider , qui est définie dans l’espace de noms .NET System . Cette interface a un membre, une méthode nommée GetService avec un Type argument.

La ImageResourceExtension classe indiquée ci-dessous montre une utilisation possible et IServiceProvider GetService pour obtenir un IXmlLineInfoProvider objet qui peut fournir des informations de ligne et de caractère indiquant où une erreur particulière a été détectée. Dans ce cas, une exception est levée lorsque la Source propriété n’a pas été définie :

[ContentProperty("Source")]
class ImageResourceExtension : IMarkupExtension<ImageSource>
{
    public string Source { set; get; }

    public ImageSource ProvideValue(IServiceProvider serviceProvider)
    {
        if (String.IsNullOrEmpty(Source))
        {
            IXmlLineInfoProvider lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
            IXmlLineInfo lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
            throw new XamlParseException("ImageResourceExtension requires Source property to be set", lineInfo);
        }

        string assemblyName = GetType().GetTypeInfo().Assembly.GetName().Name;
        return ImageSource.FromResource(assemblyName + "." + Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);
    }

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

ImageResourceExtension est utile lorsqu’un fichier XAML doit accéder à un fichier image stocké en tant que ressource incorporée dans le projet de bibliothèque .NET Standard. Elle utilise la Source propriété pour appeler la méthode statique ImageSource.FromResource . Cette méthode nécessite un nom de ressource complet, qui se compose du nom de l’assembly, du nom du dossier et du nom de fichier séparés par des points. Le deuxième argument de la méthode fournit le nom de l’assembly ImageSource.FromResource et n’est requis que pour les builds de mise en production sur UWP. Quoi qu’il en soit, ImageSource.FromResource doit être appelé à partir de l’assembly qui contient la bitmap, ce qui signifie que cette extension de ressource XAML ne peut pas faire partie d’une bibliothèque externe, sauf si les images se trouvent également dans cette bibliothèque. (Voir le Article Images incorporées pour plus d’informations sur l’accès aux bitmaps stockées en tant que ressources incorporées.)

Bien que ImageResourceExtension la Source propriété soit définie, la Source propriété est indiquée dans un attribut comme propriété de contenu de la classe. Cela signifie que la Source= partie de l’expression dans les accolades peut être omise. Dans la page Démonstration de ressource d’image, les Image éléments récupèrent deux images à l’aide du nom du dossier et du nom de fichier séparés par des points :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MarkupExtensions"
             x:Class="MarkupExtensions.ImageResourceDemoPage"
             Title="Image Resource Demo">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Image Source="{local:ImageResource Images.SeatedMonkey.jpg}"
               Grid.Row="0" />

        <Image Source="{local:ImageResource Images.FacePalm.jpg}"
               Grid.Row="1" />

    </Grid>
</ContentPage>

Voici le programme en cours d’exécution :

Démonstration des ressources d’image

Fournisseurs de services

En utilisant l’argument IServiceProvider pour ProvideValue, les extensions de balisage XAML peuvent accéder à des informations utiles sur le fichier XAML dans lequel elles sont utilisées. Mais pour utiliser l’argument IServiceProvider avec succès, vous devez savoir quel type de services sont disponibles dans des contextes particuliers. La meilleure façon de comprendre cette fonctionnalité consiste à étudier le code source des extensions de balisage XAML existantes dans le dossier MarkupExtensions du Xamarin.Forms référentiel sur GitHub. N’oubliez pas que certains types de services sont internes à Xamarin.Forms.

Dans certaines extensions de balisage XAML, ce service peut être utile :

 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, TargetObject il s’agit TargetProperty Image d’un BindableProperty objet pour la Source propriété de Image.ImageResourceExtension Il s’agit de la propriété sur laquelle l’extension de balisage XAML a été définie.

L’appel GetService avec un argument de typeof(IProvideValueTarget) retourne réellement un objet de type SimpleValueTargetProvider, qui est défini dans l’espace Xamarin.Forms.Xaml.Internals de noms. Si vous castez la valeur de retour de GetService ce type, vous pouvez également accéder à une propriété, qui est un ParentObjects tableau qui contient l’élément, le Image Grid parent et le ImageResourceDemoPage parent du Grid.

Conclusion

Les extensions de balisage XAML jouent un rôle essentiel en XAML en étendant la possibilité de définir des attributs à partir de diverses sources. En outre, si les extensions de balisage XAML existantes ne fournissent pas exactement ce dont vous avez besoin, vous pouvez également écrire vos propres extensions.