Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Silverlight : Contrainte de propriétés (Coercion)

[new:20/11/2010]La contrainte des valeurs est un mécanisme essentiel permettant à la valeur d'une propriété de rester confiner dans des bornes fixées par l'objet ou par l'utilisateur. C'est en réalité un des éléments de base permettant de respecter le paradigme de la programmation objet : l'encapsulation qui veut qu'un objet se protège de toute action externe pouvant le déstabiliser. Hélas, Silverlight n'offre pas les mécanismes que WPF propose pour les propriétés de dépendances. Nous allons voir comment régler cet épineux problème.

 

La Contrainte de valeur (value coercion) 

Le principe est simple : quand une propriété ne peut pas prendre n'importe quelle valeur, il faut mettre en place un mécanisme de protection pour valider et maintenir la valeur dans les bornes acceptées par le contexte. Validation et contrainte sont d'ailleurs deux choses assez différentes qui se traitent parfois ensemble mais qui doivent être comprises comme deux actions distinctes fonctionnellement parlant.

Valider une valeur consiste à vérifier qu'elle appartient à l'ensemble des valeurs "légales". Par exemple un TextBox peut être utilisé pour saisir un entier. La validation consiste ici à vérifier que ce qui est tapé est bien un entier et à rejeter la saisie dans le cas contraire. Le Framework propose certaines validations automatiques (ou explicites) et met à disposition du développeur d’autres mécanismes comme des attributs pouvant décorer les propriétés d’un DataContract.

La contrainte de valeur est plus limitative, elle considère que la valeur qui lui est donnée appartient bien déjà à l'ensemble des valeurs légales (elle a été validée), ce qui lui importe c'est uniquement de savoir si la valeur est "acceptable" à l'instant précis où elle est changée, c'est à dire si elle est conforme à ce que le contexte global de l’objet considéré peut accepter sans que cela ne le déstabilise.

 

Il ne faut pas voir ici un absolu, cette séparation validation / contrainte est récente et la gestion des contraintes, historiquement, à longtemps été considérée comme faisant partie des validations. La différence faite ici repose sur celle qui est mise en place au sein du Framework principalement sous WPF (et que nous allons mettre en oeuvre sous Silverlight).

 

Coercition et propriétés CLR

 

On appelle propriétés CLR les propriétés déclarées en suivant la syntaxe classique du langage dans lequel on développe (C#, VB.NET...). En C# les propriétés s'écrivent sous la forme d'une déclaration de type et de nom agrémentée d'un getter et d'un setter comme le montre l'exemple ci-dessous: 

 

private int age;
int Age { get { return age;} set { age=value;}} 

 

Dans ce petit morceau de code on utilise "age" qui est un champ entier privé qu'on appelle un "backing field". Il existe des variantes déclaratives que nous n’aborderons pas ici car tel n’est pas le sujet de cet article.

 

La validation telle qu'expliquée en début d’article n'a pas de sens dans un tel contexte puisque C# est un langage dit fortement typé et qu'il repose sur un Framework ayant la même caractéristique. De fait le setter de la propriété Age ne recevra jamais rien d'autre qu'un entier, tout code voulant lui envoyer une valeur d'un autre type sera sanctionné à la compilation. La propriété ne peut ici recevoir qu’une valeur licite (mais ce n’est pas forcément toujours le cas).

En revanche ici la coercition de la valeur a tout son intérêt. S'agissant d'un âge, et en supposant qu'il n'existe aucune autre contrainte fixée par le contexte ou le cahier de charges, il semble raisonnable d'interdire les valeurs inférieures à 1 et celles supérieures à disons 130 ans.

Pour une propriété CLR l'implémentation de la coercition est évidente, le setter (qui masque une méthode Set_<nom de la propriété>) est justement étudié pour cela - entre autres). Ainsi, notre code exemple deviendra : 

 

int Age 
      { get { return age;} 
        set { 
              if (age<1 || age>130) return;
              age=value;
            }
      } 

Il s'agit d'une coercition simple, dite par exclusion. On pourrait en débattre longtemps mais stricto sensu  la valeur n'est pas vraiment contrainte ici; on ne fait que rejeter les valeurs interdites. La coercition sous-entend qu'on "bloque" la valeur soumise tant qu'elle est interdite et que la propriété pourra reprendre toute seule la valeur saisie si jamais elle redevient valide.

 

Nota: Je traduis ici Coercion par Coercition, ce qui semble raisonnable. Toutefois le verbe lui-même est très peu utilisé, et s'utilise principalement sous la forme d'un adjectif dans l'expression "mesure coercitive" qui a un sens négatif. On pourrait utiliser le verbe "contraindre" et le mot "contrainte" à la place de "Coerce" et "Coercion" mais j'ai préféré conserver la traduction la plus proche, pour une fois qu'il existe un mot français de même sens ou presque...

 

un meilleur exemple pour comprendre cette nuance subtile mais essentielle se trouve dans tous les objets proposant des propriétés de type "mini/maxi" bornant les valeurs possibles d'une troisième propriété (généralement appelée Value mais tout dépend de l'objet et de son utilité).

 

