[WPF] Comment et pourquoi créer sa propre "MarkupExtension" ?
Lorsque l'on manipule du XAML, il n'est pas rare de rencontrer des choses comme ceci:
{Binding ...}, {StaticResource ...}, and {RelativeSource ...}
Ces chaînes de caractères, encadrées des signes {}, forment ce que l'on appelle des MarkupExtensions.
Il peut arriver, lors de vos développements WPF, que les fonctionnalités offertes par le XAML ne soient pas suffisantes. Pour pallier à ce problème, la solution est d'écrire la fonctionnalité manquante dans le ode behind. Cela marche très bien mais comment faire si l'on ne veut pas écrire cette fonctionnalité dans le code mais faire le maximum de choses en XAML ? On écrit sa propre MarkupExtension ! 
Pour faire cela, il n'y a rien d'extraordainire: il vous suffit de créer une classe qui hérite de MarkupExtension et de surcharger la méthode ProvideValue:
public override object ProvideValue(IServiceProvider serviceProvider)
{
return "Hello World";
}
Notez que les conventions WPF veulent que le nom de votre extension doit-être XXXExtension mais, dans le code, vous pouvez utitliser simplement XXX: c'est la même chose pour les attributs .NET par exemple (qui se nomme YYYAttribute mais que l'on utilise sous la forme YYY):
<TextBlock Text="{CustomExtension:CalculateSum}" HorizontalAlignment="Center" VerticalAlignment="Center" />
Si vous souhaitez utiliser des paramètres, rien de bien compliquer: il vous suffit de déclarer des propriétés dans votre classe:
public double FirstNumber { get; set; }
public double SecondNumber { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (FirstNumber == 0.0 && SecondNumber == 0.0)
{
return "No parameters specify";
}
else
{
return Convert.ToString(FirstNumber + SecondNumber);
}
}
Et ensuite, de les utiliser dans votre code XAML:
<TextBlock Text="{CustomExtension:CalculateSum FirstNumber=5, SecondNumber=20}" HorizontalAlignment="Center"
VerticalAlignment="Center" />
A l'exécution, vous remarquez que l'affichage affiche bien le résultat escompté:
Vous avez sans doute remarquez que la méthode ProvideValue renvoit un object: cela sous-entend que vous pouvez lui faire renvoyer ce que vous voulez (chaîne de caractères, images, entier, etc...). Cependant, dans la majorité des cas, vous connaissez le type que vous souhaitez renvoyer: c'est pourquoi il est bon de le spécifier, sur la classe, l'attribut MarkupExtensionReturnType (qui prend en paramètre le type à renvoyer) qui est utilisé par le parseur XAML à la compilation pour s'assurer que vous assigner un type correct à la propriété sur laquelle l'extension est utilisée:
[MarkupExtensionReturnType(typeof(string))]
Au final, votre classe (le code de votre extension) ressemblera donc à ceci:
[MarkupExtensionReturnType(typeof(string))]
public class CalculateSumExtension : MarkupExtension
{
public double FirstNumber { get; set; }
public double SecondNumber { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (FirstNumber == 0.0 && SecondNumber == 0.0)
{
return "No parameters specify";
}
else
{
return Convert.ToString(FirstNumber + SecondNumber);
}
}
}
Bon développement à tous !
A+
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :