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 deIMarkupExtension<Type>
.ArrayExtension
dérive deIMarkupExtension<Array>
.DynamicResourceExtension
dérive deIMarkupExtension<DynamicResource>
.BindingExtension
dérive deIMarkupExtension<BindingBase>
.ConstraintExpression
dérive deIMarkupExtension<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 :
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 :
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.