Le contrôle Slider illustre parfaitement cette pattern classique. On retrouve les propriétés Minimum et Maximum ainsi qu'une propriété Value qui ne peut prendre qu'une valeur comprise dans les bornes définies par les précédentes.

 

Imaginons que nous utilisions un Slider ayant pour bornes 0 et 10. Sa Value étant initialisée à 6. Changeons le Maximum pour le descendre à 4. En toute logique le changement de valeur de la propriété Maximum, en dehors de ses propres contrôles, doit déclencher ceux de la propriété Value pour s'assurer qu'elle reste bien confinée dans les bornes définies, ce qui n'est ici plus le cas.

Dans le modèle de propriété CLR la coercition s'exercera dans le setter de la propriété Maximum avec un code du type :

 

// ... setter de Maximum
  maximum = value;
  if (value>maximum) value=maximum;
  // appel de propertychanged de maximum ET de value
// ... suite

C'est simple et efficace. Cela fonctionne comme dans l'exemple de la propriété Age plus haut, sauf que la coercition est effectuée dans le setter d'une autre propriété que celle qui est "bornée". Ici, le changement de Maximum à la valeur 4 entraînera le passage de la propriété Value à 4 aussi puisque sa valeur (6) se trouve désormais en dehors des bornes. Bien entendu cela n’exclue pas le besoin d’effectuer un test similaire dans le setter de la propriété Minimum pas plus qu’il ne faut oublier d’implémenter de même type dans le setter dans la propriété Value elle-même.

 

Ce modèle est tellement simple que si nous changeons à nouveau Maximum pour mettre sa valeur à 6, la propriété Value restera à 4. Il n'y a en effet aucun effet "mémoire". Pourtant si la valeur était à 6 et que seuls sont intervenus les deux changements indiqués de Maximum (vers 4 puis vers 6), la propriété Value devrait reprendre sa valeur 6, à nouveau valide et inchangée. En effet, puisque l'utilisateur n'a pas modifié volontairement la valeur de Value directement, elle ne devrait pas être modifiée définitivement par la coercition que nous avons appliquée qui devrait se comporter comme une force de compression, qui une fois relâchée laisse la valeur « s’étirer » à nouveau.

Or, avec les propriétés CLR, sauf à développer un code complexe pour chaque propriété, un tel comportement n'existe pas par défaut.

 

Coercition et propriétés de dépendances

 

XAML et ses possibilités nombreuses (tel que le Binding) a obligé les concepteurs du Framework à réfléchir sur d'autres façons plus sophistiquées de gérer les valeurs des propriétés. Cela a débouché sur la mise en place du moteur des propriétés de dépendances (et des propriétés attachées - ou jointes). Une propriété de dépendance (DP : dependency property), comprendre "interdépendante", accepte simultanément plusieurs valeurs qui se trouvent à des niveaux de priorité différents. Par exemple une animation pourra imposer une série de valeurs dans le temps à une propriété, mais lorsque l'animation s'arrêtera la propriété reprendra la valeur qu'elle avait à l'origine, avant le lancement de l’animation. Dans mon article "Le Binding Xaml, sa syntaxe, éviter ses pièges… (WPF/Silverlight)"  ainsi que dans celui portant sur les propriétés de dépendances "Les propriétés de dépendance et les propriétés jointes sous WPF" j'ai longuement expliqué ces nuances et j'y renvoie le lecteur qui souhaite approfondir ces notions.

