[new:26/07/2010]A chaque génération de Blend l’équipe de Silverlight autant que celle de Expression Blend tentent de rendre la mise en page de plus en plus fluide, vivante et ce avec le moins de code possible (et si possible sans code du tout). Le double but : rendre les applications Silverlight encore plus attractives pour les utilisateurs et rendre Blend utilisable à 100% par un Designer sans mettre les mains dans le code.
Et, en effet, à chaque nouvelle génération les choses se sont améliorées approchant toujours de plus près ces deux buts. Avec Blend 4 et Silverlight 4 nous atteignons un premier palier. Je dis “premier palier” car je me refuse à dire que tout est fait et parfait, ces produits vont continuer à évoluer et à nous surprendre. Mais avec la version 4 Silverlight et Blend sont un peu dans la position du Framework 3.0 où toutes les fondations étaient enfin posées (WPF est introduit dans la V 3.0 notamment). Cela ne signifie pas qu’après les choses sont moins intéressantes, bien au contraire, mais simplement qu’un sentiment de “complétude” nous touche quand on regarde l’édifice. Le Framework 2.0 ou Silverlight 2.0 (même numéro mais coïncidence) ressemblaient un peu la Sagrada Familia de Barcelone : quelque chose dont on voit clairement les formes, l’allure, mais qui, dès qu’on s’approche, montre que la fin des travaux n’est pas encore pour tout de suite ! Aujourd’hui nous entrons dans l’âge de raison pour Silverlight et Blend.
La mise en page dynamique
Je ne vais pas vous parler de toutes les nouveautés de Blend 4 / Silverlight 4, j’y reviendrai certainement dans de prochains billets, mais d’un aspect essentiel pour les applications Web (mais aussi pour les téléphones) : supporter une mise en page fluctuante.
- Fluctuante en fonction des dimensions physique du support (écran du PC, du notebook, du téléphone…),
- fluctuante en fonction de la cinématique même de l’application (changement de page, ouverture et fermeture de panneaux…) et enfin
- fluctuante en fonction de la dynamique des données (apparition de nouvelles données, modification, suppression de données…).
- On pourrait même ajouter les fluctuations liées à l’utilisateur (préférences, droits d’accès…) qui peuvent aussi impacter la mise en page d’une application.
Bien entendu les animations sont présentes depuis Silverlight 1, et depuis la version 2 et l’introduction d’un vrai langage de programmation (C#, ou même VB sont de loin supérieurs à JavaScript), il est possible à tout développeur un peu rusé de concevoir des transitions et des effets visuels donnant de la vie à l’application. Avec Silverlight 4 et Blend 4 on peut simplement aller plus loin et plus vite.
Donner vie au cycle de vie de l’information
Car les mises en page dynamiques (englobant tous les aspects listés plus haut) confèrent avant tout une meilleure visibilité au cycle de vie de l’information. Quand dans une liste un item disparaît ou apparaît, cela est instantané. Si la liste est l’élément d’interface principal et que l’utilisateur à les yeux rivés dessus il verra quelle ligne vient de disparaitre ou d’apparaitre. Mais si l’utilisateur n’est pas concentré à ce moment précis sur l’interface ou bien si la liste en question n’est qu’un des éléments du visuel de l’application, peut-être ne s’apercevra-t-il de rien du tout !
Cette vitesse, cette instantanéité, nous l’avons tous recherchée pendant des années : chaque développeur consciencieux essayant de rendre son application plus “réactive”, plus “rapide” que celle du concurrent, luttant contre la lenteur de PC n’ayant pas la puissance dont il rêve… Mais ces temps sont révolus, les machines d’aujourd’hui ont plus de puissance et de mémoire qu’il n’en faut pour traiter la compatibilité de cent PME à la fois. Du coup, il reste de la puissance disponible pour s’attacher à un autre aspect que la pure fonctionnalité : le visuel et “l’expérience utilisateur” la fameuse UX des américains (User eXperience).
Ainsi, dans notre liste, l’instantanéité de l’arrivée ou de la sortie d’une nouvelle ligne n’est pas forcément un avantage. Le fait d’arriver ou de disparaitre est aussi une information pour une ligne, son contenu n’est pas la seule information existante qui doit être véhiculée à l’utilisateur…
Le Design, un gadget ?
Ceux qui pensent (et il y en a encore) que le nouveau paradigme des applications “designées” n’est qu’un gadget, un artifice de vente pour les commerciaux ou de la simple “frime” n’ont rien compris et passent à côté de l’essentiel.
Le fait pour une information de naître ou de mourir, de passer d’un état à un autre (et pas seulement d’être dans tel ou tel état) est aussi une information essentielle pour l’utilisateur et comme toute information elle doit être mise en valeur (selon son degré d’importance fonctionnelle) !
Le Design d’une application est une étape désormais incontournable. Non seulement parce qu’il rend l’application plus “attractive”, mais surtout parce qu’il permet de mettre l’information en valeur au lieu de mettre la technique en avant. Le temps des techniciens, des tripoteurs de bits est morte, celle des designers arrive…
Et Silverlight 4 ?
Peut-être certains penseront qu’une fois encore en éternel bavard je me perds dans des digressions au lieu d’aller à l’essentiel : la technique.
Je ne leur dirai pas de passer leur chemin, au contraire ! Je prêche aussi (et surtout ?) pour que ceux-là m’entendent ! Et il convient donc de ne pas les chasser ni de leur jeter la pierre, ou alors juste une petite … Car la “technique” nous sommes en plein dedans ! Ce qui peut échapper à certains c’est que la “technique” a changé ! Et que ce qui était hors de son cadre il y a dix ans fait aujourd’hui partie intégrante de ces bases.
Le passéisme n’est finalement pas tant le fait de rester accroché aux valeurs d’un passé idéalisé que d’être aveugle aux changements et aux évolutions…
Un peu d’archéologie !
La préhistoire (an 2007)
Dès sa naissance, Blend offre la possibilité de créer des animations pour Silverlight et WPF sur la base des StoryBoards, en manipulant des des KeyFrames. C’est la base de tout ce qui suivra. Les nouvelles fonctionnalités auront pour base des Storyboards écrit par le développeur, d’autres vont construire ces StoryBoards, et d’autres utiliseront les deux approches.
L’histoire ancienne (an 2008)
Dans Blend 2 SP1, les équipes Blend et Silverlight introduisent le Panneau d’états “States Panel” qui permet de créer et de gérer les VisualStates et les VisualStateGroups (Silverlight 2 et WPF 3.5 avec le Toolkit).
C’est ici qu’à été introduite la notion d’état définie comme un moyen de communication entre le code et le visuel et comme une simplification énorme dans la description et l’utilisation des différents états visuels.
Le code peut décider en fonction de ses entrées de passer dans un état ou un autre. L’état signale ainsi de façon simple et avec un nom explicite une situation qui elle peut découler de conditions ou calculs complexes. Sous cet angle un état est un niveau d’abstraction utilisé par le code pour avertir “l’extérieur” sur ce qu’il vient de faire, ce qu’il s’apprête à faire, sur ce qui est possible de faire ou sur ce qui est impossible à faire. Les états sont généralement à double sens, c’est à dire qu’il est possible, depuis l’extérieur du code, de faire changer ses états internes en fixant un nouvel état global.
Du côté de l’interface, les états sont des “constats” d’une situation qui peuvent être pris en compte pour modifier l’aspect de l’affichage. Aucun code n’est nécessaire, tout se fait grâce à un intermédiaire : le panneau des états derrière lequel se cache le VSM (Visual State Manager).
Le VSM permet même de fixer un temps global ou ponctuel pour gérer automatiquement des transitions entre les différents états visuels.
Le VSM a toutefois ses limites. Par exemple il ne peut calculer que des interpolations linéaires entre deux valeurs numériques. Il ne marche pas vraiment pour les propriétés prenant des valeurs discrètes (énumérations par exemple) ou pour des données qu’il ne peut connaître à la conception.
Histoire récente (an 2009)
L’équipe de Blend a beaucoup travaillé sur ces limitations et dans la version 3, elle a ajouté de nombreuses améliorations. La première concerne les EasingFunctions qui permettent d’ajouter un peu de “crédibilité” visuelle aux animations. Effet d’amortissement, ralentissement progressif, rebonds élastiques, tout cela s’ajoute simplement à toute animation par le biais d’un menu présentant de façon graphique les diverses fonctions disponibles (en entrée d’animation, en sortie ou bien les deux). Les EasingFunctions sont applicables à une KeyFrame donnée ou une animation et un easing par défaut peut être défini globalement pour toutes les animations découlant d’un même changement d’état (transition).
La seconde idée introduite dans la V 3 est celle de comportement (les behaviors). L’un des tous premiers est justement le GotoStateAction permettant de programmer les changements d’état du code sans avoir à utiliser de code-behind (C# ou VB). De fait l’interface de passive (faisant le constat d’un changement d’état du code) devient active en autorisant la modification de l’état du code.
La troisième idée consiste en l’ajout du FluidMoveBehavior. Ici c’est tout un ensemble de nouveaux scenarii qui sont concernés. Par exemple les éléments d’un StackPanel sont amenés à changer de position suite à un redimensionnement, l’ajout ou la suppression d’un contrôle dans leur collection. Aucun procédé simple n’existait pour gérer ce type de situation. Cela était possible, mais à la condition de le faire par code. Un code souvent complexe, très spécialisé et peu souple (sauf à entrer dans un développement démesuré).
Le FluidMoveBehavior vient ici combler une lacune en automatisant de façon simple et déclarative des transitions animées lorsque les éléments enfants d’un conteneur changent de taille, de position, naissent ou meurent. Le tout contrôlé par les EasingFunctions pour plus de réalisme et d’attractivité visuelle.
Bien plus que d’étendre les possibilités de Blend, c’est bien un pas de géant en plus qui est fait dans la direction d’une programmation visuelle réalisable par un Designer sans l’aide de code.
Mais il restait encore quelques scenarii inaccessibles au système d’animation de Blend malgré ces évolutions essentielles. Par exemple il était impossible d’animer un changement entre Visible et Collapsed… Dès qu’on souhaitait cacher un élément ou le rendre visible il fallait jouer sur son opacité. Or cela n’a pas le même effet : un élément Collapsed est “retiré” visuellement : sa place devient libre et d’autres contrôles peuvent remplir l’espace vacant.
Après certainement pas mal de recherches, l’équipe de Blend créa la quatrième bonne idée introduite dans Blend 3 : le FluidLayout.
Il suffit de cliquer sur ce petit bouton dans le panneau du VSM et tous les changements de mise en page dans le VisualStateGroup considéré seront animés (changements d’état) même lorsque cela paraît impossible, comme pour une propriété Visibility.
Techniquement le FluidLayout prend un cliché de la mise en page avant la transition et un autre après (ce qui est non visible heureusement, ce sont des opérations internes) et il créé un morphing entre les deux clichés… Cela permet d’animer et de rendre “fluide” des transitions qui, autrement, étaient brutales.
L’histoire présente (an 2010)
Avec Blend 4 l’idée principale était, au sujet des animations, d’aller encore plus loin sur la voie tracée par les améliorations judicieuses de la V3.
LayoutStates
Par exemple, prenons le cas d’une liste et de ses items. Comment rendre l’arrivée ou la sortie d’un item plus attractive qu’un simple changement instantané (voir ce que je disais bien plus haut à ce sujet) ?
La première solution, grâce aux nouveautés de la V3, consiste à utiliser un FluidMoveBehavior. C’est déjà pas si mal. L’entrée d’un nouvel item se fera doucement : les items présents vont, grâce au FluidMovebehavior, se pousser gentiment pour lui faire de la place. Lors de la sortie d’un élément les items présents viendront tout aussi gentiment combler le trou laissé par le partant.
Mais au-delà de cette parade (déjà efficace) il n’était pas forcément facile de réellement contrôler l’élément entrant ou sortant. Les développeurs les plus malins pouvaient, en bricolant plusieurs événements, arriver à contrôler, au moins partiellement, l’entrée d’un item. Mais il fallait être sacrément rusé (et au top niveau de l’utilisation de Silverlight, Xaml et Blend) pour trouver une solution à la situation inverse (la sortie d’un item). Et encore cela au prix d’un incroyable déploiement d’efforts et de codes alambiqué.
Pour pallier ces cas assez courant, l’équipe de Blend a travaillé avec l’équipe Silverlight. La solution s’appelle les “LayoutStates”. Ils sont bien cachés et nul doute que vous ne les découvrirez pas tout seul juste en regardant Blend…
Pour les trouver il faut aller les chercher là où ils se cachent, c’est à dire là où la solution a été implémentée en éditant le ItemContainerStyle du contrôle (ListBox par exemple).
Pour l’instant rien de spécial… mais si vous regardez attentivement le panneau du VSM vous découvrirez 3 nouveaux états :
Grâce à ces nouveaux états vous pouvez contrôler ce à quoi ressemble un item juste après s’être chargé, juste avant d’être chargé ou juste avant qu’il ne soit déchargé (retiré de la liste).
Silverlight créera automatiquement les animations voulues lorsque ces transitions auront lieu, c’est à dire quand des items seront ajoutés ou retiré de la liste.
La fonction est puissante mais bien cachée. Plus vicieux, elle ne fonctionnera que si vous ajoutez un FluidMoveBehavior au template de l’ItemsPanel en n’oubliant pas de fixer sa propriété AppliesTo à la valeur Children. Sinon les autres items (en dehors de celui concerné par sa propre entrée ou sortie) ne seront pas animés. Les LayoutStates s’entendent donc comme un complément au FluidMoveBehavior pour créer un effet visuel complet.
Pour compliquer un tout petit plus le tableau, il faut signaler que si l’ItemsPanel est de type VirtualizingStackPanel la propriété VirtualizinStackPanel.VirtualizationMode de la Listbox devra être fixée à la valeur “Standard”.
Ce n’est pas très simple tout cela, mais en le pratiquant on comprend mieux. Et puis il faut se rappeler qu’on est là dans le raffinement, dans des comportements visuels complexes qui étaient, avant ces améliorations, réellement très difficiles à coder.
ci-dessus, un exemple de LayoutStates utilisés pour permettre aux items entrants d’arriver dans une sorte de basculement 3D.
TransitionEffects
La V3 de Blend ajoutait le FluidLayout qui permet d’animer des changements d’état qui n’étaient pas “animables” , comme par exemple les propriétés discrètes de type Visibility. La solution retenue utilise un morphing entre l’image de départ et celle d’arrivée.
Dans Blend 4 l’équipe de développement a voulu aller un cran plus loin dans cet esprit. Ainsi apparaissent les TransitionEffects.
Si vous pensez aux logiciels d’édition vidéo, vous connaissez sûrement les effets de transition qu’on peut ajouter entre deux séquences ou deux images (pour faire un slideshow à partir d’un album photo par exemple). Dans ces logiciels les transitions sont des calculs basés sur les pixels constituants les images des deux séquences entre lesquelles prend place la transition. Avec les TransitionEffects de Blend 4, on obtient dans le même esprit un calcul de transition basé sur les pixels pour assurer le passage d’un état à un autre.
Prosaïquement, un TransitionEffect sous Blend 4 est un PixelShader (comme l’ombre portée, le floutage…) qui a une propriété Progress animable.
Blend 4 est livré avec plusieurs effets de transitions mais comme pour les PixelShaders, si vous savez coder en HLSL vous pouvez écrire les vôtre et les ajouter à votre palette !
Ci-dessous on voit comment la transition par défaut du groupe “LayoutStates” d’un contrôle est fixé à “Smooth Swirl Grid” (“grille de tourbillons lisses'”), sur une durée de 1 seconde avec un easing cubique… Quand on pense à la complexité de ce qui est accompli par ces quelques clics on mesure à quel point Blend est un outil essentiel et pourquoi je me tue à répéter que Visual Studio n’est pas l’outil adapté au développement de la partie visuelle d’applications Silverlight ou WPF.
L’image ci-dessous capture l’effet réglé plus haut en pleine transition (on devine le morphing entre les images de départ et d’arrivée et on voit nettement l’effet de “smooth swirl grid”) :
FluidMoveTagSetBehavior
Ici on entre dans le jardin secret de la team Blend, son fantasme fou, en passe d’être réalisé, de pouvoir faire les animations les plus extravagantes sans aucun code !
Selon l’équipe elle-même, cela faisait 5 ans qu’il cherchait une solution à un problème tout bête : ils s’étaient aperçus, perspicaces qu’ils sont, que très souvent des éléments sont animés d’un endroit à l’autre d’une application mais que ces éléments ne sont pas seulement des petits dessins ou des contrôles posés sur le artboard, puisqu’ils peuvent aussi être générés depuis des données.
Seulement voilà, dans la paradigme MVVM qui s’impose sous Silverlight et WPF, le Model (les données) ne doit absolument rien savoir à propos du visuel (View). Et cela peut devenir très sportif d’essayer de programmer ce type particulier d’animations sans casser le modèle MVVM et sans truffer le ViewModel de code qui n’a normalement rien à y faire.
La solution retenue pour Blend 4 consiste à faire en sorte que ce soit le visuel qui, d’une façon ou d’une autre, en sache plus sur les données qu’il traite. Ce qui est parfaitement licite en MVVM (le visuel doit même forcément connaître les données puisque sa raison d’être est de présenter convenablement ces dernières…).
C’est en rendant le FluidMoveBehavior plus souple que la solution est venue : en lui permettant d’associer des positions non plus seulement avec des éléments visuels mais aussi avec des données.
Dit comme ça, c’est assez flou, j’en conviens, toutefois c’est très facile à utiliser, une fois qu’on a compris la façon de procéder.
Voici l’image d’une application exemple fournie par Microsoft et illustrant ce nouvel effet visuel :
Ici nous avons, à gauche, une ListBox contenant des données avec un ItemTemplate personnalisé montrant le nom et le prix de l’article ainsi qu’une miniature de celui-ci. A droite nous avons un panneau de détail affichant l’article sélectionné en grand, avec des explications en plus etc (on pourrait supposer un site marchand, l’ajout au panier…).
Le but du jeu est de faire apparaitre l’article qui se trouve dans la partie détail par une animation depuis sa miniature, comme si cette dernière grossissait tout en venant se placer dans la partie de droite.
la ListBox est alimentée par des données “vivantes”, le système d’animation doit donc s’adapter à ctete situation particulière, c’est tout le challenge de cette nouveauté.
Et comme je le disais plus haut, en réalité c’est très simple à réaliser. Dans un premier temps il faut localiser l’élément à animer dans l’ItemTemplate de la ListBox (la miniature) puis de lui ajouter un FluidMoveTagSetBehavior. Ce behavior va avoir pour rôle d’enregistrer la miniature dans le moteur de FluidMove. Placer le behavior se fait comme suit :
La propriété Tag du behavior indique “DataContext”, ce qui signifie que l’item sera marqué en fonction de son DataContext qui est le modèle se cachant derrière le visuel. Ce n’est donc pas le contrôle image lui-même qui est taggé mais la donnée qui se cache derrière.
Maintenant il faut prendre l’image se trouvant dans la partie détail de l’écran (la grande image de droite) et lui ajouter un FluidMoveBehavior :
C’est là qu’entre en jeu la partie “Tag Properties” de ce behavior… InitialTag pointe aussi le DataContext (qui est le même pour la liste et la fiche détail). Cela signifie que lorsque l’item du détail apparaitra il devra prendre en considération comme point de départ la position enregistrée de son DataContext. La connexion est ici effectuée entre l’image détail et la miniature de la ListBox. En réalité la liaison s’opère, comme on le voit, entre Le FluidMoveBehavior de la grande image (détail) et le FluidMoveTagSetBehavior qui décore la miniature dans le data template des items de la Listbox.
Et le tour est joué !
L’image ci-dessous montre comment la chaise rouge semble partir depuis la position de l’item sélectionné dans la ListBox pour rejoindre sa place à droite de l’écran :
On s’en doute un peu, avec une poignée de propriétés c’est une animation d’une grande complexité qui est réalisée, et le travail de développement derrière ces effets visuels est à la hauteur de cette sophistication. Automatiser de façon générique ce type d’animation réclame beaucoup de code, mais surtout beaucoup de savoir-faire. On veut bien croire que l’idée a pu nécessité 5 ans avant de prendre forme.
Bien entendu on ne voit ici qu’un simple exemple. Le procédé est utilisable de mille façons, comme par exemple pour donner l’impression qu’un élément passe d’une ListBox à une autre.
Plus fou ?
Si, ça existe. Dans Blend 4 aussi. Un truc complètement délirant. Ca s’appelle la PathListBox.
C’est tellement fou qu’il m’est bien impossible de résumer ses possibilités sans doubler la taille de ce post déjà bien long… La PathListBox est une ListBox, certes, mais en fait c’est autre chose. Elle possède bien des items, mais elle sait les animer, en rond, en carré, en suivant un tracé vectoriel quelconque, elle peut servir à animer un objet le long d’un chemin (plus rien à voir avec une listbox donc), ou bien à présenter les lettres d’un mot en arrondi, en vague, en n’importe quoi (loin d’une listbox encore). Bref c’est un contrôle délirant. J’essayerai d’en parler prochainement, quand je serai sûr d’avoir tout compris de ces ruses (elles sont nombreuses) et si j’arrive à condenser ça de façon intelligible. Il existe un tutor assez complet sur le site “.toolbox” (ainsi que beaucoup d’autres choses intéressantes).
Conclusion
La mise en page dynamique et les transitions sont des piliers visuels des applications Silverlight et WPF. Savoir donner de l’importance aux états de l’application, à l’apparition ou la disparition d’éléments, aux changements de forme, de position, de couleurs de blocs visuels ou d’éléments isolés, tout cela s’appelle le Design. Loin d’être juste un embellissement graphique, le Design fait partie du cycle de développement d’un logiciel moderne dans le sens où il s’attache à trier les informations essentielles, à donner un sens aux états, une lisibilité aux données produites par le code.
Il n’y a pas d’un côté le travail sérieux que serait le codage et de l’autre une tâche accessoire, supplémentaire et un peu futile que serait le Design. Je croise encore trop souvent des développeurs qui sont dans cet état d’esprit. C’est peut-être d’ailleurs pour ça qu’ils ne sont que développeurs dans la hiérarchie, un manque de vision, la peur d’être détrôner, que sais-je… Mais encore une fois ne les blâmons pas. Tous ne pourront être sauvés mais en expliquant et en expliquant encore je crois que certains finiront par comprendre.
Quant à ceux qui ont déjà compris, j’espère que ce petit tour d’horizon de certaines (seulement certaines) nouveautés de Blend 4 et Silverlight 4 leur donnera envie de tester au plus vite ces effets pour les mettre en pratique, et surtout, au service des données que leurs applications produisent!
Stay Tuned !