La contrainte des valeurs est un mécanisme essentiel permettant de maintenir la valeur d'une propriété dans des bornes fixées par l'objet ou par l'utilisateur. Cela permet de respecter l'encapsulation, un principe fondamental de la programmation orientée objet. Contrairement à Silverlight mais tout comme WPF, MAUI supporte nativement la coercition de valeurs à travers ses propriétés Bindable.
La Contrainte de Valeur (Value Coercion)
Le principe est simple : lorsqu'une propriété ne peut pas prendre n'importe quelle valeur, il faut mettre en place un mécanisme pour valider et maintenir la valeur dans les bornes acceptées. Validation et contrainte sont deux concepts distincts. Valider une valeur consiste à vérifier qu'elle appartient à l'ensemble des valeurs "légales". Par exemple, un Entry peut être utilisé pour saisir un entier. La validation vérifie que ce qui est tapé est bien un entier, rejetant la saisie contraire.
La contrainte de valeur, quant à elle, se concentre sur la validité contextuelle de la valeur au moment où elle est changée. La valeur doit être "acceptable" dans le contexte global de l’objet sans le déstabiliser.
Coercition et Propriétés CLR
Pour illustrer la coercition de valeur, commençons par un exemple "naïf" utilisant des propriétés CLR. Dans cet exemple, nous avons une propriété Age dont la valeur doit être comprise entre 1 et 130 ans. La coercition est effectuée dans le setter de la propriété :
private int age;
public int Age
{
get { return age; }
set
{
if (value < 1 || value > 130) return;
age = value;
}
}
Ce code montre une coercition simple où les valeurs en dehors de la plage autorisée sont rejetées. Cependant, cette approche n'a pas d'effet "mémoire" : une fois la valeur invalidée, elle n'est pas restaurée lorsque les contraintes sont levées. C'est un filtrage plus qu'une contrainte au sens des propriétés de dépendance de WPF (et donc de MAUI).
Coercition et Propriétés Bindable dans MAUI
MAUI utilise les propriétés Bindable pour gérer les valeurs des propriétés de manière plus sophistiquée, similaire aux propriétés de dépendance dans WPF. Une propriété Bindable est déclarée avec une propriété CLR correspondante. Par exemple :
public class MyStateControl : BindableObject
{
public static readonly BindableProperty StateProperty = BindableProperty.Create(
nameof(State), typeof(bool), typeof(MyStateControl), false);
public bool State
{
get { return (bool)GetValue(StateProperty); }
set { SetValue(StateProperty, value); }
}
}
Les propriétés Bindable dans MAUI peuvent gérer plusieurs couches de valeurs avec des priorités différentes. Cela permet de simuler l'effet "mémoire" comme décrit précédemment. Par exemple, un contrôle Slider avec des propriétés Minimum et Maximum peut gérer la coercition de manière efficace :
public class MySlider : BindableObject
{
public static readonly BindableProperty ValueProperty = BindableProperty.Create(
nameof(Value), typeof(double), typeof(MySlider), 0.0,
coerceValue: (bindable, value) =>
{
var slider = (MySlider)bindable;
double newValue = (double)value;
if (newValue < slider.Minimum)
{
return slider.Minimum;
}
else if (newValue > slider.Maximum)
{
return slider.Maximum;
}
return newValue;
});
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public double Minimum
{
get { return (double)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public static readonly BindableProperty MinimumProperty = BindableProperty.Create(
nameof(Minimum), typeof(double), typeof(MySlider), 0.0);
public static readonly BindableProperty MaximumProperty = BindableProperty.Create(
nameof(Maximum), typeof(double), typeof(MySlider), 1.0);
}
Implémenter la Coercition dans MAUI
Pour déclarer une propriété Bindable dans .NET MAUI avec une expression lambda de coercition, suivez ces étapes :
1. Créer une propriété Bindable :
- Dérivez votre classe de BindableObject.
- Déclarez une propriété publique statique en lecture seule de type BindableProperty.
- Définissez cette propriété en utilisant BindableProperty.Create.
- Spécifiez un identifiant, le type de la propriété, le type de l'objet possédant et une valeur par défaut.
2. Ajouter la logique de Coercition :
- La coercition garantit qu'une valeur reste valide dans des scénarios spécifiques.
- Dans votre déclaration de propriété bindable, définissez le paramètre coerceValue sur une expression lambda qui effectue la coercition.
- L'expression lambda prend la nouvelle valeur en entrée et retourne la valeur contrainte (Il est bien entendu possible de déclarer une méthode au lieu d'utiliser une expression Lambda, toutefois cette dernière étant intégrée au code même de la déclaration de la propriété cela garantit un code plus compact et plus maintenable).
public class MyClass : BindableObject
{
public static readonly BindableProperty MyProperty = BindableProperty.Create(
nameof(MyProperty),
typeof(int),
typeof(MyClass),
defaultValue: 0,
coerceValue: (bindable, value) =>
{
// Logique de coercition
int coercedValue = (int)value;
return coercedValue > 0 ? coercedValue : 0;
});
public int MyProperty
{
get { return (int)GetValue(MyProperty); }
set { SetValue(MyProperty, value); }
}
}
Vous pouvez maintenant utiliser MyProperty dans XAML ou dans le code-behind. L'expression lambda de coercition assurera des valeurs valides.
Conclusion
MAUI fournit une prise en charge native pour la coercition des valeurs via les propriétés Bindable, permettant ainsi de maintenir l'intégrité des valeurs des propriétés dans divers scénarios. Cela permet de respecter les principes de l'encapsulation et de la programmation orientée objet, assurant ainsi la robustesse et la fiabilité des applications développées avec MAUI. Grâce à ce support, il est possible de gérer efficacement les contraintes de valeurs, offrant une solution élégante et intégrée pour les développeurs. Les propriétés de dépendance sont souvent mal comprises et mal utilisées. Le fait que le XAML MAUI soit très riche doit vous inciter à en utiliser toute la puissance. Un code utilisant habilement les propriétés de dépendance et leur système de coercition évitera beaucoup de "bricolage" pour maintenir la validité des propriétés des objets au runtime. Pensez-y !
Stay Tuned!