Pour ce qui nous intéresse ici rappelons ainsi qu'une propriété de dépendance se déclare de façon spécifique et qu'elle est généralement "doublée" par une propriété CLR de même nom. Les mécanismes en place pour enregistrer et gérer une propriété de dépendance ne sont pas implémentés dans le langage lui-même mais dans le Framework. De fait, une propriété de dépendance n'est pas "visible" directement pour du code classique. D'où la nécessité de déclarer une propriété CLR qui ne fait que dialoguer avec la propriété de dépendance afin de rendre celle-ci plus facilement accessible au travers du code et conserver une cohérence de nommage et d’accès à la valeur de la propriété. Ci-dessous un exemple simple de déclaration d'une DP avec sa propriété CLR :

 

public class MyStateControl : ButtonBase
{
  public MyStateControl() : basea() { }
  public Boolean State
  {
    get { return (Boolean)this.GetValue(StateProperty); }
    set { this.SetValue(StateProperty, value); } 
  }
  public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
    "State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}

Les propriétés de dépendances gèrent plusieurs couches de valeurs comme nous l'avons dit. Il existe donc déjà un effet "mémoire" comme celui évoqué plus haut. Il est donc naturel que la coercition s'exerce de façon complète et non de façon simpliste comme pour les propriétés CLR. Dans l'exemple du Slider que nous avons utilisé plus haut le passage du Maximum de 10 à 4 puis de 4 à 6 doit faire varier dans un premier temps la propriété Value à 4 puis à 6, sa valeur originale redevenue licite.

 

Pour rendre cela possible il faut considérer qu'il existe en réalité deux valeurs pour une propriété : sa valeur réelle et sa valeur bornée. En fait le mécanisme fait intervenir une méthode pour en assurer la coercition. Cette méthode est un Callback passés lors de l'enregistrement de la propriété de dépendance au travers d’une structure de métadonnées. Le reste, notamment l'effet "mémoire", est géré par le moteur des propriétés de dépendance du Framework car il n’y a techniquement pas besoin de conserver une copie de la valeur non bornée. La coercition doit ainsi se comprendre plutôt comme un filtre en lecture, la valeur est lue au travers du filtre ce qui donne l’impression qu’il y a deux valeurs, la « vraie » stockée dans l’objet, la « bornée » retournée par la coercition, supprimons le filtre et la « vraie » valeur semble « revenir » par magie. En réalité elle a toujours été là et c’est l’effet du filtre qui donne l’impression qu’elle a pris d’autres valeurs.

 

Silverlight ne supporte pas la coercition

Hélas pour nous, et de façon assez incompréhensible il faut le dire, le Framework Silverlight ne supporte pas la même structure de métadonnées pour les DP que WPF, il manque le callback de coercition. Certes il fallait bien couper des fonctionnalités pour passer d'un framework complet de plusieurs dizaines de méga au plugin Silverlight, et ce découpage chirurgical a été majoritairement effectué de main de maître avec une grande subtilité, mais il y a des ratés... La suppression du callback de coercition dans Silverlight interdit tout bonnement à un objet de type Slider de pouvoir borner les valeurs qui lui sont passées ce qui fait un peu désordre (car cela brise l’un des piliers du paradigme objet, l'encapsulation).

 

Les mauvaises réponses au problème

 

Vous allez me dire que ce n'est pas vrai, que le Slider de Silverlight fonctionne parfaitement et gère bien la coercition de la propriété Value. Prenez un outil comme Reflector et décompilez le code de la classe Slider... vous verrez alors la complexité de la solution mise en œuvre pour simuler la coercition !

 

Microsoft pouvait certes ponctuellement déléguer certains de ces développeurs pour régler le problème dans une seule propriété d’un seul composant, mais la méthode choisie est bien trop complexe pour être industrialisable dans un projet mettant en œuvre plusieurs propriétés de ce type. D’ailleurs Microsoft ne communique pas sur cette « solution » qui n’est documentée nulle part sauf à utiliser un décompilateur et à étudier le code original du Framework Silverlight…

 

La réponse de Microsoft dans le composant Slider est donc une mauvaise réponse au problème car elle n'est pas réutilisable (non industrialisable) et non documentée. De plus, si nous y regardons de plus près, le comportement de la propriété Value n’est pas exactement celui qu’il devrait être, il y a un léger bogue dans ce code très complexe... L’application de démo suivante montre le problème.

 

Pour bien comprendre il faut savoir que la valeur Minimum est considérée comme un point de repère car il faut bien choisir une règle au risque de se retrouver dans une situation ingérable d’un point de vue logique. Par exemple si on augmente le Minimum, il finira par « pousser » la Value jusqu’à l’amener en butée contre le Maximum. Et si on continue ce mouvement le Minimum entraînera Value et Maximum vers la droite. Si on maintenant on prend la situation inverse et que l'on diminue le Maximum, ce dernier poussera bien Value qui sera bien amenée en butée contre le Minimum mais si on continue le mouvement on sera bloqué : le Minimum ne peut pas être descendu en le « poussant » avec le Maximum.

C’est arbitraire, les concepteurs du Framework aurait pu prendre la logique contraire (faire du Maximum le point de repère immuable). En revanche il serait difficile de considérer Minimum et Maximum comme des points fixes tout comme n’en considérer aucun comme étant le point fixe. Réfléchissez à la mise en œuvre logique de l'algorithme et vous comprendrez mieux j’en suis certain.

 

Dans l’exemple ci-dessous regardez aussi le comportement de la valeur lorsqu’elle est « compressée » par la monté du minimum ou la descente du maximum puis lorsque que cette « pression » est relâchée : la valeur reprend progressivement sa valeur originale mais avec des « sautes ». C'est le bogue évoqué plus haut.

 

[silverlight:source=/SLSamples/Coerce/CoercionDemoBase.xap;width=450;height=94]

 

Quelques explications : ce qui est montré est le comportement des trois propriétés Maximum, Minimum et Value et principalement le mécanisme de coercition à l'oeuvre lorsqu'on ne touche pas à Value et que l'on augmente ou diminue à l'extrême la valeur d'une des bornes puis qu'on la remplace à sa valeur de départ. Le Silder qui est "testé" en quelque sorte par cette démo se trouve tout à droite. Il ne ressemble plus à un Slider mais à rectangle de couleur affichant la valeur courante de Value. C'est un Slider tout à fait "normal" qui a été templaté pour l'occasion. Nous testons son code et non son look. Les trois Slider horizontaux permettent de matérialiser les trois valeurs testées (maxi, mini et valeur). Chacun d'eux est bindé à la propriété correspondante du Slider templaté et reflètent donc son état courant. Comme ces bindings sont en two-way, on peut agir sur les Slider pour modifier l'état du Slider testé, ce qui, en retour, peut faire varier la position des Slider horizontaux qui réagissent aux changements d'états des propriétés auxquelles ils sont liés. La procédure de test consiste donc ici à augmenter le Minimum jusqu'à l'amener en butée à droite, puis à le refaire descendre et observer le comportement du Slider Value durant ces opérations (ainsi que celui de Maximum). La deuxième étape consiste à refaire la même chose avec Maximum (en le poussant en butée à gauche cette fois-ci). Vous noterez que lorsque vous remettez progressivement le maximum ou le minimum à leur valeur d'origine, Value va elle aussi descendre ou monter pour reprendre progressivement sa position d'origine. Dans l'implémentation de la coercition du Slider de Silverlight il y a un bogue qui fait que Value n'a pas un déplacement graduel et continue, elle effectue des bonds.

Une autre mauvaise réponse classique à ce problème consiste à modifier le setter de la propriété CLR pour implémenter la coercition.

Effectivement lorsqu’on modifiera la valeur par code, puisque ce dernier va généralement passer par la propriété CLR, la valeur sera bien bornée puisque passant par le setter de la propriété (bornée mais pas contrainte avec mémoire de la valeur saisie, c’est l’exemple de la propriété Age en début d’article).

Hélas c'est bien mal comprendre comment les DP fonctionnent ! Seul le code (C# ou autre) peut voir la propriété CLR, lorsque le changement de valeur s'effectue par un mécanisme XAML tel que le Binding par exemple, la propriété CLR est totalement ignorée et le code de coercition avec... la propriété CLR déclarée en doublon d'une DP n'est là que pour en simplifier l'accès, son getter et son setter ne doit rien contenir d'autres que les appels à Set/GetValue de la DP. C'est donc une (très) mauvaise réponse au problème, pire que celle de MS dans le Slider car là, cela ne fonctionne même pas totalement... Cette mauvaise solution pose d’ailleurs, et en plus, les mêmes problèmes que la suivante.

 

La troisième façon classique de se tromper devant ce problème épineux consiste à utiliser le callback de changement de valeur de la propriété de dépendance qui lui existe aussi bien sous SL que sous WPF. Erreur grossière... En effet, dans le code en question nous sommes dans un "changed" et non pas un "changing". Les règles de nommage dans le Framework ont fait l'objet d'un long travail de la part de l'équipe qui l'a écrit. Je vous conseille d'ailleurs la lecture de "Framework Design Guidelines. Conventions, Idioms, and Patterns for Reusable .NET Libraries" écrit par ceux qui ont fait le Framework et qui expliquent comment et pourquoi les choses sont ce qu'elles sont. Les créateurs du Framework y avouent aussi leurs mauvaises idées, leurs échecs, ce qu'ils auraient du faire autrement, c'est un retour sur expérience incroyablement riche et instructif (mais en anglais...). Bref l'utilisation du passé dans les événements est une norme indiquant que ce qui est notifié à déjà eu lieu là où le présent indique une action en cours pouvant éventuellement être annulée. "changed"' implique donc que la valeur est déjà enregistrée par la DP, l'événement n'est là que pour nous permettre d'en prendre note si cela vous intéresse.

 

Implémenter la coercition à cet endroit aura un premier effet négatif : modifier la valeur dans le changed fera entrer le code dans un mode récursif pas très sain. Mieux vaut éviter ce genre de montage risqué qui fait pédaler dans le vide le logiciel ce qui, au fil des erreurs de ce type le rendra peu réactif (en dehors d'autres ennuis comme un plantage). Mais ce n'est pas tout... Pour une DP un Binding est au niveau "valeur locale" (Cf mon article sur les DP) et une valeur fixée par code est aussi considérée comme une valeur locale. Vous commencez à comprendre le malaise ? Non ? ... En fixant par code une valeur locale le moteur de DP va effacer et remplacer la valeur locale en cours puisque sur un niveau de priorité donné d'une DP il ne peut y avoir qu'une seule valeur. Moralité si un Binding était présent il sera perdu définitivement ! Impossible de le retrouver sauf à relancer le logiciel ou bien à implémenter un code redondant recréant le Binding original. Implémenter la coercition de valeur dans le callback changed est donc une erreur qui débouche sur des bogues insolvables de perte des Bindings en place.

 

 

Une solution ?

J'en ai vu quelques unes, toutes sont plus complexes les unes que les autres et en réalité aucune ne fonctionne correctement, ce sont des bricolages plus ou moins sophistiqués. Et toutes ont le même défaut que l'implémentation de Microsoft dans le Slider : être trop complexes et totalement ingérables sur de nombreuses propriétés (et présentant le plus souvent des écueils du même type).

 

J’ai aussi beaucoup réfléchi à ce problème car rien ne me choque plus que de ne pas pouvoir développer un contrôle capable de protéger ses propriétés, c'est-à-dire renoncer au 3ème millénaire et en utilisant les outils à la  pointe du progrès à toute une partie de ce qui fait les bases in-négociable de la programmation objet. Mes réflexions m’ont amené à tester divers modèles plus ou moins satisfaisants. Au final on s’aperçoit que la seule vraie solution est de simuler la fonctionnalité manquante, notamment en modifiant les métadonnées des propriétés de dépendance de Silverlight pour y ajouter le fameux Callback manquant (et réussir à interférer avec le moteur pour prendre en compte ce nouveau Callback, ce qui n’est pas une mince affaire).

Mais on ne « tripatouille » pas les méandres du moteur de DP de Silverlight comme ça ! Il s’agit d’un exercice de style assez complexe. De plus, il semble souhaitable d’adopter une solution compatible avec WPF, c'est-à-dire capable de détecter sous quel environnement elle est compilée pour exploiter les facilités de WPF et les simuler sous Silverlight. Produire un code portable WPF/Silverlight est un objectif qu’on ne doit jamais perdre de vue. La convergence SL/WPF dont j’ai parlé souvent ici en étant parfois mal compris par certains lecteurs est une réalité avérée désormais, chaque nouvelle version de SL est plus compatible avec WPF que la précédente et lui "vole" au fur et à mesure des points forts (comme la création d'applications desktop, l'automation COM, etc). Donc concevoir un code portable SL/WPF devient ainsi en toute logique une obligation dans l’optique du respect du paradigme de la réutilisabilité du code.

Malgré les différences dans les Frameworks il est bien plus intelligent de se forcer un peu pour écrire un contrôle portable une fois (et maintenable au sein d’un seul et même code) que de s’apercevoir qu’il faut le récréer totalement (et avoir deux codes à maintenir) pour l’utiliser dans l’autre environnement…

 

Toujours à la recherche d’une solution « propre » à ce gros problème je fouine régulièrement sur le Web pour voir si quelques solutions nouvelles sont apparues. Comme je le disais plus haut je déchante assez vite. Mais dernièrement j’ai découvert un code (récent) qui, s’il a lui aussi une certaine complexité (puisqu’il faut suppléer une fonction de base du Framework) répond à toutes les exigences : cohérence du fonctionnement, simulation exacte du comportement attendu, portabilité WPF/Silverlight et simplicité d’utilisation.

 

C’est cette solution, plus aboutie que mes propres essais, que je vais vous présenter maintenant.

Pourquoi alors avoir terminé le titre de ce paragraphe par une point d'interrogation plutôt qu'un point d'exclamation... C'est que tant que Microsoft n'aura pas implémenté cette fonction essentielle, tout ce qu'on pourra faire pour la suppléer ne sera que bricolage, plus ou moins savant, plus ou moins pratique. La solution que je vous propose répond au besoin, reste assez simple à mettre en oeuvre car l'auteur fournit des snippets pour écrire le code automatiquement, mais cela n'est pas une vraie solution définitive. Toutefois elle fonctionne et permet même de régler le bogue visible dans le Slider de SL. C'est déjà pas mal et c'est pour cela que je vous la présente.

 

Mais pour mieux comprendre tout ceci je vous propose de "jouer" avec le même exemple SL que celui présenté plus haut mais réécrit en utilisant le code de coercition de « Dr WPF », c’est ainsi qu’il se fait appeler sur son blog (et impossible d’en savoir plus sur ce mystérieux personnage puisque même le nom de domaine de son site est déposé via tiers d’anonymisation ! Si cela se trouve il travaille chez Adobe ou Apple et ne veut surtout pas être démasqué J).

Testez les mêmes mouvements des trois Slider pour voir la différence de traitement.

 

[silverlight:source=/SLSamples/Coerce/CoercionDemo.xap;width=450;height=94]

 

Le Fonctionnement

Il s’agit d’un code très subtil dont les mécanismes sont un peu longs à disséquer en totalité. Si vous avez un niveau de compréhension assez élevé de C# et du Framework, alors il est préférable d’étudier le code par vous-même. Et si vous n’avez pas ce niveau mes explications vous embrouilleraient certainement encore plus…

Mais de très haut, car il faut bien en dire quelque chose sinon cela serait vraiment frustrant, le principe repose sur l’idée que j’ai déjà évoquée dans ce billet : remplacer la classe de métadonnées permettant de définir une DP par une classe plus complète intégrant le callback de coercition. Le tout en mimant la syntaxe de WPF pour la portabilité.

Bien entendu cela n’est pas réellement suffisant puisque Silverlight ne saurait quoi faire des informations supplémentaires. Donc, sous SL uniquement, la librairie initialise une sorte de hook qui lui permet d’avoir la main pour traiter le callback. Le cheminement réel est un chouia plus compliqué que cela, regardez le code, il n’est pas très gros, la difficulté réside dans son niveau d’astuce plus que dans sa taille…

La solution est « clean » elle ne fait aucune entorse ni « bricolage » coupable qui pourrait poser des problèmes. Toutefois je ne saurais vous offrir plus de garanties que l’auteur lui-même, c'est-à-dire en de tels cas : aucune (voir la licence d’utilisation) Laughing.

 

Le code

 

Vous trouverez le code à télécharger sous deux formes, un projet de démonstration (les trois Slider version corrigée) ainsi qu’un ensemble de snippets à installer dans Visual Studio. Ces dernières contiennent à la fois le code de la classe principale (mais vous pouvez tout simplement reprendre le fichier qui se trouve dans le code de la démonstration) et de nombreuses variantes de déclaration de DP, ce qui est beaucoup plus intéressant puisque cela évite une frappe fastidieuse tout en gérant (ou non, c’est au choix) le fameux callback de coercition.

 

Le billet présentant l’ensemble se trouve ici : http://drwpf.com/blog/2010/05/05/value-coercion-for-the-masses/

Il est accompagné d’une vidéo d’un quart d’heure qui illustre bien la solution proposée (attention, c’est en anglais et le son est tellement compressé que la voix de robot qui en résulte peut être difficile à comprendre si vous n’êtes pas réellement fluent en english…). Cela n'est certainement pas le fruit du hasard, Dr WPF ne semble pas souhaiter pas qu'on reconnaisse sa voix non plus...

Vous trouverez aussi le billet suivant : http://drwpf.com/blog/2010/05/08/metadata-options-for-silverlight/ qui dévoile un peu plus les dessous de la solution adoptée (notamment dans le support des flags d’options utilisés pour la déclaration des métadonnées).

Pour ceux qui ne comprennent vraiment pas assez l’anglais pour s’y retrouver voici le lien direct de téléchargement de la démo : http://drwpf.com/blog/Portals/0/Samples/CoercionDemo.zip et celui de la librairie de snippets (exécuter le fichier, il y a un expert d’installation assez simple à comprendre qui se lance) : http://drwpf.com/blog/Portals/0/Reference/DrWPFSnippets.zip 

 

  

Conclusion

 

 

Il est grand temps que l’équipe de Silverlight nous fournisse une vraie solution (elle existe, c’est celle de WPF) pour nous éviter d’avoir recours à de telles extrémités. D’un autre côté, tant que cette solution intégrée au Framework n’existe pas il est hors de question de concevoir des contrôles qui ne sont pas capable de répondre aux exigences les plus élémentaires de l’encapsulation. Alors remercions le mystérieux Dr WPF pour ce code de très bon niveau qui apporte une solution viable et industrialisable tout en étant compatible avec WPF. Il est étrange que Dr WPF se cache à ce point et cherche à masquer son identité jusqu’au dépôt de nom de domaine de site, jusqu'à maquiller sa voix sur la vidéo. Mais c'est son choix. 

Restons sur ce mystère et surtout le plaisir de disposer d’une solution exploitable à cet énorme problème que pose la coercition de valeur sous Silverlight !

 

Pour le reste, vous connaissez le refrain : Stay Tuned !

 

Faites des heureux, partagez l'article !
blog comments powered by Disqus