Vous êtes sur la page 1sur 505

Rfrence

Silverlight
Conception dapplications interactives riches
http://www.free-livres.com/
ric Ambrosi

Pratique de

Rseaux et tlcom Programmation Dveloppement web Scurit Systme dexploitation

Pearson Education France a apport le plus grand soin la ralisation de ce livre afin de vous fournir une information complte et fiable. Cependant, Pearson Education France nassume de responsabilits, ni pour son utilisation, ni pour les contrefaons de brevets ou atteintes aux droits de tierces personnes qui pourraient rsulter de cette utilisation. Les exemples ou les programmes prsents dans cet ouvrage sont fournis pour illustrer les descriptions thoriques. Ils ne sont en aucun cas destins une utilisation commerciale ou professionnelle. Pearson Education France ne pourra en aucun cas tre tenu pour responsable des prjudices ou dommages de quelque nature que ce soit pouvant rsulter de lutilisation de ces exemples ou programmes. Tous les noms de produits ou marques cits dans ce livre sont des marques dposes par leurs propritaires respectifs.

Publi par Pearson Education France 47 bis, rue des Vinaigriers 75010 PARIS Tl. : 01 72 74 90 00 www.pearson.fr

dition et et mise en pages : Dominique Buraud

ISBN : 978-2-7440-4125-9 Copyright 2010 Pearson Education France Tous droits rservs

Aucune reprsentation ou reproduction, mme partielle, autre que celles prvues larticle L. 122-5 2 et 3 a) du code de la proprit intellectuelle ne peut tre faite sans lautorisation expresse de Pearson Education France ou, le cas chant, sans le respect des modalits prvues larticle L. 122-10 dudit code. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc.

Table des matires


Prface Partie I Approche de Silverlight 1. Introduction Quest-ce que Silverlight ? De .Net 1 Silverlight Les avantages de Silverlight La suite Expression Studio Positionnement mtier 1.5.1 Designer interactif 1.5.2 La chane de production 1.6 Langages de dveloppement et choix 1.6.1 Langages accessibles 1.6.2 CLR, DLR et langages non compils 1.1 1.2 1.3 1.4 1.5 2. Le couple XAML / C# 2.1 XML 2.1.1 quoi sert le XML ? 2.1.2 La grammaire 2.1.3 Lambigut des relations familiales 2.2 XAML, un langage dclaratif puissant 2.2.1 Lutilit du XAML 2.2.2 Comparaison XAML / C# 2.2.3 Afficher un visuel XAML 2.2.4 Espaces de noms 2.3 Les fondamentaux du langage C# 2.3.1 C# et lAPI Silverlight 2.3.2 Introduction la programmation oriente objet 2.3.3 Une premire application en mode console 2.3.4 Les types 2.3.5 Dclarer des mthodes 2.3.6 Hritage et implmentations 3. HelloWorld 3.1 Une premire application Silverlight 3.2 Architecture d'une solution 3.3 Le conteneur racine 1 2 3 4 6 7 7 8 9 9 10 13 13 13 14 15 16 16 17 18 19 20 20 21 22 23 31 34 37 37 40 42 IX

IV

Table des matires

3.4 Ajouter du texte 3.4.1 Crer le champ texte 3.4.2 Alignement 3.5 Tester et compiler 3.5.1 Premire compilation 3.5.2 Une application 100 % Silverlight 3.5.3 Fichiers gnrs 3.5.4 Processus de compilation 4. Un site plein cran en 2 minutes 4.1 Les projets de type site Internet 4.2 Crer des conteneurs redimensionnables 4.2.1 Crer le pied de page 4.2.2 Crer le menu du haut 4.2.3 Crer la grille centrale 4.3 Le composant bouton 4.3.1 Dfinir un nom dexemplaire 4.3.2 Afficher une bulle dinformation au survol 4.3.3 Choisir un curseur de survol personnalis 4.3.4 La proprit Content 4.4 Ajouter de linteractivit 4.4.1 Utiliser les comportements 4.4.2 Mode plein cran 4.4.3 Spcificits du mode plein cran 4.4.4 Dtecter le changement daffichage 4.5 Fichiers dploys 5. Larbre visuel et logique 5.1 Composants visuels 5.1.1 Familles de composants 5.1.2 Arbre dhritage des classes graphiques 5.2 Principe dimbrication 5.2.1 Ordre dimbrication 5.2.2 Accder aux objets de larbre visuel 5.2.3 Parcourir la liste des enfants 5.3 Ajouter des enfants la liste daffichage 5.3.1 Mcanisme dinstanciation dobjets graphiques 5.3.2 Ajouter et insrer des objets dans larbre 5.3.3 Erreurs leves 5.3.4 Crer un menu dynamique 5.3.5 Affecter les proprits Child et Content 5.3.6 vnement diffus 5.4 Supprimer des objets de larbre visuel 5.4.1 Les diffrentes mthodes 5.4.2 Leffondrement de la liste denfants 5.4.3 Dsactiver des objets 5.4.5 vnement diffus 5.5 changes dindex 5.5.1 change dindex du point de vue conception 5.5.2 Une mthode dextension pour UIElementCollection 5.5.3 change dindex du point de vue design

42 42 43 44 44 45 47 49 51 51 53 53 55 60 61 61 62 63 64 67 67 69 70 71 72 73 73 73 75 81 81 83 87 91 91 92 94 95 97 98 99 99 100 103 104 105 105 106 108

Table des matires

Partie II Interactivit et cration graphique 6.Animations 6.1 Introduction 6.1.1 Quest-ce quune animation? 6.1.2 La cadence des animations au sein de Silverlight 6.1.3 Une premire animation 6.1.4 Les diffrents types danimation 6.1.5 Les diffrents types dinterpolation 6.1.6 La classe Storyboard 6.2 Animer avec Expression Blend 6.2.1 Les bonnes pratiques 6.2.2 Crer une animation dintroduction 6.2.3 Dclencher des animations 6.2.4 Les transformations relatives 6.3 Grer lacclration 6.3.1 Les principes 6.3.2 Une animation de rebond en une seule cl danimation 6.3.3 Amliorer lanimation dintroduction 6.4 Animer avec C# 6.4.1 Lintrt danimer avec C# 6.4.2 Instanciation dynamique de ressources Storyboard 6.4.3 Affectation dynamique de Storyboards 6.4.4 Dupliquer un Storyboard cr dans Blend via C# 6.5 Les transformations relatives 6.5.1 Principes 6.5.2 Tester la prsence dune instance TransformGroup 6.5.3 Affecter la proprit RenderTransform 6.5.4 La bibliothque ProxyRenderTransform 6.5.5 Effets antagonistes et complmentaires 6.6 Animer des particules 6.6.1 Exemples dun fond sous-marin 6.6.2 Crer lanimation des bulles 7. Boutons personnaliss 7.1 Crer un lecteur vido 7.1.1 Mettre en place le projet 7.1.2 Insrer une image darrire-plan 7.1.3 Le rle du composant Grid 7.2 Style visuel 7.2.1 Crer un style personnalis 7.2.2 Naviguer entre style, modle et application principale 7.3 Bouton gnrique 7.3.1 La proprit Content 7.3.2 Liaison de modles 7.4 Le gestionnaire dtats visuels 7.4.1 volution de lexprience utilisateur 7.4.2 Au sein dun control 7.4.3 Au niveau de lapplication 7.5 Le bouton interrupteur ou ToggleButton 7.5.1 Crer le bouton 7.5.2 Le systme dagencement fluide 113 114 114 115 116 118 120 123 124 124 125 128 129 132 132 133 137 138 138 139 144 146 150 150 151 153 154 158 160 161 165 169 169 170 170 171 172 172 174 177 177 178 183 184 187 196 201 202 203

VI

Table des matires

8. Interactivit et modle vnementiel 8.1 Les fondements du modle vnementiel 8.1.1 Le pattern Observateur 8.1.2 Introduction au couplage faible 8.1.3 Souscrire un vnement en C# 8.1.4 Cas pratique 8.2 Supprimer lcoute dun vnement 8.2.1 Principe 8.2.2 Un cas concret dutilisation 8.3 Le couplage faible en pratique 8.3.1 Principe 8.3.2 Simplifier le code du lecteur vido 8.3.3 Affectation dynamique danimations 8.4 Propagation vnementielle 8.4.1 Principe 8.4.2 Un exemple simple de propagation 8.4.3 viter la diffusion dvnements 8.4.4 Arrter la propagation vnementielle 8.4.5 Glisser-dposer et capture des vnements souris 8.5 Les comportements 8.5.1 Comportements versus programmation vnementielle 8.5.2 Les diffrents types de comportements 8.5.3 Crer des comportements personnaliss 9. Les bases de la projection3D 9.1 Lenvironnement3D 9.1.1 Introduction 9.1.2 Le plan de projection 9.2 Les proprits3D 9.2.1 Rotation3D 9.2.2 Laxe de rotation 9.2.3 Les axes de translation 9.2.4 Accs et modification via C# 9.3 La camra 9.3.1 Position de la camra dans lespace de projection 9.3.2 Langle douverture 9.3.3 Les conteneurs3D 9.3.4 Le point de fuite 9.4 Introduction aux matrices 9.4.1 Dfinition et principes 9.4.2 Les matrices3D 9.4.3 Oprations sur les matrices 9.4.4 Initialiser une vue perspective 10. Prototypage dynamique avec SketchFlow 10.1 Lenvironnement 10.1.1 Le prototypage 10.1.2 Quest-ce que SketchFlow? 10.1.3 Le flux de production 10.2 Prototype simple 10.2.1 Problmatique cliente 10.2.2 Le projet SketchFlow 10.2.3 La carte de navigation

205 205 206 207 208 209 211 211 212 215 215 217 219 220 221 222 223 225 228 232 232 232 234 245 245 246 247 249 249 250 251 253 257 258 259 260 262 263 263 267 269 272 277 277 277 279 282 283 283 284 287

Table des matires

VII

10.3 Le lecteur SketchFlow 10.3.1 Navigation 10.3.2 Collaboration transverse avec SketchFlow 10.4 Interactivit 10.4.1 Importer des fichiers PSD 10.4.2 Navigation utilisateur 10.4.3 Simuler un flux dutilisation 10.4.4 tats visuels 10.5 Interface riche 10.5.1 cran versus composant 10.5.2 Lexemple du configurateur riche Partie III Conception dapplications riches 11. Ressources graphiques 11.1 Quest-ce quune ressource 11.1.1 Dfinition et types de ressources 11.1.2 Les dictionnaires de ressources 11.1.3 Appliquer des ressources 11.2 Les pinceaux 11.2.1 Couleurs et pinceaux 11.2.2 Les pinceaux dimages et de vidos 11.3 Les polices de caractres 11.3.1 Afficher et mettre en forme du texte 11.3.2 Polices personnalises 11.4 Styles et modles de composants 11.4.1 Les styles 11.4.2 Affectation dynamique 11.4.3 Organiser et nommer les ressources 11.4.4 Les modles 11.5 Le modle Slider 11.5.1 Principes et architecture 11.5.2 Un Slider personnalis 11.6 Les liaisons 11.6.1 Crer une liaison 11.6.2 Les donnes fictives 11.6.3 Le contexte de donnes 11.6.4 Paramtres optionnels 11.7 Le modle ListBox 11.7.1 Structure et principes 11.7.2 Modifier lapparence dune liste dlments 11.7.3 DataTemplate versus ListBoxItem 12. Composants personnaliss 12.1 Contrle utilisateur 12.1.1 Un hritage pertinent 12.1.2 Navigation page par page 12.2 Bote de connexion 12.2.1 Conception visuelle 12.2.2 Validation par liaison de donnes

290 291 292 298 298 300 302 303 304 305 306

315 316 316 319 324 327 328 336 340 340 344 348 348 350 351 353 355 356 358 360 360 367 371 374 375 375 377 379 385 385 386 386 390 390 393

VIII

Table des matires

12.2.3 Rafrachissement manuel de liaison de donnes 12.2.4 Notification de changement de proprit 12.2.5 vnements personnaliss 12.3 Contrles personnalisables 12.3.1 ColorChooser et ColorPicker 12.3.2 Crer des contrles 12.3.3 Le contrat de modle 12.3.4 Les proprits de dpendance 13. Mdias et donnes 13.1 Chargement de mdias 13.1.1 Chargement dynamique dimages 13.1.2 Formats vido et modes de diffusion 13.1.3 Un lecteur vido simple 13.1.4 Chargement dynamique de vidos 13.2 Conception MVVM 13.2.1 Principes 13.2.2 Modle 13.2.3 Vue-Modle 13.3 Chargement de donnes 13.3.1 Lobjet WebClient 13.3.2 Introduction LINQ 13.3.3 Expression lambda 13.3.4 Consommer du XML avec LINQ 13.3.5 Charger un flux JSON 13.3.6 Scurit interdomaines Index

398 399 403 409 410 411 413 423 429 429 430 438 444 449 452 452 454 457 459 460 463 467 469 472 477 481

Prface
Cela fait maintenant trois annes que jutilise Silverlight et avant lui WPF. Lorsque lon me demande de qualifier Silverlight, le premier mot qui me vient lesprit est moderne. Moderne, lenvironnement de travail via Expression Blend, logiciel de conception, que lon pourrait qualifier dhyper contextuel, et via Visual Studio port en WPF pour sa version 2010. En tant que concepteur, cest pour moi ce jour le meilleur outil et produit cr par Microsoft. Moderne, le flux de production et les enjeux humains quil engendre dans celle-ci. Silverlight porte en lui une rflexion sur nous-mmes et sur la manire dont nous catgorisons les acteurs de la production et leurs comptences. Que lon soit dveloppeur, graphiste, designer, architecte, directeur technique ou artistique, il est impossible de rester insensible cette mutation qui sopre autour de nous. Jusqu rcemment, le design graphique ne concernait pas ou peu le monde du dveloppement applicatif, mais le Web et son volution ont servi de catalyseur et ont bouscul nos habitudes de production. Moderne enfin, parce que Silverlight reprsente le fer de lance des technologies dans ce domaine et quil chappe aux habitudes et aux clichs. Les applications voluent et, de ce fait, la communication qui a souvent fait dfaut dans le pass entre techniques et cratifs est remise en jeu. Les frontires seffacent diffrents niveaux. Ainsi, une application perue comme riche, lest indpendamment de son support ou de son contexte de diffusion, quelle soit bureautique ou Internet. Ainsi, dveloppeurs et designers prouvent aujourdhui la ncessit de communiquer et de travailler de concert pour obtenir des applications de meilleure qualit. Lun sans lautre, ils ne peuvent plus rpondre au renouvellement constant des problmatiques clientes. Ainsi, les comptences de chacun ne sont plus enfermes et catgorises aussi simplement quauparavant. Silverlight offre, de ce point de vue, un environnement de dveloppement performant, robuste et complet. Il ne se contente pas de porter lexistant .Net dans une application compile pour le Web ; il correspond pleinement lvolution des murs et des attentes des internautes et leur propose de nouvelles expriences enthousiasmantes. Ce livre est bti sur ces principes, cest une rfrence pratique de Silverlight qui vous accompagnera en production. Il sadresse aux designers interactifs, aux dveloppeurs ainsi qu tous les concepteurs souhaitant apprendre le framework Silverlight. Il expose les principes et concepts de cette plateforme et les illustrent par de nombreux exemples tlchargeables. Il sarticule autour des deux axes de conception que sont le design et le dveloppement, et les met en perspective lun par rapport lautre. Si vous tes designer interactif, ce livre vous donnera une meilleure comprhension des contraintes lies au dveloppement dapplications. Il vous immergera progressivement dans lunivers du dveloppement orient objet tout en vous apportant les cls de la conception graphique propre Silverlight. Si vous tes dveloppeur, il vous sensibilisera aux contraintes nouvelles en matire de design, de prototypage et dexprience utilisateur. Il facilitera le dialogue et la communication avec les autres acteurs de la production. Quel que soit votre cas, cet ouvrage est conu pour fluidifier vos productions et tablir les bases dune rflexion intermtiers respectueuse de chaque profil.

Prface

Prrequis
Ce livre sadresse deux types de public diffrents : les designers et les dveloppeurs. La difficult est progressive. Toutefois, quelques sections peuvent sadresser lun de ces profils en particulier. Ainsi, ne vous formalisez pas sur certains termes utiliss car mme sans pratiquer le design ou le dveloppement, il est ncessaire dapprendre le vocabulaire propre ces mtiers pour communiquer avec chacun des acteurs dune production. Dans cette optique, les copies dcran dExpression Blend sont en anglais. Il nest cependant pas ncessaire de connatre la langue de Shakespeare pour comprendre ce livre. De manire plus gnrale, il est conseill davoir des notions basiques en cration graphique ou en dveloppement quel que soit le langage et le niveau technique. Ce livre se positionne comme un ouvrage dapprentissage en mode pas pas. Les trois premiers chapitres ainsi que celui ddi SketchFlow (Chapitre 10) sont les seuls qui ne ncessitent a priori aucune des disciplines mentionnes prcdemment.

Organisation de ce livre
Cet ouvrage se compose de trois parties :

Partie I, Approche. Cette partie du livre donne une vision globale de la technologie Silverlight et de son positionnement. Nous y dcouvrons larchitecture de la plateforme ainsi que son histoire. Nous crons notre premier projet Silverlight et nous y abordons les principes lmentaires de conception lis Silverlight. Nous la clturons par un tour dhorizon des composants fournis par la plateforme et nous concevons un premier site brut plein cran. Partie II, Interactivit et cration graphique. Cette partie saxe essentiellement sur le graphisme et linteractivit au sein de Silverlight. Lanimation, le modle vnementiel, la conception dinterfaces graphiques, la personnalisation graphique de composants ou encore la 3D, sont autant de sujets tudis. En fin de partie, nous abordons la conception de prototypes dynamiques via la technologie SketchFlow. Partie III, Conception dapplications riches. Le flux de production, le positionnement mtier et larchitecture reprsentent les thmes de cette partie. Au cur de ceux-ci, nous tudierons notamment la conception de contrles, lorganisation et le rle des ressources responsables de la rpartition des tches de chacun, ainsi que le modle de conception MVVM et le chargement de donnes externes.

Les exemples
Ce livre contient de nombreux exemples sous forme dexercices, de projets et de fichiers divers dont la majorit est tlchargeable sur le blog ddi au livre ainsi que sur le site de lditeur Pearson. Le blog est conu dans le but de mettre jour les projets et de garder un contenu vivant et cohrent. Il est disponible ladresse http://referencesilverlight.tweened.org. Certains projets doivent tre rcuprs sur ce dernier avant de pouvoir vous lancer. Il est organis sous forme de treize catgories dont chacune correspond un chapitre. Elles donnent accs diffrents articles contenant les sources, les projets et certains schmas tlchargeables. Plusieurs composants et autres classes sont en tlchargement libre et peuvent vous aider dans vos productions. Certains

Prface

XI

des contrles ont t rcemment ajouts la bibliothque SLExtensions ou fondus avec ceux dj existants. Dans tous les cas, ils sont accessibles sur mon blog http://www.tweened.org via la catgorie Composants.

Conventions typographiques
Les conventions typographiques adoptes dans ce livre sont les suivantes :

Police fixe. Cette police met en valeur les lments du langage. Dans les extraits de code, cette police met en exergue les modifications apportes aux programmes.
NOTE INFO

Police fixe grasse.

Ce type de note fournit des prcisions en marge du texte.

ATTENTION

Cette icne vous met en garde sur un point prcis.

propos de lauteur
Issu dun cursus scientifique Paris VII, puis dune formation aux mtiers de la production audiovisuelle et de la post-production, ric Ambrosi est co-fondateur de lcole Europenne Suprieure dAnimation, rebaptise cole Mlis, dont il fut le responsable pdagogique de 1999 2003. Il devient par la suite concepteur dapplications Web 2.0 Flash / Flex et responsable technique sur les outils de mobilit pour la socit Atos Origin jusqu fin 2006. Il est aujourdhui responsable pdagogique et directeur technique chez Regart.net pour les plateformes Microsoft Silverlight et WPF. Il a t nomin deux fois MVP, une premire fois en tant que Client Application Developer pour lanne 2008-2009 et une seconde fois comme MVP Silverlight pour lanne 2009-2010.

Remerciements
Je remercie toutes les personnes qui ont cru en moi et mont accompagn tout au long de cet exercice prilleux et fastidieux dcriture. Je remercie galement mes parents et mes beaux-parents qui nous ont soutenus ma femme et moi tout au long de ce parcours. Je remercie tous mes collgues et ex-collgues de Regart.net. Merci donc Fatos et Guylaine, les deux prsences fminines de Regart.net. Un grand merci Vincent Maitray pour mavoir accord les droits de la vido Petit Pan (utilise au Chapitre 13), ralise avec talent en une journe par ses soins. Je remercie galement Matthieu Appriou pour ce joli visuel de premire de couverture que jai repris pour le lecteur multimdia du Chapitre 11. Merci mon collgue Nicolas pour son humour et son soutien durant ces dix derniers mois. Merci Thibault pour toute cette nergie quil diffuse atour de lui. Merci en vrac mes amis, Philippe et Samia, Cyril et Aurlie, Candice et Herv, et Num et Say qui jai pens ces derniers mois. Ils mont support durant tout ce temps

XII

Prface

par leur prsence ou leurs coups de fil mme si je ne les ai vu que de manire entrecoupe. Merci toutes les personnes de Microsoft avec qui je collabore et qui me font confiance. Un grand merci mon ditrice Patricia Moncorg, qui ma permis dcrire ce livre, et ma relectrice Dominique Buraud, avec qui il est vraiment agrable de travailler. Toutes deux forment une trs bonne quipe et mont permis daccomplir ce voyage jusquau bout. Merci mon relecteur ct dveloppement, Thierry Bouquain, compatriote MVP Siverlight qui ma apport beaucoup par ses conseils et le temps quil ma allou. Thierry est co-fondateur de lentreprise Ucaya qui sest illustre sur des projets de Smooth Streaming pour les vnements du Tour de France et de Roland Garros entre autres. Merci Aude Mousset, ma relectrice ct design interactif et amie depuis trois ans, merci donc pour avoir pris le temps de me relire et dtre une force de proposition. Aude est graphiste de formation, experte sur Blend et a travaill pour I-Breed et Microsoft durant ces dernires annes. travers son travail constant et de qualit, elle a ouvert la voie aux designers. Son aventure continue chez MPower en tant que Directrice artistique et Designer interactif. Merci donc vous deux, Aude et Thierry, sans qui le livre ne serait pas ce quil est aujourdhui. Pour finir, je remercie galement ma femme pour son soutien, pour mavoir pouss crire ce livre, et pour sa comprhension dans cette preuve. Merci de nous avoir donn cette jolie Gabrielle qui nous rend tellement heureux. Merci galement pour notre fils qui va natre dans les prochains jours et qui fait dj des siennes ds quil entend le rire de Gabrielle ou la musique autour de nous je vous ddie ce livre.

Un mot des collaborateurs techniques


"La lecture de cet ouvrage renforce ma vision de lvolution des sites Internet. La dimension interaction et design est de plus en plus prsente et devient incontournable pour des sites de qualit. Les bonnes pratiques de dveloppements dcrites ici permettent de bien dmarrer un projet o la mthode de travail et de collaboration entre designer, intgrateur et dveloppeur est un des lments cls du succs." Thierry Bouquain, directeur technique et fondateur de Ucaya.

"En tant que graphiste, Silverlight est un nouveau terrain de jeux explorer. Les possibilits sont multiples, la technologie est puissante, mais sans connaissances techniques cela peut savrer frustrant. Mme si vous ntes pas dveloppeur, faire un pas vers le ct obscur est un vrai plus dans le cadre de projets Silverlight. Que vous produisiez en solo ou en quipe, que vous soyez du ct Blend ou du ct Visual Studio, ce livre est un bon moyen dapprhender le workflow Silverlight. Vous rentrerez rapidement dans le vif du sujet : ric Ambrosi partage sa matrise de Silverlight et vous permet dapprhender des concepts dintgration et de dveloppement via de nombreux cas pratiques, pertinents et complets. Un ouvrage indispensable pour tous les devsigners1 !" Aude Mousset, Directrice Artistique et Designer Interactif pour MPower.

1. Devsigner pour designer + dveloppeur.

Partie I Approche de Silverlight 1


Introduction
Dans ce chapitre, vous dcouvrirez la nouvelle plateforme de diffusion plurimdias interactive Silverlight et les raisons qui ont pouss Microsoft sa conception. Vous apprendrez en quoi Silverlight hrite de la bibliothque .Net et propose un nouveau modle de conception avantageux. Nous voquerons galement la nouvelle suite doutils Expression Studio ddie aux graphistes et aux intgrateurs et comment ceux-ci se positionnent dans la chaine de production. Silverlight laisse aussi bien la place aux langages .Net C# quaux langages libres et dynamiques comme JavaScript. Prendre partie pour lun de ces langages est lune des tapes incontournables de sa prise en main. Nous listerons donc les critres qui orienteront votre choix parmi ceux-ci. De manire gnrale, Silverlight est fait pour amliorer notre quotidien de designer ou de dveloppeur, ainsi que lexprience utilisateur sur Internet. Nous examinerons les moyens mis en uvre pour atteindre ces diffrents objectifs.

Partie I

Approches de Silverlight

1.1 Quest-ce que Silverlight ?


Silverlight est un lecteur Internet existant sous forme de plug-in, anciennement connu sous le nom de WPF/E, initiales de Windows Presentation Foundation Everywhere. Les applications lisibles par ce lecteur sont des fichiers au format xap. Bas sur un moteur vectoriel puissant, il permet dafficher du contenu dynamique et interactif pour le Web. Il facilite la conception et la diffusion dapplications riches sur Internet. Il fait partie de la plateforme de dveloppement .Net (prononcer "dotte net") propose par Microsoft, mais ne ncessite quune fraction hrite de celui-ci pour tre excut, autrement dit, linstallation du lecteur seul suffit. Cette particularit lui permet dtre diffus au sein de nombreux navigateurs sur MacOS, Windows ou Linux (via le projet Moonlight pour Linux, voir Tableau 1.1).
Tableau 1.1 : Navigateurs et systmes supports.

Systme dexploitation Windows 7 Windows Vista WindowsXP SP2 Windows 2000 SP4 Windows Server 2003 / 2008 Mac OS10.4.8+ (PowerPC) Mac OS10.4.8+ (Intel) Linux, FreeBSD, SolarisOS

Internet Explorer8 Oui Oui Oui

Internet Explorer7 Oui Oui -

Internet Explorer6 -

Firefox 2/3 Safari 3/4 Oui -

Oui Oui Oui -

Oui Oui Oui Oui

Oui Oui

Oui

Oui -

Support par le projet Moonlight dvelopp par Novell

Les applications .Net traditionnelles reposent sur la notion de client lourd, cest--dire quelles ncessitent linstallation de la bibliothque .Net. Celle-ci peut peser jusqu195Mo pour la version 3.5. Le lecteur Silverlight chappe ce type de fonctionnement peu souple car cest un environnement dexcution pour les applications de type client lger. Cela signifie que son poids est suffisamment ngligeable (de 4Mo 7Mo selon les systmes dexploitation) lors du tlchargement, pour que son installation soit rapide et les applications excutes trs lgres (souvent infrieure 1Mo). Sous Vista et Windows 7, les droits ncessaires son installation sont moins contraignants pour lutilisateur de la machine cliente. Bien que lon puisse avoir limpression quil sagit dun dtail, les rseaux dentreprises actuels sont souvent constitus de centaines, voire de milliers dordinateurs, et les dploiements qui en dcoulent ncessitent dimportants moyens humains et techniques. Dans ces conditions, le dploiement de clients lgers est une stratgie efficace court et moyen termes puisque les applications dveloppes pour ces plateformes sont de plus

Chapitre 1

Introduction

en plus performantes et puissantes. Malgr un poids ngligeable, Silverlight apporte un environnement de dveloppement complet.

1.2 De .Net 1 Silverlight


Comme nous lavons vu prcdemment, Silverlight est la fois une volution parallle et un hritage de la plateforme de dveloppement .Net (prononc "dotte nette"). Quest-ce que .Net? Quel est son but et comment est-elle ne? Rpondre ces questions nous permettra de mieux comprendre les orientations prises par les quipes dingnieurs ayant particip sa conception et nous permettra plus facilement denvisager les amliorations possibles dans le futur. Il faut remonter le temps jusqu fvrier2002 pour voir la sortie de .Net1.0, livr avec le Service pack 1 de Windows XP. Visual Studio.Net est cette poque, loutil de prdilection pour dvelopper ce type dapplications. .Net est n des besoins dinteroprabilit (entre ancienne et nouvelle technologie) et de portabilit (valable pour les langages et les systmes). Les objectifs sont simples:

Proposer une meilleure plateforme de dveloppement. Apporter un environnement indpendant du rseau ou du langage choisi quels quils soient Visual Basic, C# ou C++, etc. Dlivrer un unique modle de conception quelle que soit la version de Windows: XP, 2000, Windows CE, etc. Concurrencer Java. Faciliter la cration de services web. Accompagner les dveloppeurs et assouplir la mthodologie de dveloppement avec en point de mire lindustrialisation des processus.

Microsoft propose de nombreux systmes dexploitation et .Net uniformise le dveloppement dapplications. Les applications dveloppes en .Net ciblent essentiellement lOS Windows. Par ailleurs Microsoft ralise une premire perce significative pour scinder le design des interfaces et le code logique, grce aux formulaires Windows, surnomms Winforms. Avec ce type darchitecture, apparat la notion de code "behind". Un fichier va contenir le code ncessaire pour fabriquer linterface visuelle. Celle-ci sera simplement cre par de simples glisser-dposer de composants dans la fentre de prvisualisation sous Visual Studio. Un autre fichier contient dsormais le code logique, ou code "behind", sans lequel linterface ne rpondrait pas aux interactions utilisateurs et ne possderait aucune logique. Sorti fin 2005, .Net 2 est une vritable amlioration mais napporte que peu de nouveauts. Il faut attendre janvier 2007 pour dcouvrir .Net 3 qui rvolutionne le dveloppement dapplications sous Windows. .Net 3 nest pas une refonte, mais une extension de .Net2. Cette version apporte, en plus de C#3 ou de technologies comme Linq, de nombreux bnfices rpartis en quatre modules:

WCF (Windows Communication Foundation) facilite la communication entre les applications, les domaines ainsi que partage de bas de donnes. WCS (Windows CardSpace) pour lauthentification des utilisateurs.

Partie I

Approches de Silverlight

WWF (Windows Workflow Foundation) pour lamlioration des flux de production. WPF (Windows Presentation Foundation) comme couche de prsentation.

WPF est la technologie qui nous concerne : Silverlight en est un dveloppement la fois hrit et parallle. On peut considrer que WPF reprsente le futur de la technologie Winforms. Tout en conservant les capacits prcdentes, il intgre les profils du designer et de lergonome qui, dans 90% des cas, taient soit mis lcart, soit relgus au second plan. Microsoft comprend en effet que la fonctionnalit nest plus la seule garantie dune russite commerciale ou technique. De plus en plus dapplications voient le jour et beaucoup sont fonctionnelles. Toutefois, seules trs peu dentre elles y ajoutent lergonomie et lesthtisme, deux facteurs que lon retrouve pourtant dans lindustrie automobile, les tlphones portables et de nombreux autres secteurs. Grce lenvironnement WPF, vous pourrez changer le visuel dune application dans sa globalit. Modifier le design dune barre de dfilement ou dune liste dlments se rvlera trs simple. Tout ceci est ralisable grce WPF et au langage XAML (eXtensible Application Mark-up Language). Le XAML permet de formaliser nimporte quel dessin vectoriel ou composant visuel sous forme de balises XML. Un client peut dornavant configurer le visuel dune application en modifiant des feuilles de styles XAML et y apposer ainsi sa charte graphique sans faire appel lditeur. Certes, ces oprations sont ralisables depuis longtemps en important des bibliothques entires de classes, mais autant dire que les graphistes ntaient pas vraiment prsents dans le processus de cration. Exit donc les interfaces grises, rectangulaires, hrites de Windows3.1. WPF aborde donc avec succs lun des grands chantiers de linformatique moderne: la sparation complte du fond et de la forme, elle dpasse de loin les Winforms sur ce point. Dautres technologies ont galement essay de rpondre cette problmatique: XUL, de la fondation Mozilla, ou encore le langage FXG bas sur SVG du ct dAdobe. WPF a pris de lavance, mais concerne les dveloppements sur systme Windows pour les langages de hauts niveaux. partir de ce constat, une nouvelle problmatique apparat. De manire gnrale Microsoft est avant tout diteur de solutions, quel que soit le systme dexploitation, cest l son cur de mtier. Il se doit donc proposer des solutions indpendantes du systme. Afin de supprimer le couplage existant entre lenvironnement de dveloppement et les systmes dexploitation Windows cibls, WPF/Everywhere voit le jour. Cest lancien nom de code de Silverlight. Lobjectif est clair: puisque lon cre des solutions autant faire en sorte quelles ciblent le plus de systmes dexploitation possibles. Le moyen le plus efficace consiste alors proposer un lecteur Internet sous forme de plug-in. Les navigateurs les plus courants sont cibls en premier, et Silverlight voit finalement le jour en novembre2007. Cette initiative de Microsoft rpond avant tout aux attentes du march actuel qui volue rapidement vers les applications en ligne et rpond au quasi monopole de la plateforme Flash.

1.3 Les avantages de Silverlight


Dvelopper avec Silverlight apporte beaucoup davantages, dont certains ne lui sont pas forcment propres, mais sont plutt relatifs lensemble des technologies asynchrones prsentes sur le Web comme Shockwave, Flash, Silverlight et Ajax. Silverlight est avant tout orient applications interactives riches et, dans ce cadre, il bnficie galement de toute lexprience de Microsoft en matire de dveloppement. Ce serait une erreur de penser que les graphistes sont dlaisss car des efforts importants ont t raliss pour fournir des outils de design et danimations performants. Lors du rachat de Macromedia par Adobe, de nombreux acteurs de talent furent recruts par Microsoft pour atteindre ces objectifs. Voici les avantages les plus significatifs de Silverlight:

Chapitre 1

Introduction

Comportement asynchrone. Ajax est la premire technologie asynchrone au sein du navigateur, mais cest aussi la plus ancienne. Apparu avec Internet Explorer5 en 2001, cette technologie, rapidement adopte, provient dun objet en particulier (Xml HttpRequest) permettant deffectuer des requtes client serveur. La spcificit des technologies asynchrones rside dans le fait quelles ne ncessitent pas le rechargement complet de la page du navigateur la rception des donnes serveur. Lutilisateur peut mme continuer utiliser le reste de linterface sans provoquer derreur. Silverlight possde de nombreuses mthodes asynchrones, plus modernes quAjax permettant non seulement les changes dans un format texte, mais galement dans un format binaire. Ainsi, lchange dimages, de flux vido, de donnes types est possible ; le mode peer-to-peer est galement support. Il ne dpend pas dune technologie serveur spcifique. Il vous suffit dun simple client FTP et le tour est jou. Vous navez pas besoin dune configuration serveur spcifique ou propritaire. Un serveur Apache traditionnel fera trs bien laffaire pour diffuser votre site ou votre application Silverlight. Ouvert aux technologies du Web. Les langages dynamiques, comme JavaScript, ont la capacit de communiquer avec une instance de plug-in Silverlight de manire transparente. La communication est en ralit possible dans les deux sens. De plus la lecture, lcriture ou lenvoi de donnes sont ralisables dans des formats courants, comme XML, ou JSON, de mme que laccs nimporte quel type de technologie ct serveur. On peut ainsi interfacer sans problme une application Silverlight avec des services, ct serveur, cods en PHP, ASP, etc. Il bnficie dune compatibilit multi-environnement. Comme nous lavons dit au dbut de lintroduction, Silverlight est accessible en tant que lecteur sur Mac OS, Windows et Linux (Moonlight) et sur les navigateurs Chrome, Firefox, Internet Explorer6, 7 et8, Safari. Votre application, bien que dveloppe avec Visual Studio, Expression Blend ou mme Eclipse, sera donc visible et accessible au plus grand nombre. Les applications ne ncessitent pas de dploiement. Autrement dit, une fois accessible une adresse donne, lapplication est lisible et excutable au sein des navigateurs par les internautes. Cela est peut tre anodin ou normal si vous travaillez actuellement sur le march du Web, mais la philosophie actuelle (en mutation) consiste encore dployer des clients lourds et des applications locales poste par poste. Dans des rseaux comprenant des milliers de postes clients, le dploiement de telles applications est extrmement coteux en ressources humaines et techniques. Les applications Silverlight apportent une rponse efficace ces problmatiques de diffusion. Les langages logiques .Net supports sont grs. Le code gr (dit aussi manag) est loppos du code interprt. C# ou VB sont des codes compils, JavaScript, PHP, HTML sont interprts. Cela signifie quils sont lus par le logiciel dune machine cliente ou serveur dans le cas de PHP. Pour un langage comme JavaScript, cela se traduit par des diffrences de performances flagrantes selon le navigateur, mais aussi par des diffrences dinterprtations. Dans un site web traditionnel, laspect visuel, ainsi que la version du langage, peuvent donc varier fortement selon les navigateurs (IE, Firefox ou Safari par exemple). Au sein de Silverlight, toutes ces problmatiques sont rsolues, laffichage sera le mme quelle que soit la plateforme, la version du langage reste constante. On obtient galement beaucoup de performances car le langage est gr. la compilation, il est transform et optimis en langage intermdiaire. Par la suite, selon la machine cliente, le systme dexploitation et le navigateur, le lecteur sadaptera pour loptimiser en un langage machine adapt chaque navigateur (voir Chapitre3).

Partie I

Approches de Silverlight

Il contient un moteur daffichage vectoriel puissant. Lensemble des composants ou objets visuels sont vectoriels. Ils sont donc affichs grce au moteur vectoriel Silverlight. De nombreuses problmatiques, comme le poids des fichiers dploys ou encore la gnration dobjets de manire dynamique, sont ainsi rsolues. Les animations vectorielles sont non seulement possibles, mais galement simples raliser. Laffichage de texte avec des polices de caractre embarques, des vidos ou des images est ais mettre en uvre. Les visuels ne sont pas figs sous forme de bitmap ce qui facilite grandement la mise jour des applications et le travail collaboratif. Il amliore la collaboration entre designers et dveloppeurs. Hritant de WPF, Silverlight bnficie de la mme architecture de production. Cela signifie que le langage XAML est prsent pour formaliser lensemble des lments visuels dune application. Tout ce que le graphiste va produire gnre du XAML, de la mise en forme jusquau moindre pictogramme visuel. La consquence directe est que la cration dun composant (ou contrle) personnalis, comme une mire de connexion par exemple, seffectue en deux tapes distinctes compltement autonomes. Les designers interactifs ou les intgrateurs crent les lments visuels et les animations. Le dveloppeur ajoute le code logique. Cest une vision un peu simplifie de la ralit, mais cependant assez proche. Lavantage rside dans le fait que les graphistes participent pleinement la conception. De plus, ce quils produiront sera fidlement rutilis par les dveloppeurs et non recr ou retraduit par ceux-ci. tout moment, les designers pourront mettre jour le visuel sans mettre en danger laspect fonctionnel ou modifier le code logique.

1.4 La suite Expression Studio


La gamme Expression Studio fait partie de la stratgie WPF. Cette suite de logiciels apporte un confort jamais atteint pour le dveloppement dapplications Microsoft. Les objectifs de la gamme Expression Studio sont:

Permettre la cration dapplications riches connectes (Rich Desktop Application) ou dapplications riches pour navigateur (Rich Internet Application) via Expression Web ou Blend intgrant Silverlight. Amliorer la qualit graphique et lergonomie des applications en proposant de nouveaux outils aux profils de type graphiste, intgrateur ou designer dans lenvironnement .Net et Silverlight, tout cela en scindant le fond et la forme. Ces outils facilitent la mise en place de un flux de production reposant sur la collaboration intermtiers. Proposer de nouvelles solutions aux besoins de la "vido la demande" trs prsents sur le Web grce Silverlight, Expression Encoder et au format wmv. Rpondre aux problmatiques traditionnelles propres la cration de site Internet via Expression Web.
NOTE INFO

Pour rappel, Visual Studio est loutil de dveloppement phare de Microsoft. Du point de vue dun dveloppeur et concernant des projets standard, Visual Studio peut tre utilis seul. En effet, il est possible de btir un projet Silverlight sans besoin de logiciels de la gamme Expression Studio (Blend ou Design). Toutefois, cela ne serait pas pertinent, on pourrait en effet se demander quelle serait la valeur ajoute de telles applications? La gamme Expression facilite justement laccs au dveloppement de nouveaux acteurs. Ces nouveaux profils, que sont lintgrateur, lergonome et

Chapitre 1

Introduction

le graphiste, par leur apport, enrichissent de manire considrable lapproche et le ressenti dune application pour lutilisateur. La gamme Expression Studio apporte une ouverture exceptionnelle au monde du graphisme qui, jusque-l, tait laisse de ct. Blend et Design ont donc pour mission de fournir du contenu graphique et interactif, ainsi quune ergonomie accrue en comparaison des applications bureautiques ou Internet standard.

Voici une liste des outilscompris dans la suite:


Expression Web pour la cration de sites Internet ; Expression Blend pour la conception dinterfaces riches ; Expression Design pour la conception graphique vectorielle ; Expression Encoder pour lencodage des fichiers au format wmv en haute dfinition ; Expression Media pour lorganisation et la lecture des mdias ; Visual Studio pour la conception, le dveloppement et larchitecture dapplications.

Pour notre part, nous couvrirons la conception dapplications interactives riches via lutilisation dExpression Blend et de Visual Studio.

1.5 Positionnement mtier


Comme nous le voyons, WPF et les outils de la gamme Expression sont sur le point de bouleverser les modes opratoires existant. La tendance actuelle repose sur un besoin devenu essentiel qui consiste formaliser le graphisme grce des langages dclaratifs de type XML. Il est intressant de noter que ce mouvement, initi par Mozilla avec le XUL et par Adobe avec le SVG il y a quelques annes, est aujourdhui concrtis par Microsoft. Cependant, nous parlons bien de tendance, ce qui signifie que dautres acteurs comme Adobe reprennent la mme direction. Le FXG est la version Adobe du XAML, les deux langages se ressemblent fortement. Lenseignement que lon peut tirer de cette situation est que les modes et flux de production suniformisent et sont en pleine mutation. Les prochaines annes seront riches tous points de vue. Les capacits de Silverlight, Flash et Ajax (et nouvellement XHTML 5) proposer des langages performants et diffuser du contenu innovant seront dcisives. Ce qui est abord dans cette section est donc valable pour tous les acteurs du march quelle que soit leur provenance.

1.5.1 Designer interactif


Au sein de lenvironnement .Net, trois logiciels de la gamme sont le thtre de cette volution: Expression Blend, Expression Design et Visual Studio:

Expression Design concerne essentiellement les graphistes. Il contient lensemble des outils ncessaires la cration vectorielle. Cependant il joue aussi le rle de passerelle et permet dimporter nativement de nombreux types de fichiers dont le format Adobe Illustrator ou le format Photoshop psd. Expression Blend cible avant tout les designers interactifs, les intgrateurs et les designers deXprience Utilisateur. Les ergonomes peuvent aussi dans une certaine mesure crer des maquettes et prototype en partie rutilisables (voir Chapitre 10).

Partie I

Approches de Silverlight

Visual Studio comme outil de dveloppement principal est conue pour les dveloppeurs et possde un puissant outil de dbogage que Blend ne fournit pas. ce jour, il est considr comme lun des meilleurs produits dlivrs par Microsoft.

Le tableau 1.2 indique la localisation de Blend / Design dans la chane de production, ainsi que linvestissement prvoir en fonction du rle de chacun. On remarque que chacun peut lutiliser, Blend tant un outil polyvalent et multiforme.
Tableau 1.2 : Positionnement de Blend au sein de la chane de production.

Outils et niveau dutilisation Rle Expression Design Graphiste Designer interactif Dveloppeur Fort Moyen Aucune Expression Blend Moyen Fort Faible moyen Visual Studio Aucune Faible moyen Fort

Comme on peut sen rendre compte, un nouveau profil merge: le designer interactif. On peut considrer ce profil comme un nouveau genre de designer web. Dans la majorit des cas, cest un graphiste ayant volu et acquis une relle culture de dveloppeur ainsi quune connaissance aigu de lergonomie. Lintgrateur HTML reprsente en partie ce type de profil. Il est la fois confront des langages comme JavaScript, PHP (ralisation de modles) et CSS, tout en conjuguant cette technique une sensibilit de graphiste. La diffrence entre intgrateur et designer interactif repose essentiellement sur la partie animations et transitions. On peut voir le flasher comme designer interactif. Son objectif principal est de coupler le visuel, lergonomie, lanimation et les transitions. Il considre la logique applicative et la fonctionnalit comme importantes, mais coulant de source et plutt dvolues aux dveloppeurs. Au sein des environnements WPF et Silverlight, le designer interactif tient un rle crucial puisquil fait le lien entre les profils situs chaque extrmit de la chane de production. Cest un lment fdrateur. Silverlight et WPF proposent un modle qui facilite la collaboration, mais cest le profil de designer interactif qui formalise et permet cette communication. On pourrait y voir un mlange des genres douteux, mais sans lui, on se retrouverait dans une situation dlicate o les graphistes nauraient finalement que peu dinfluence sur la production.

1.5.2 La chane de production


Tout projet conu avec Blend sinscrit dans le cadre WPF, les applications Silverlight sont un sousensemble de WPF. Cependant, au contraire des applications WPF bureautiques, les applications Silverlight sont multi-plateformes et multi-navigateurs. Les projets Silverlight suivent la logique classique de tout dveloppement applicatif avec un renforcement singulier de la collaboration entre chaque ple mtier. Voici le dtail de chaque tape et son impact mtier:

Cahier des charges. Profils concerns: client, D.A. / D.T., chef de projet, graphistes, dveloppeurs, ergonomes et utilisateur final

Chapitre 1

Introduction

Maquette fonctionnelle et story-boards. Profils concerns: 50% dveloppeurs et 50% graphistes ou ergonomes. Rflexion papier commune sur la disposition des objets de linterface et sur lergonomie de lapplication. La navigation et la cinmatique doivent tre penses ce stade. Squelette technique et maquettage. Les collaborateurs du projet sont dans le mme bureau et travaillent ensemble :
11

llaboration du squelette technique, profils concerns: 95% dveloppeurs et D.T., 5% graphistes ou ergonomes la cration de plusieurs maquettes sous Expression Design ou Illustrator "Look & Feel", profils concerns: 5% dveloppeurs et 95% graphistes ou D.A. Cette phase se termine lorsque lune des maquettes est valide par le client.

11

Production. Cycle de "va et vient" dit itratif entre chaque ple mtier qui est une interaction continue entre les profils. Durant cette phase chaque ple mtier fournit lautre les lments dont il a besoin afin davancer dans le dveloppement du projet.
11

Dveloppement de la partie logique de lapplication, profils concerns: dveloppeurs et directeur technique; Intgration graphique des lments composant lapplication, profils concerns: graphistes, designers interactif ou intgrateurs, directeur artistique.

11

Figure 1.1
Le cycle itratif de production.

Dveloppeur

Designer interactif

Un designer interactif est toujours ncessaire. Toutefois, si le projet ncessite peu de ressources et quil est de faible envergure, ce rle est dvolu un graphiste ou un dveloppeur, ou encore aux deux tour de rle selon les besoins.

1.6 Langages de dveloppement et choix


Choisir un langage de dveloppement nest pas seulement un choix pragmatique, cette dcision est troitement lie la sensibilit et lhistoire personnelles de chacun. Nous allons toutefois lister les langages, et essayer de nous dcider pour lun deux de manire impartiale.

1.6.1 Langages accessibles


Plusieurs langages sont accessibles aux dveloppeurs dans la gamme Expression Studio, ils sont catgoriss en trois types distincts. La premire catgorie concerne les langages manags propres la CLR (Common Language Runtime). On y compte:

10

Partie I

Approches de Silverlight

Le langage dclaratif XAML. XAML signifie eXtensible Application Mark-up Language. Ce langage permet de formaliser le graphisme: les courbes vectorielles, les dgrads de couleurs ou les couleurs unies, les styles, les composants visuels, les animations, les modles de composants qui correspondent la forme et au graphisme de ceux-ci. C#. Le langage logique que nous utiliserons tout au long du livre (voir Chapitre 2). Visual Basic. Langage de haut niveau, comme C#, mais plus spcifique dans son criture, nous ne lutiliserons pas dans ce livre.

La deuxime catgorie concerne les langages manags dynamiques grs par la DLR (Dynamic Language Runtime). Ils ne seront pas couverts ici. Parmi eux on trouve:

IronPython. Cest le portage du python pour la plateforme .Net, vous trouverez plus dinformations ladresse suivante: http://www.codeplex.com/IronPython. IronRuby. Cest la version du langage Ruby propre .Net, vous trouverez plus dinformations ladresse suivante: http://www.ironruby.net/. JScript. Cest un langage cr par Microsoft qui jouit de la norme ECMA. JavaScript. Version spcifique du langage du mme nom mais compile par la DLR

La troisime catgorie fait rfrence au langage non compil (donc interprt) JavaScript, cela engendre moins de possibilits et daccs au lecteur Silverlight, mais laccs est transparent. Le XAML est le seul langage dont vous aurez besoin quel que soit le code logique que vous choisirez. Celui-ci est orient prsentation, cest un langage dclaratif de type XML (voir Chapitre 2).

1.6.2 CLR, DLR et langages non compils


Nous aborderons en dtails les notions de CLR et de DLR au Chapitre3. Sachez simplement que la CLR est le compilateur grant les langages natifs de la plateforme .Net, donc de lenvironnement Silverlight. Au sein de Silverlight, deux langages sont grs par dfaut dans les projets : Visual Basic et C#, mais la CLR donne accs dautres langages moins connus comme F# par exemple. Dune toute autre manire, la DLR ouvre et enrichie Silverlight dautres langages dynamiques qui ne sont pas forcment hrits de ou propres .Net. Un langage dynamique est un langage capable de faire voluer sa structure lexcution, autrement dit un langage dont il est facile dtendre les capacits des classes ou objets natifs dynamiquement. Ce type de langage nest pas rellement dans la culture originelle de Microsoft mais les anciens dogmes provenant des annes80 sont en cours de mutation. Lvolution de C# en est un flagrant exemple. La DLR est en ralit une surcouche la CLR, elle permet des langages dynamiques daccder au lecteur Silverlight en communiquant avec la CLR. JavaScript est un cas particulier, il peut tre gr de deux manires, soit par la DLR, soit de manire transparente. Lorsquil est gr par la DLR, sa mise en production est, au dpart, plus complexe mais dans ce cas, il accde entirement la CLR et bnficie des avantages lis cette dernire. Dans le cas dune utilisation transparente, il donne directement accs une petite partie des capacits du lecteur Silverlight, mais les performances lexcution sont beaucoup moins leves puisquil ny a pas de compilation. Le choix du langage dpendra essentiellement de votre culture de dveloppeur. Cependant, dcider dutiliser ou non directement JavaScript comme langage non compil est un peu moins vident, vous devrez vous poser deux questions:

Chapitre 1

Introduction

11

Quel type de projet souhaitez-vous construire?


11

Si vous souhaitez construire un projet Silverlight faible interactivit, comme des bannires ou de petits sites vnementiels, JavaScript parat plus adquat car sa mise en uvre, ainsi que larchitecture projet, est moins complexe. Le plus logique sera alors de crer un site web Silverlight dans lequel JavaScript assurera la logique. Si vous souhaitez au contraire crer une application riche ayant une forte interactivit utilisateur, optez pour C#, Visual Basic ou nimporte quel langage gr par la DLR (selon votre culture). Tous ces langages ont accs lensemble des fonctionnalits du lecteur Silverlight et permettent des performances bien suprieures lintgration simple de JavaScript. Bien que cela soit rellement possible, raliser une bannire avec C# est sans aucun doute disproportionn.

11

Quel est votre corps de mtier?


11

Si vous tes intgrateur HTML ou que vous cumulez les expriences dans ce secteur, vous avez sans doute dj dvelopp avec JavaScript et vous connaissez peut-tre AJAX. Vous naurez donc pas deffort de reformation dans un premier temps. Vous vous apercevrez cependant que certaines interactions seront moins faciles, voire impossibles mettre en place en JavaScript. Je vous encourage envisager un apprentissage C# moyen terme. Visual Basic est un trs bon langage bnficiant dune grande communaut, mais sa syntaxe est trs spcifique. C# est tout de mme plus proche de ce que nous connaissons. Si vous tes un dveloppeur Java ou .Net, C# parat tout dsign, la puissance de ce langage, son confort dutilisation, son orientation vers des langages fonctionnels, surtout dans sa version 3 (avec les infrences de type par exemple) sont sans gales.

11

Pour notre part, nous utiliserons de faon significative le XAML et opterons pour le langage C#, assez proche de la norme ECMA (les origines de lauteur) sur de nombreux points. JavaScript ne nous servira qu lintgration de Silverlight au sein dune page HTML. Ce livre sadresse en partie aux designers web, dans ce cadre et pour diverses raisons, nous naborderons pas Visual Basic, IronRuby, IronPython ou JScript. Au Chapitre 2, afin de commencer notre apprentissage de Silverlight, en douceur, nous ferons un rapide retour sur les bases du langage XML et XAML, ainsi que sur C#. De cette manire, vous les assimilerez plus facilement par la suite.

2
Le couple XAML / C#
Lapparition du XAML constitue lune des grandes nouveauts de .Net 3. Ce langage repose sur XML. Dans ce chapitre, nous reviendrons donc brivement sur lcriture et la grammaire XML. Puis nous verrons en quoi certains processus de cration sont facilits grce XAML, et comment afficher un document XAML valide au sein dun navigateur ou dun diteur de code simple. Au mme niveau que XAML, le langage C# permet dajouter de la logique nos applications Silverlight. Nous dresserons donc un rcapitulatif succinct de lcriture afin de vous familiariser avec C# et la programmation oriente objet. Si vous dveloppez avec un autre langage, comme JavaScript ou PHP, ou si vous tes intgrateur, ce chapitre vous concerne. Ainsi, inutile de consacrer des heures la lecture dun ouvrage sur C#, dans un premier temps. Si vous tes vous-mme dveloppeur .Net, vous pouvez passer votre chemin ou revoir les fondamentaux du langage.

2.1 XML
Le XAML repose sur XML. Connatre les rgles dcriture du XML revient donc respecter celles du XAML. XML est lacronyme de eXtensible Mark-up Language, cest un langage dclaratif balises.

2.1.1 quoi sert le XML ?


Le XML na quun seul objectif: prsenter dune manire structure et universelle des donnes. Il ny a pas de vocabulaire li ce langage, seule la grammaire est importante. Celle-ci est trs simple et ne connat que quelques rgles importantes. XML se veut donc le plus gnrique possible. Au contraire du XAML qui est conu pour afficher un visuel et qui possde un vocabulaire spcifique, le XML ne possde pas de vocabulaire spcifique. crire ou comprendre la structure dun fichier XML est la porte de tous, dveloppeurs ou non. Les noms des balises ne sont donc pas prdfinis ou figs, mais arbitrairement choisis par le dveloppeur ou le fournisseur de la source XML. Le transit de fichier XML est indpendant du rseau, de la plateforme ou de la connaissance pralable du fichiers XML. Cest aujourdhui le format de communication le plus utilis sur Internet. Vous connaissez sans doute les fameux flux RSS bass sur XML. Les flux RSS

14

Partie I

Approches de Silverlight

ne sont rien dautre que des fichiers de donnes XML respectant la norme RSS. Cest pour cette raison quun lecteur de flux RSS est capable de lire nimporte quelle source do quelle provienne tant que la norme RSS est respecte. Voici un exemple de contenu au format XML:
<DISCOGRAPHIE> <INTERPRETE prenom="Patrick" nom="Hernandez"> <ALBUM annee="1979" titre="Born to be alive"> <JACQUETTE url=www.amazon.com/images/P/Patrick.jpg /> <CHANSON>Born to be alive</CHANSON> <CHANSON>You Turn me On</CHANSON> <CHANSON>It Comes So Easy</CHANSON> </ALBUM> <ALBUM annee=1980 titre=Crazy days Mystery nights> </ALBUM> </INTERPRETE> ... </DISCOGRAPHIE>

Vous remarquez que les donnes sont structures suivant des relations familiales. Ainsi la balise INTERPRETE contient plusieurs balises ALBUM qui contiennent elles-mmes plusieurs balises CHANSON. Les balises ALBUM sont surs les unes par rapport aux autres car elles sont situes sur le mme niveau dimbrication: elles sont toutes contenues par la balise mreINTERPRETE. Nous pouvons donc comparer une structure XML un arbre gnalogique. Toutefois les noms des balises sont arbitraires et ne relvent pas du langage proprement dit. Nous allons maintenant tudier les rgles dcriture du XML qui sappliquent galement aux langages drivs tels que XAML.

2.1.2 La grammaire
Le langage XML est constitu de balises et dattributs. Les balises peuvent tre ouvrantes, fermantes ou auto-fermantes. Les attributs sont dfinis au sein des balises ouvrantes ou auto-fermantes. Ils sont suivis de loprateur daffectation = et leurs valeurs sont toujours entre guillemets (voir Figure 2.1).
Figure2.1
Structure dun fichier XML.
Nud racine Attributs de balise Valeur de l'attribut nom

Balise auto-fermante

Nud texte Nud lment Balise fermante

Balise fermante du nud racine

Chapitre 2

Le couple XAML/C#

15

Bien que les balises soient dfinies arbitrairement, il existe des rgles dcritures respecter sous peine que le fichier ne soit pas lisible:

La balise xml est proscrite. Cest une balise rserve, utilise uniquement pour dcrire lencodage du fichier XML. Les balises ne doivent pas commencer par un chiffre ou par un caractre spcial. Le seul caractre spcial autoris est _. Les autres ne doivent pas tre contenus dans un nom de balise. Attention donc viter les caractres avec accent dont la langue franaise fourmille. Il doit y avoir un unique nud racine. Dans le code XML prcdent, la balise racine est DIS COGRAPHIE. Une balise ouverte doit imprativement tre suivie dune balise de fermeture qui commence par "</" ou tre elle-mme auto-fermante. Cest le cas de la balise JACQUETTE. Les attributs de balise, par exemple annee, ne doivent pas contenir de caractres spciaux. Les valeurs des attributs de balise doivent toujours tre entre guillemets ou entre simples apostrophes.

Vous pouvez galement vous rfrer des fichiers de type DTD (Document Type Definition). Ceux-ci contiennent une dfinition de type de document permettant de spcifier certaines rgles.

2.1.3 Lambigut des relations familiales


Dcider arbitrairement dune structure de donnes base sur des relations familiales peut savrer trs risqu. Dans un arbre gnalogique, la structure familiale reprsente la vie relle, il est donc facile de concevoir des donnes XML bases sur ce modle. Toutefois, lexemple de la discographie est intressant car de nombreuses mthodes de tri existent dans ce cas. Nous avions class notre discographie par interprte puisque les balises INTERPRETE contenaient un ou plusieurs albums. Cependant, nous aurions pu classer les albums au sein de balises GENRE contenant un attribut type avec des valeurs comme funk, rap, disco. Puis, lintrieur des balises GENRE, nous aurions pu avoir des balises ALBUM. Les donnes contenues auraient t les mmes, mais leur structure aurait t diffrente. Nous aurions galement pu classer les albums par date :
<DISCOGRAPHIE> <DATE annee="1979" month="05"> <ALBUM titre="Born to be alive"> <INTERPRETE prenom=Patrick nom=Hernandez /> <JACQUETTE url=www.amazon.com/images/P/Patrick.jpg /> <CHANSON>Born to be alive</CHANSON> <CHANSON>You Turn me On</CHANSON> <CHANSON>It Comes So Easy</CHANSON> </ALBUM> </DATE> <DATE annee=1980> </DATE> ... </DISCOGRAPHIE>

Bref, notre premire structure aurait pu diffrer alors que nous avons les mmes donnes. Il en est de mme pour tous les langages drivs du XML. Les consquences pour les fichiers XML peuvent tre importantes car cela peut rendre difficile les oprations de tri et daccs aux donnes.

16

Partie I

Approches de Silverlight

Pour les langages comme le XAML, les diffrentes approches dimbrication de balises permettent une souplesse de conception unique. Nous allons donc nous intresser davantage au XAML afin de comprendre en quoi ces relations peuvent engendrer des visuels diffrents et innovants.

2.2 XAML, un langage dclaratif puissant 2.2.1 Lutilit du XAML


Comme nous lavons expliqu au Chapitre 1, le XAML, driv de XML, est le nouveau langage apport par .Net 3. Ce langage permet simplement un graphiste de formaliser nimporte quel visuel. Crer des lments graphiques, grce ce langage, peut donc tre ralis de deux manires:

La premire consiste crire du XAML via nimporte quel traitement de texte ou diteur de code. Cest lapproche que va adopter le dveloppeur. Un outil comme Note Pad suffit, mais Visual Studio est recommand car le dveloppeur bnficie de lIntelliSense. Ce concept facilite grandement la programmation en vitant aux concepteurs de connatre le vocabulaire dun langage dans sa totalit. Cela suppose que le graphiste code le visuel, ce qui nest pas lidal car concevoir du graphisme de cette manire se rvle tre une dmarche abstraite et indirecte, qui fait appel peu de sensibilit. Lapprentissage technique du langage est tel que le coder directement dans un premier temps nuit la cration graphique. La deuxime mthode passe par lutilisation dun outil ddi aux graphistes ou aux designers interactifs. Dans ce cas, deux logiciels de la suite Expression rpondent cette problmatique: Expression Blend et Expression Design. Avec ces deux logiciels, les graphistes peuvent concevoir le design dlments visuels ou dune application. Ces logiciels ont la capacit de traduire le visuel en XAML. Une fois le design cr, le dveloppeur peut non seulement en avoir un aperu, mais aussi rcuprer le code XAML gnr de manire transparente. Si vous travaillez avec des outils tels que Adobe Illustrator ou Photoshop, il est tout fait possible dimporter les fichiers produits par ces logiciels au sein dExpression Design ou Expression Blend directement. Dans ce cas, les fichiers psd ou ai sont transforms en bitmap ou au format vectoriel XAML selon le type du fichier import.

Le code gnr est directement rutilisable au sein dune production, le dveloppeur ne le modifiera que trs peu et laissera la place au designer interactif. Le travail de ce dernier est donc rellement respect. Voici une liste de ce qui peut tre formalis en XAML par le graphiste:

les tracs vectoriels ; les couleurs unies ; les dgrads de couleurs ; Les animations ; les composants visuels ; lagencement dune interface visuelle ; les styles de composants ; les modles de composants ;

Chapitre 2

Le couple XAML/C#

17

les filtres ; la 3D.

Comme nous pouvons le voir, le XAML est un formidable outil de communication conu pour chaque acteur dune production. Lergonome, le directeur artistique, le graphiste, le designer interactif, lintgrateur, le dveloppeur et le directeur technique peuvent participer pleinement la cration dune application sans empiter sur le travail des uns ou des autres.

2.2.2 Comparaison XAML / C#


Ces deux langages sont de mme niveau. Cela signifie que tout ce qui est cr en XAML peut ltre via C#, bien quil ne soit pas adapt la cration graphique. Linverse nest pas vrai, XAML est orient visuel avant tout, ainsi il nest pas possible de crer dalgorithmes quelconques sans C# ou un autre langage logique, comme VB. Voici lcriture dun bouton en C#:
Button monBouton = new Button(); monBouton.Width = 156; monBouton.Height = 80; monBouton.Content = "Hello"; Canvas.SetTop(monBouton, 50); Canvas.SetLeft(monBouton, 75); monBouton.Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xC3, 0x02, 0x02)); monBouton.Click += new RoutedEventHandler(button_Click); monCanvas.Children.Add(monBouton);

Voici la mme criture en version XAML:


<Canvas x:Name="monCanvas" > <Button x:Name="monBouton" Width="156" Height="80" Content="Bonjour" Canvas.Top="50" Canvas.Left="75" Background="#FFC30202" Click="button_Click" /> </Canvas>

Dans ces exemples, nous instancions un bouton lintrieur dun conteneur de type Canvas. Comme nous le constatons, le XAML est bien plus simple crire. Par exemple, affecter une couleur se rvle trs facile. De mme, dfinir le bouton comme enfant dun autre objet est trs intuitif et moins verbeux quen C#. Cela provient de la nature mme du XAML qui mane du XML. Vous pouvez avoir un aperu du rsultat la Figure 2.2.
Figure2.2
Visuel dun bouton gnr par XAML ou C#.

18

Partie I

Approches de Silverlight

La proprit Content du bouton permet dans ce cas dafficher le mot Bonjour. Cette proprit ne sappelle pas Label car elle a la capacit dafficher autre chose quune chane de caractres. Grce son criture, trs souple, sappuyant sur le langage XML, le XAML permet dimbriquer des objets complexes aisment. Pour cela, il suffit de dfinir lobjet imbriqu comme nud lment enfant du bouton (voir la section 2.1.2 pour plus dinformations sur XML). Par exemple, on peut afficher une case cocher dans le bouton au lieu dun mot (voir Figure 2.3):
<Canvas x:Name="monCanvas"> <Button x:Name="monBouton" Width="156" Height="80" Canvas.Top="50" Canvas.Left="75" Background="#FFC30202" Click="button_Click" > <CheckBox Content=CheckBox /> </Button> </Canvas>

Figure2.3
Visuel dun bouton gnr par XAML avec case cocher.

Lexemple de la Figure 2.3 ne serait pas rellement ergonomique pour lutilisateur, imbriquer une case cocher au sein dun bouton na pas de relle utilit, toutefois cela montre quel point le XAML sappuie sur les relations familiales hrites du XML. Vous pourrez donc imaginer toutes sortes dinterfaces visuelles et de nouvelles ergonomies pour vos applications. Ce nest quun aperu de ce dont le XAML est capable. Vous allez maintenant crer votre premier visuel XAML.

2.2.3 Afficher un visuel XAML


Lexemple prcdent est illustratif, mais nous ne bnficions daucun moyen pour le moment den avoir un aperu. Bien sr, vous pourriez utiliser Expression Blend ou Visual Studio, mais ces logiciels sinscrivent dans une logique de projet. Vous souhaiterez souvent avoir laperu visuel dun code XAML sans pour autant crer un projet ou une solution (voir Chapitre 3). Pour cela, il existe quelques diteurs de XAML dont lun sappelle Kaxaml. Il a t conu par Robby Ingebretsen, vous pouvez le tlcharger cette adresse: http://www.kaxaml.com. Comme le dit son concepteur, lobjectif est de vous proposer une IntelliSense pousse tout en fournissant un aperu de nimporte quel fichier XAML prsent sur votre disque dur. Vous trouverez un fichier de dmonstration, preview.xaml, dans le dossier chap2 des exemples du livre. Cependant Kaxaml nest pas obligatoire. Il existe une autre solution si vous souhaitez envoyer votre travail un collgue ou votre directeur artistique, mais que ces derniers ne possdent pas dditeur XAML. En ralit, ils nen ont pas forcment besoin tant quaucun code logique nest li au code dclaratif. Tout fichier XAML que vous crez est lisible par votre navigateur, si le lecteur Silverlight est install, et si ce fichier est correctement format. Dans ce dernier cas, le lecteur Silverlight compile directement le fichier XAML lexcution et laffiche dans le navigateur (voir Figure 2.4).

Chapitre 2

Le couple XAML/C#

19

Figure2.4
Fichier preview.xaml directement lisible par Internet Explorer ou Kaxaml.

Mme si Kaxaml est pratique pour lire des fichiers, il ne permet pas rellement un graphiste dlaborer des lments visuels complexes. Nous utiliserons donc exclusivement Expression Blend et Visual Studio pour concevoir nos projets.

2.2.4 Espaces de noms


Pour visualiser correctement un code dclaratif XAML, vous devez imprativement utiliser les espaces de noms conformes au dveloppement XAML. Voici une portion du code o vous pouvez apercevoir les espaces de noms dans les lignes en gras ; il permet dafficher la Figure 2.4:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="640" Height="480"> <Grid x:Name=LayoutRoot Background=White> <Border Height=134 Width=624 Canvas.Left=8 Canvas.Top=8 CornerRadius=24,24,24,24> <Border.Background> <LinearGradientBrush EndPoint=0.5,1 StartPoint=0.5,0> <GradientStop Color=#FF002352/> <GradientStop Color=#FF68A9DE Offset=1/> </LinearGradientBrush> </Border.Background> <Grid Margin=24,20,8,20> <TextBlock HorizontalAlignment=Left VerticalAlignment=Top FontSize=24 Foreground=#FFFF Text=Pratique de Silverlight TextWrapping=Wrap/> <TextBlock HorizontalAlignment=Left FontSize=16 Foreground=#FFFF Text=Conception dapplication interactives riches TextWrapping=Wrap Margin=0,39,0,20 /> </Grid> </Border> </Grid> </UserControl>

Vous remarquez que le code prcdent rpond bien au standard XML. Outre de nombreuses balises permettant de gnrer du contenu graphique, il sy trouve un nud XML racine UserControl. Celui-ci reprsente le premier objet visuel de lapplication Silverlight. Au sein de cette balise, deux attributs nous intressent particulirement: xmlns et xmlns:x. Les initiales xmlns signifient XML NameSpace. Ces attributs sont des espaces de noms, cest--dire quils font rfrence des dictionnaires ncessaires au dveloppement dapplications bases sur WPF et XAML. Ces espaces de noms doivent toujours se situer dans le conteneur XAML racine. Le premier fait rfrence la bibliothque WPF (Window Presentation Foundation) dont Silverlight mane. Cest lespace de noms par dfaut. Grce lui, nous avons accs aux objets complexes de cette bibliothque, comme Border, Grid ou TextBlock. En interne, cette bibliothque est base sur le langage XAML. Cest pourquoi on a besoin dun deuxime espace de noms, xmlns:x, qui fait pour sa part rfrence au

20

Partie I

Approches de Silverlight

langage XAML proprement dit. chaque fois que nous ferons rfrence cet espace de noms, les balises ou attributs devront tre prfixs de x:. Cest, par exemple, le cas de lobjet grille qui contient lattribut x:Name:
<Grid x:Name=LayoutRoot Background=White>

Pour adjoindre un comportement logique aux objets visuels, il vous faudra une classe dite partielle. Celle-ci devra tre rfrence au sein du nud racine de cette manire (voir Chapitre 3 pour les classes partielles):
<UserControl x:Class="maClasse"

Cependant, gardez bien lesprit quun navigateur renverra une erreur daffichage lors de la lecture directe dun fichier XAML si celui-ci rfrence une classe partielle. Dans ce cas, il vous faudra compiler les fichiers XAML et C# pour en faire un unique fichier xap lisible par le lecteur Silverlight. Nous allons maintenant nous concentrer sur le code logique C# qui contribue largement la robustesse des applications Silverlight.

2.3 Les fondamentaux du langage C#


Cette section ne concerne que les dveloppeurs non .NET ou les designers interactifs et intgrateurs ayant des bases de programmation dans nimporte quel langage logique (JavaScript, PHP, ActionScript). Si vous tes dveloppeur .Net expriment, vous pouvez passer votre chemin. Lobjectif est de prsenter et de sinitier aux bases de la programmation oriente objet et de C#, de savoir dclarer des variables et des mthodes et de connatre les types C#.

2.3.1 C# et lAPI Silverlight


Le langage C# est sorti dans sa premire version avec la plateforme .Net 1. Daprs Microsoft, ce langage est le plus performant en termes de lisibilit et de confort. Il allie la puissance de C++ et la simplicit de Visual Basic. Chaque version de C# est une rvolution en soi. Pour ses versions 3 et 4, il a bnfici damliorations visant assouplir les rgles et les mthodologies de dveloppement. Lide est de permettre des prises de dcisions tardives dans les choix darchitecture en intgrant les avantages propres aux langages fonctionnels F# ou JavaScript. Au mme titre que Visual Basic, il est gr par la CLR (Common Language Runtime), cest--dire quil est tout dabord compil en langage intermdiaire avant de ltre en langage machine par le Just In Time Compiler (JITC). C# est un langage orient objet. Les variables ou mthodes sont fortement types. Toutefois les types (comme string ou double) nappartiennent pas au langage lui-mme, mais au Common Type System (CTS). Cela signifie quun type string en C# ou en Visual Basic est avant tout un type string gr par le CTS propre .Net. Cest cela qui permet aux dveloppeurs de coder dans diffrents langages. Le CTS est donc une composante importante de la CLR. Il permet linteroprabilit des langages. Le cur du langage C# est totalement indpendant de lAPI Silverlight. Une API est constitue dune multitude de bibliothques (ou espaces de noms). LAPI (ou framework) Silverlight permet aux dveloppeurs de concevoir des applications Silverlight. Lespace de noms principal est System. Par exemple, lune des bibliothques accessibles dans le framework Silverlight permet de sauve-

Chapitre 2

Le couple XAML/C#

21

garder des donnes sur le poste client local. Il sagit de la bibliothque IsolatedStorage. Celle-ci contient plusieurs classes qui permettent datteindre cet objectif.

2.3.2 Introduction la programmation oriente objet


La programmation oriente objet soppose la programmation procdurale. Jusquau dbut des annes 1980, avec les langages bas niveau proche de la machine, le code tait organis de manire linaire: il tait lu de haut en bas la manire dune procdure que lon suit. Par la suite, avec des langages comme C++, puis des langages de haut niveau, la programmation oriente objet sest impose. La POO part du principe que la plupart des fonctionnalits ou composants dune application peuvent tre dcrits sous forme dobjets. Par exemple, si lon cre une application de gestion de parc automobile, on peut considrer les voitures comme un composant essentiel de lapplication, les voitures seront donc envisages comme des objets. Les objets sont en ralit des exemplaires de modles dobjets appels classes. Chaque exemplaire de la classe Voiture sera diffrenci par les valeurs de ses proprits et de ses champs (voir la section 2.3.4.6). Par convention, on privilgie la notation Pascal o chaque nom de variable ou de mthode commence par une majuscule : MaFonction, MaProprit, MonChamp. Pour les paramtres de mthode, on utilise plutt la notation Camel: monParametre. Le modle de Voiture, appel classe, permet de dcrire tout ce que peut faire une voiture, ainsi que tout ce qui la dfinit. Le mot-cl class permet de crer une nouvelle classe. Voici en C# comment gnrer une classe Voiture:
class Voiture { //champs de la classe voiture public string Marque; public string Modele; public string Imat; public double Longueur; public string TypeCarburant; //mthode qui permet la voiture de rouler public void Roule(){ // permet de tracer la voiture roule dans une console Console.WriteLine("la voiture roule"); //permet de laisser la console affiche Console.ReadLine(); } //mthode qui permet la voiture de sarrter public void Stop(){ Console.WriteLine("la voiture stoppe"); Console.ReadLine(); } }

Comme nous le voyons, tous les exemplaires manant de la classe auront des champs et des mthodes (ou fonctions) propres au modle Voiture. Toutefois, les valeurs affectes aux proprits et aux champs pourront tre diffrentes pour chacun deux, cest cela qui permet de les diffrencier. Toutes les voitures ont une proprit couleur, mais celle-ci pourra possder plusieurs valeurs: rouge, verte ou bleu selon lexemplaire. Le mot-cl new permet de crer un nouvel exemplaire de la classe Voiture. Voici comment vous pouvez crer des exemplaires (galement appels instances) du modle Voiture:

22

Partie I

Approches de Silverlight

//voici un exemplaire de la classe Voiture Voiture MaPorsche = new Voiture() { Marque="Porsche", Longueur=1.95,Modele="Carrera 4", TypeCarburant="essence"}; // voici un autre exemplaire Voiture MaSuper5 = new Voiture() { Marque = "Renault", Longueur = 1.2, Modele = "Super5", TypeCarburant = "diesel" };

On se rend bien compte que chaque voiture instancie possde les mmes champs mais que ceuxci contiennent des valeurs diffrentes. La dclaration et laffectation de variables seront abordes la section 2.3.4.

2.3.3 Une premire application en mode console


Nous allons maintenant mettre en pratique notre apprentissage rcent en crant une petite application en mode console. Ouvrez Visual Studio 2008 et choisissez Fichier > Nouveau projet C# > Application console. Entrez le nom de solution : ParcAuto. Voici le code que Visual Studio gnre par dfaut:
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace ParcAuto { class Program { static void Main(string[] args) { } } }

Toute application console possde une classe par dfaut qui sappelle Program, contenue dans un espace de noms correspondant au nom du projet. Celle-ci contient une mthode qui sexcute par dfaut: Main. Nous allons tracer un message dans la console Windows. Pour cela, ajoutez les lignes suivantes au sein de la mthode Main:
static void Main(string[] args) { Console.WriteLine(Bonjour tout le monde!!); //ceci trace le message Console.ReadLine(); //ceci empche la fermeture de la console }

Pour compiler notre premire application et lexcuter, rien de plus simple : appuyez sur la touche F5. Lorsque vous utilisez ce raccourci, vous lancez le mode Debug. Ce dernier vous permettra de corriger et de comprendre les dysfonctionnements de votre application lorsque vous compilerez ou durant son excution. Si vous nutilisez pas ce mode, votre application chouera en silence si elle contient des erreurs. Pour compiler et excuter sans dboguer, il suffit de laisser appuyer sur les touches Ctrl et F5 en mme temps. Si vous souhaitez uniquement compiler sans lancer votre application, vous pouvez utiliser le raccourci Ctrl+Maj+F5.

Chapitre 2

Le couple XAML/C#

23

2.3.4 Les types


2.3.4.1 Variables et champs dobjets
Une variable permet de stocker des donnes. Voici comment dclarer une variable au sein dune classe, dans ce cas la variable est un champ dobjet (en C#, on diffrencie champ de proprit):
class Program { int monEntier = 13; }

Vous remarquez que le type est toujours prcis en premier, dans notre cas int signifie entier. Il vous faut, cependant, faire la diffrence entre la dclaration et laffectation. Ce sont deux tapes distinctes et laffectation peut tre ralise plus tard. Nous aurions tout aussi bien pu crire:
class Program { int monEntier; monEntier = 13; }

Il arrivera souvent de dclarer une variable sans pour autant laffecter. Par exemple, dans un jeu la variable score sera affecte ds son initialisation mais durant lexcution du programme. Lorsquune variable de type entier est dclare sans tre affecte, sa valeur par dfaut est 0. Ce comportement est d au fait que le type int est un type primitif numrique.

2.3.4.2 Les types primitifs


Il est ncessaire de typer les variables dune part par obligation due au langage, et dautre part parce que cela permet damliorer les performances de vos applications. Le choix du type est trs important dans ce contexte car cest lui qui dterminera loccupation mmoire alloue par dfaut pour stocker la valeur. Parmi tous les types existants, on trouve les types primitifs. Ceux-ci acceptent des valeurs simples. Ils sont la base de tous dveloppements, sans eux aucune conception ne verrait le jour. Voici quelques types primitifs importants:

sbyte. Il contiendra une valeur entire comprise entre 128 et 127. Son nom vient du fait que la valeur pourra tre ngative (s pour signed) et que le nombre de possibilits correspond un octet soit 28 (256 chiffres). Il ne faudra pas confondre Byte, en anglais, et bit, qui signifie 0 ou 1. byte. Ce type peut accepter un entier entre 0 et 255. uint. Il accepte un entier entre 0 et 232, soit 4294967295 possibilits. Le u de uint signifie que la valeur sera toujours non signe (u pour unsigned), donc toujours positive. int. Il reprsente le mme nombre de possibilits mais contient la moiti des chiffres en dessous de 0. Soit entre 2147483648 et 2147483647. decimal. Il contient des valeurs virgule. La plage des valeurs admises se situe entre 1028 et 7.91028. double. Ce type contient galement des valeurs virgule. Comme pour decimal le stockage des donnes est assez complexe, mais le nombre de valeurs acceptes est beaucoup plus grand: entre 510324 et 1.710308.

24

Partie I

Approches de Silverlight

bool. Il est le digne reprsentant de la logique de Mr George Boole. Ce mathmaticien britannique est lorigine dune rvolution des mathmatiques et de la philosophie au XIXme sicle. On en trouve aujourdhui de nombreuses utilisations dans lindustrie ou dans le secteur informatique. Ce type ne peut contenir que deux valeurs: vrai ou faux (true ou false); le bit de donne repose sur cette logique. string. Il reprsente une chane de caractres. La valeur est toujours spcifie entre guillemets. La chane de caractres contenue peut-tre infinie, la mmoire utilise sera alloue au fur et mesure des besoins. Toutefois le type string nest pas comme les autres types simples (voir la section "Le tas et la pile" dans ce chapitre).

2.3.4.3 Les types complexes


Stocker des valeurs simples ne suffit pas. Bien souvent, vous aurez besoin dune variable ayant la capacit de contenir plusieurs donnes. Voici les types complexes:

Les numrations notes enum. Elles vous permettent de stocker un choix de valeurs arbitrairement. Si lon reprend lexemple de la voiture, nous pourrions par exemple proposer une numration pour le type de carburant au lieu dune chane de caractres. Nous pourrions crire ceci:
class Program{ Voiture MaDeLorean = new Voiture() { TypeCarburant = Carburant.Detritus, Marque = DeLorean, Modele = volante }; } enum Carburant{ Diesel, Essence, propane, Detritus, Ethanol } class Voiture{ public string Marque; public string Modele; public Carburant TypeCarburant; }

Vous remarquez que lnumration est en dehors de la classe, elle se suffit elle-mme. Elle pourrait galement en faire partie. Au sein de la classe Voiture, nous dclarons un nouveau champ public de type Carburant. Le mot-cl public est un modificateur daccs, nous verrons les modificateurs daccs plus loin dans ce chapitre. Laffectation se produit au niveau de la classe Program, linstanciation dune nouvelle voiture grce cette ligne:
Voiture MaDeloreane = new Voiture() { TypeCarburant = Carburant.Detritus, Marque = DeLorean, Modele = celle qui vole };

Il faut savoir quune valeur dnumration possde toujours un type sous-jacent. Par dfaut ce type est int mais vous pourriez le changer.

Les structures notes struct. Il sagit de lquivalent dune classe, mais elle est gre diffremment en mmoire. Il faut envisager une structure comme une dfinition dobjets. Dans la majorit des cas, ce seront des objets simples. Par exemple, un point gographique est dfini

Chapitre 2

Le couple XAML/C#

25

grce deux coordonnes: la latitude et la longitude, toutes deux exprimes en degrs. Nous pourrions ainsi dfinir la position de notre voiture grce une structure qui sappellerait PositionGPS:
class Program{ //ceci est une criture pratique //pour crer un nouvel exemplaire de voiture Voiture MaDeloreane = new Voiture(){ TypeCarburant = Carburant.Detritus, Marque = "DeLorean", Modele = "volante", MyPlace = new PositionGPS() { DegreLat=180, DegreLong=176 } }; } struct PositionGPS{ public int DegreLat; public int DegreLong; } class Voiture{ public string Marque; public string Modele; public Carburant TypeCarburant; public PositionGPS MyPlace; }

Les tableaux nots Array et []. Ce sont des objets diffrents de ceux que nous venons de citer en cela quils sont faits pour stocker de multiples donnes sous forme dlments indexs numriquement partir de 0. Il faudra toujours prciser le type des objets stocks. Pour initialiser un tableau, il existe deux mthodes. La premire consiste utiliser le mot-cl new et indiquer le nombre dlments quil pourra contenir. Dans dautres langages comme Java ou Action Script3, ce type correspond la classe Vector (vecteur). Voici un exemple dinstanciation:
Voiture[] MesVoitures = new Voiture[3];

Par la suite, on affecte une voiture chaque index numrique du tableau comme ceci:
MesVoitures[0] = MaDeLorean; MesVoitures[1] = MaPorsche; MesVoitures[2] = MaSuper5;

Voici la seconde mthode appele "criture littrale":


Voiture[] MesVoitures = { MaDeloreane, MaPorsche, MaSuper5 };

Il nous suffit maintenant daccder aux voitures du tableau. Pour cela, nous pouvons utiliser une boucle qui nous permettra de tracer le nom de chaque voiture dans une console Windows. La boucle foreach est la mieux adapte ce type de situation. Voici comment lutiliser:
void TraceMesVoitures(){ //Pour chaque lment de type Voiture dans le tableau MesVoitures foreach(Voiture V in MesVoitures){ //cette ligne permet dafficher le rsultat dans une Console Console.WriteLine("jai une {0}", V.Marque); } //celle-ci permet de figer laffichage de la console pour la lecture Console.ReadLine(); }

26

Partie I

Approches de Silverlight

Concrtement, la boucle parcourt le tableau MesVoitures, rcupre un exemplaire de Voi ture chaque index et trace une phrase en fentre de sortie. Cette boucle sarrte delle-mme lorsque le tableau est entirement parcouru. Les tableaux possdent la proprit length qui permet de connatre le nombre dlments contenus en leur sein. Lobjet List, en C#, est plus souvent utilis que lobjet tableau (Array) en raison des nombreuses capacits quil offre. Un tableau possde une longueur (ou nombre dlments) fixe. La classe List possde pour sa part des mthodes lui permettant dajouter ou de supprimer des lments sans avoir besoin dinitialiser la longueur. Vous la trouverez dans lespace de noms System.Collections. Generic.

2.3.4.4 Les modificateurs daccs


Vous avez sans doute remarqu le mot-cl public prsent devant la dclaration de certains membres de classe. Cest un modificateur daccs. Ces derniers permettent de rendre accessible ou non des champs, des proprits et des mthodes de classe. Le mot-cl public permet de rendre un membre de classe accessible depuis lextrieur de la classe. Cest cela qui nous a permis dinstancier des voitures tout en initialisant leurs champs publiques depuis lextrieur. Voici un cas concret:
class Program{ //ceci est une criture pratique //pour crer un nouvel exemplaire de voiture Voiture maDeLorean = new Voiture(); maDeLorean.marque = "DeLorean"; } class Voiture{ public string marque; Guid numeroSerie = new Guid(); }

La proprit numeroSerie nest dfinie avec aucun modificateur daccs. En fait, lorsque rien nest prcis cest le modificateur private qui est utilis la compilation pour un membre de classe. Pour une classe ce sera le mot-cl internal. Un champ de classe, dfini avec private, nest pas accessible en dehors de la classe, mais seulement en son sein. La meilleure pratique consiste toujours laisser le moins de champs ou de mthodes visibles depuis lextrieur. Votre classe doit toujours tre ferme la modification et toujours ouverte lextension. Seules les proprits et mthodes utiles doivent tre accessibles celui qui instancie ou utilise votre classe. Dans le cas prcdent, il est logique que le numro de srie reste priv et ne soit pas accessible au quidam de base. Le type Guid est en fait une valeur unique car le nombre de possibilits est quasi illimit. De plus, on affecte la valeur lors de linstanciation de la classe Voiture. Voici la liste des modificateurs daccs utilisables:

public. Permet laccs depuis nimporte quel endroit du code. private. Dfinit un membre de classe accessible uniquement depuis la classe contenant ce membre. internal. Autorise laccs toutes les classes de lespace de noms dans lequel est la classe et aux espaces de noms amis. protected. Permet laccs au code situ au sein de la classe ou dans une de ses sous-classes.

Chapitre 2

Le couple XAML/C#

27

2.3.4.5 Conversion de type implicite et explicite


Il vous arrivera souvent dans un langage orient objet de transformer le type dune valeur en un autre type. Catgoriser des objets est une dmarche qui permet doptimiser les performances des applications. Toutefois catgoriser est une dmarche rigide, mme dans la vie courante. Il est toujours dangereux et rarement vrai long terme quun objet soit dun seul type. La classification des espces, bien que ncessaire dun point de vue scientifique, est remise en question chaque fois quune espce sortant du cadre est dcouverte. Lornithorynque est le cas le plus flagrant qui dmontre que classifier des espces est hasardeux. Celui-ci pond des ufs, allaite ses petits, possde un bec de canard, sappuie sur des pattes aux cinq orteils palms. Bref, il regroupe de nombreux aspects que lon croyait uniques au mammifres, aux reptiles et aux ovipares. Il ne rentre dans aucune catgorie simple et prsente certains aspects de plusieurs dentre elles (depuis la thorie de Darwin, la classification des espces a volu, il sagit bien ici dun exemple mettant en vidence la dangerosit de cette manire de raisonner). Pour cette raison et de nombreuses autres, il vous arrivera donc souvent, si vous commencez la POO, dutiliser un type la place dun autre; davoir un jour besoin dun entier la place dun dcimal ou de transformer un boolen en chiffre. Pour transformer un type en un autre type, vous utiliserez une opration de conversion implicite ou explicite appele transtypage ou casting en anglais. La conversion implicite est ralise par le compilateur sans que vous ayez besoin de lui indiquer un mot-cl. Pour que le compilateur puisse russir cette opration, il suffit juste que le type de destination accepte la valeur que lon souhaite dfinir avec ce type. Par exemple, il est facile de transformer un type byte en type uint car un byte est toujours positif et la plage de valeurs possibles est contenue dans la plage de valeurs possibles de uint:
int MonEntier; byte MonByte = 113; MonEntier=MonByte; // Dans ce cas, le type de b sera converti en int la compilation, // ce qui est faisable, puis a recevra la valeur de b.

Il est donc trs facile de dduire les conversions implicites pour les types primitifs numriques. Le deuxime type de transtypage est un peu plus dlicat manier car il vous faudra prciser vousmmes la conversion souhaite. Nous allons reprendre le mme exemple, mais en affectant la valeur de type byte un entier not int:
byte MonByte2; int MonEntier2 = 113; MonByte2 = (byte)MonEntier2; Console.WriteLine(type de MonByte2 :: + MonByte2.GetType());

Dans ce cas, vous devrez mettre le type de destination entre parenthse devant la valeur convertir. Tout type possde une mthode GetType renvoyant le type. Si jamais vous oubliez de convertir explicitement, Visual Studio vous surligne la valeur affecte dans notre cas, cela serait mon Entier2. Lorsque vous passez la souris au-dessus du surlignage, Visual Studio vous indique que vous avez peut-tre oubli une conversion et vous prcise quune conversion explicite existe. Cela nest pas toujours le cas. Que se passe-t-il si jamais une valeur numrique sort de la plage de valeur admise par le type de destination? Par exemple, que se passerait-il si monEntier3 tait gal 312? Le rsultat correspond la valeur convertir, modulo (%) la longueur de la plage des valeurs du type de destination.

28

Partie I

Approches de Silverlight

Modulo est un oprateur mathmatique qui permet de calculer le reste dune division entire. Dans notre exemple "312 modulo 256" nous renverra 56. 312 divis par 256 est gal 256 divis par 256 (qui est nombre entier) plus 56 divis par 256. 56 est bien le reste de la division. Ce sera donc la valeur affecte notre variable de type byte:
int MonEntier3 = 312; byte MonByte3 = (byte)MonEntier3; Console.WriteLine(type de MonByte3 :: + MonByte3.GetType() + valeur :: + MonByte3);

Un autre moyen de convertir explicitement une valeur est dutiliser la classe Convert. Celle-ci possde des mthodes de conversion. Nous pourrions par exemple crire:
byte MonByte4; int MonEntier4 = 312; MonByte4 = Convert.ToByte(MonEntier4); Console.WriteLine(type de MonByte4 :: + MonByte4.GetType());

Lavantage de cette mthode est quelle gnre par dfaut une erreur lexcution si jamais la valeur convertir ne correspond pas la plage du type de destination. Dans lexemple prcdent, nous aurons donc une erreur leve.

2.3.4.6 Diffrencier les champs et les proprits


Jusqu maintenant nous navons utilis que des champs de classe. Une proprit est un membre de classe stockant une valeur au mme titre quun champ de classe. Cependant lavantage dune proprit est quelle permet lajout de logique lorsquelle est mise jour ou lue. Dfinir une proprit est simple avec Visual Studio, il suffit de taper prop, suivi de deux tabulations pour gnrer automatiquement le code:
public string modele { get; set; }

Ceci est la nouvelle criture courte des proprits depuis C# 3. Vous remarquez le mot-cl get qui signifie obtenir et le mot-cl set qui signifie tablir. Ces termes reprsentent deux mthodes qui vont nous permettre de contrler les accs notre proprit. En rgle gnrale, une proprit est toujours accompagne dun champ priv, donc non accessible, qui est mis jour par ces deux mthodes. Nous allons maintenant ajouter un champ priv et un peu de logique dans notre proprit:
class Program { static void Main(string[] args) { Voiture maVoiture = new Voiture(); Console.WriteLine(modele de la voiture :: + maVoiture.modele); Console.ReadLine(); } } class Voiture{ // ceci est le champ priv modele de type chane de caractres private string _modele; public string Modele

Chapitre 2

Le couple XAML/C#

29

{ get{ // on met la logique concernant la lecture de la proprit //si le modle est dfini alors je renvoie le nom du modle if ( _modele.Length > 0) return _modele; else return "N.C."; //si non je renvoie Non Communiqu } set{ // on met la logique concernant lcriture de la proprit // si la valeur que lon essaie dtablir nest pas nulle // alors on affecte la nouvelle valeur du modle if (value.Length > 0) _modele = value; } } }

Par dfaut, une proprit gnre par Visual Studio est publique. Si vous souhaitez crer une proprit uniquement accessible en lecture, il suffit de supprimer la mthode set. Vous pouvez galement prciser un modificateur daccs devant le mot-cl set, ce qui est plus lgant et avantageux. Le modificateur daccs internal permettra par exemple daccepter lcriture de cette proprit uniquement aux objets contenus dans lespace de nom; protected permettra quant lui de laisser laccs en criture aux classes hritant de Voiture.

2.3.4.6 Le tas et la pile


On rpartit les types en deux grandes catgories: les rfrences attribues sur le tas et les valeurs attribues sur la pile. Concrtement, il sagit de deux manires diffrentes de stocker des donnes. La pile reprsente lespace mmoire allou pour les valeurs, alors que le tas reprsente lespace mmoire grant les rfrences. La gestion de ces espaces mmoire est trs diffrente. Lallocation mmoire est fige dans le cas de la pile mais peut tre variable sur le tas. Vous pouvez considrer les rfrences comme des variables qui pointent vers une adresse mmoire, laffectation sera contenue cette adresse. Le Tableau2.1 vous prsente ces types.
Tableau 2.1 : Types grs par la pile et le tas.

Valeurs attribues sur la pile byte / sbyte short / ushort int / uint long / ulong boolean double, float, decimal char numration structure

Rfrences gres sur le tas Array classe personnalise string interface List ObservableCollection

30

Partie I

Approches de Silverlight

Vous remarquez que le type string est gr sur le tas. Chaque modification dune chane de caractres entrane une allocation mmoire et donc des accs coteux en terme de performances. Il faudra utiliser la classe StringBuilder qui permet dallger les accs mmoire. Diffrencier une rfrence dune valeur est assez simple. Il faut se rappeler quune rfrence est une variable qui pointe une adresse mmoire. Commenons par dfinir une valeur de type structure alloue sur la pile:
struct PositionGPS{ public int DegreLat; public int DegreLong; } PositionGPS Gpa = new PositionGPS { DegreLat = 141, DegreLong = 76 }; PositionGPS Gpb = Gpa; Gpa.DegreLat = 35; Console.WriteLine(Gpb.DegreLat);

La console affiche 141, la structure gpb ne change pas car nous avons procd une simple recopie de valeurs. Les deux variables ciblent un espace mmoire diffrent. Elles sont donc autonomes. Examinons le mme code en remplaant les structures par des classes personnalises. Celles-ci sont sont attribues sur le tas:
class Point{ public int X; public int Y; } Point P1 = new Point(){ X = 141, Y = 76 }; Point P2 = P1; P1.X = 35; Console.WriteLine(P2.X);

Cette fois, la console affiche 35, la valeur du champ X de P2 a chang car linstance P2 pointe vers la mme allocation mmoire que P1. On procde une recopie de pointeur dans le cas dune affectation de variables de type rfrence. P2 et P1 ciblent le mme espace mmoire.

2.3.4.7 Les infrences de type


Un nouveau mot-cl est apparu avec C# 3: var. Ce mot-cl vous vitera de prciser le type dune variable lors de sa dclaration. Cela signifie que le type dune variable dclare avec var nest fix quau moment de laffectation de la variable. Cette capacit est trs pratique si vous ne connaissez pas lavance la valeur daffectation. Toutefois le mot-cl var nest pas utilisable pour dclarer des membres de classes, il sert essentiellement dfinir des variables locales aux mthodes.

2.3.4.8 Les types anonymes


Les types anonymes ont un peu le mme rle que les structures. Comme pour celles-ci, lobjectif majeur est de crer un objet ne contenant que des proprits (bien que les structures puissent faire mieux). Cest une reprise directe de ce que vous trouverez dans les langages dynamiques fonctionnels. Ces types anonymes ne peuvent tre dfinis et affects quau sein dune mthode, grce au mot-cl var. Il sagit donc de variables locales. Voici comment crer une classe anonyme:
var MaVoitureAnonyme = new { Modele="307", Marque="Peugeot", Prix=8950, Annee=2004 };

Chapitre 2

Le couple XAML/C#

31

En ralit, le typage fort est prsent, mais une classe anonyme, ainsi que les champs qui la composent, sont crs dynamiquement.

2.3.5 Dclarer des mthodes


2.3.5.1 Dfinition et appel de mthodes
Une mthode est une fonction appartenant une classe. Son premier objectif est de centraliser la mise en uvre dune srie dinstructions. Celle-ci sera excutable linfini par simple appel du nom de la mthode, suivi de deux parenthses (ouverte et ferme). Quels que soient les langages, les fonctions ou mthodes permettent la rutilisation du code. En langage C#, les fonctions globales qui nappartiennent aucune classe nexistent pas. Cest un abus de langage de dire quune mthode statique de classe (donc appartenant et excutable par la classe) est une fonction globale. A contrario de C#, les fonctions sont considres comme des objets dans les langages dits fonctionnels. Dans ces langages, dont JavaScript fait partie, une fonction peut exister par elle-mme (car elle est considre comme un objet). Ce nest pas le cas en C#. Deux types de mthodes existent, les mthodes excutables par la classe et les mthodes invoques par les exemplaires ou instances de classe. Il faut tout dabord dfinir une mthode pour linvoquer par la suite. Voici une dfinition et un appel de la mthode rouler, propre aux exemplaires de la classe Voiture :
class Voiture{ public void Rouler(){ Console.WriteLine("La voiture roule 100Km"); } } class Program{ static void Main(string[] args){ //On invoque la mthode rouler sur linstance de Voiture MaDeLorean MaDeLorean.Rouler(); Console.ReadLine(); //la console tracera le message dfinit au dessus } }

Comme vous pouvez le constater, le nom de la mthode est dabord prcd du mot-cl public (voir "Les modificateurs daccs"), puis du mot-cl void qui fait rfrence au type muet. Cela signifie que la mthode ne retourne aucune valeur. Dans le cas dune mthode renvoyant une valeur, il suffit de prciser le type la place de void. On pourrait dduire que Rouler modifie la position de la voiture et renvoie du dioxyde de carbone en mme temps. Voici le mme exemple mis jour:
public class Voiture{ public int Rouler(){ Console.WriteLine("La voiture roule 100Km ") return 125; } } class Program{ static void Main(string[] args){ Voiture MaDeLorean = new Voiture(){ TypeCarburant = Carburant.Detritus, Marque = De Loreane, Modele = volante, MyPlace = new PositionGPS() { DegreLat = 180, DegreLong = 176 } }; //On invoque la mthode rouler sur linstance MaDeLorean

32

Partie I

Approches de Silverlight

Console.WriteLine(Elle rejette :: + MaDeLorean.Rouler() + g CO2 / Km); Console.ReadLine(); //la console tracera le message dfinit dans la mthode, //puis le message dfini dans la mthode Main } }

Comme nous lavons dj dit, la mthode Main de la classe Program est une mthode dinitialisation, cest le point dentre de notre application console, cest--dire que celle-ci sera excute ds le lancement de lapplication par la CLR. Cest pour cela que sa dfinition commence par le mot-cl static. Les mthodes static prsentent de nombreux avantages. Nous pourrions par exemple crer une mthode de ce type pour la classe Voiture, qui renverrait le nombre de voitures en circulation.

2.3.5.2 Les paramtres de mthode


Nous allons maintenant amliorer la mthode rouler en lui dfinissant un paramtre. Comme nous lavons vu au dbut de ce chapitre, une mthode doit faciliter la rutilisation1. Toutefois, on constate que notre mthode rouler ne permet une voiture de rouler que 100 km. Il serait utile de pouvoir choisir le nombre de kilomtres chaque appel de cette mthode. Pour cela, il nous faut ajouter un paramtre dans la dfinition de cette mthode:
class Voiture { public string Marque; public string Modele; public Carburant TypeCarburant; public PositionGPS MyPlace; public int Rouler( int nombreKilometre) { Console.WriteLine(La voiture roule + nombreKilometre + km); return 125; } }

Puis, nous invoquons celle-ci en lui passant le nombre de kilomtres attendus:


static void Main(string[] args) { //On invoque la mthode rouler sur linstance maDeLorean Console.WriteLine("Elle met :: " + MaDeLorean.Rouler(113) + " g CO2 / Km"); Console.ReadLine(); //la console tracera le message dfini dans la mthode en //prenant en compte le nombre de kilomtres parcourus }

2.3.5.3 Le tableau de paramtres


Dans certains cas, vous aurez besoin de passer un nombre variable de paramtres. C# propose pour cela une signature de fonction spcifique. Il vous faudra utiliser le mot-cl params entre les

1. La rutilisation est un principe connu des dveloppeurs, qui consiste rutiliser le code ou les fonctionnalits dj conues.

Chapitre 2

Le couple XAML/C#

33

parenthses en prcisant le type des paramtres reus. Le terme params reprsente le tableau des paramtres qui ont t passs lors de lappel de la mthode. Si vous ne souhaitez pas prciser de type, il suffit de prciser object. Toutes les classes en C# hritent de object, ainsi vous pourrez spcifier nimporte quel type de paramtre. Dans lexemple suivant, nous calculons le prix moyen dune voiture:
static void Main(string[] args){ Voiture MaDeLorean = new Voiture(){ Prix=150000, TypeCarburant = Carburant.Detritus, Marque = "De Loreane", Modele = "volante", MyPlace = new PositionGPS() { DegreLat = 180, DegreLong = 176 } }; Voiture MaPorsche = new Voiture() { Marque = "Porsche", Modele = "Carrera 4", TypeCarburant = Carburant.Essence, Prix=18500 }; Voiture MaSuper5 = new Voiture() { Marque = "Renault", Modele = "Super5", TypeCarburant = Carburant.Diesel, Prix=1300 }; //on trace directement le retour de la mthode CalculPrixMoyen Console.WriteLine(prix moyen des voitures :: {0}, CalculPrixMoyen (MaDeLorean, MaPorsche, MaSuper5) ); } //on utilise le tableau de paramtre et on prcise un type de retour //car cette fonction renvoie la moyenne calcule private static decimal CalculPrixMoyen( params Voiture[] mesVoitures){ decimal Total = 0; foreach (Voiture v in mesVoitures){ Total += v.Prix; } return Total / mesVoitures.Length; }

2.3.5.4 Porte de variables


Les variables que vous dfinissez au sein dune mthode ne sont accessibles qu lintrieur de celle-ci. Ce sont des variables locales la mthode. la fin de lexcution et dans le cas de variables de type valeur, celles-ci librent la mmoire qui leur est alloue. Ces variables ne sont donc pas accessibles depuis lextrieur. La variable locale total de lexemple prcdent est donc inaccessible dans la mthode main. Cependant, vous pouvez trs bien dcider daffecter une proprit ou un champ de classe. Ils peuvent tre atteint depuis nimporte quel endroit au sein de cette classe mis part au sein de membres ou proprits statiques.

2.3.5.5 Les mthodes dextension


Comme nous lavons dit plusieurs reprises, C# soriente vers les langages dynamiques. Les mthodes dextension sont un nouveau pas dans cette direction. Celles-ci permettent dajouter de manire propre et efficace des mthodes nimporte quel type. Une mthode dextension doit toujours tre static et public et appartenir une classe static. Tout se passe au niveau de la signature de la mthode dont voici un exemple simple:
static class MyExensionsMethods { public static bool IsBiggerThan (this int myInt, int compare) {

34

Partie I

Approches de Silverlight

return myInt > compare; } }

Vous remarquez que le premier paramtre commence par le mot-cl this. Cela signifie quil fait rfrence la variable de type entier qui va faire appel la mthode. Le second paramtre est le premier paramtre de la mthode IsBiggerThan lorsque celle-ci sera appele. Voici comment se droule lappel:
int monEntier = 37; bool myBoolean = monEntier.IsBiggerThan( 13 );

2.3.6 Hritage et implmentations


2.3.6.1 Principes
Un des grands axes de la programmation oriente objet des annes 80 90 est la capacit des classes hriter dautres classes. Dans lapplication dexemple, peut-tre souhaitez-vous louer des voitures de type Utilitaire. Dans ce cas, il nest pas ncessaire dcrire une classe Utilitaire en reprenant chaque champ de la classe Voiture. Nous pouvons simplement considrer que la nouvelle classe Utilitaire hritera de la classe Voiture. Dans ce dernier cas, nous naurons qu le prciser au moment de sa dfinition comme ceci:
class Utilitaire : Voiture{ public int Volume; public void Charger(){ Console.WriteLine("on charge lutilitaire"); Console.ReadLine(); } public void Decharger(){ Console.WriteLine("on dcharge lutilitaire"); Console.ReadLine(); } }

Le grand avantage rside dans le fait que nous navons pas recoder une nouvelle classe entirement. De ce point de vue, lhritage en POO est une technique de dveloppement qui permet la rutilisation. La sous-classe de Voiture (Utilitaire) bnficie de tous les comportements et proprits dune voiture normale en plus des siennes. Voici comment crer une instance de la classe Utilitaire:
//une classe hrite de Voiture Utilitaire MonKangoo = new Utilitaire() { Marque = "Renault", Longueur = 1.2, Modele = "Super5", TypeCarburant = "diesel", Volume=6

};

La problmatique nest cependant pas si simple car imaginez un vhicule de type 4x4. Nous pourrions lenvisager comme un utilitaire ou un vhicule familial. Doit-il hriter dans ce cas de la classe Voiture ou de la classe Utilitaire? Il ny a malheureusement aucune bonne rponse cette question en utilisant lhritage, car il est impossible dhriter de plusieurs classes en C#. Nous avons donc l un problme de conception important: noubliez pas quune fois la dcision prise, vous ne pourrez plus revenir en arrire facilement. Votre dveloppement subira long terme

Chapitre 2

Le couple XAML/C#

35

les dcisions que vous aurez pris trop tt face la ncessit de commencer le dveloppement. Bien que de nombreuses techniques permettent de concevoir un code souple la modification, la programmation objet tente de classifier les fonctionnalits par type, ce qui ne correspond pas toujours une ralit. Les langages dynamiques permettent la prise de dcisions tardives mais aussi de rectifier simplement des choix de conception. Plus vous dcidez tard, meilleure est votre apprciation de la situation et des besoins. Nous verrons que C# soriente dans cette direction depuis sa version 3.

2.3.6.2 Surcharge de mthodes


Comme nous lavons vu, toutes les classes de C# hritent de la classe object. Celle-ci possde une mthode ToString qui permet davoir une reprsentation sous forme de chane de caractres de linstance sur laquelle elle est invoque. Les classes C# ont pour la plupart une implmentation diffrente de cette mthode. Les classes personnalises dont Voiture fait partie, implmentent par dfaut la mthode ToString propre object. Utilisons cette mthode sur notre classe Voiture et voyons le rsultat:
Console.WriteLine( MaDeLorean.ToString()); //renvoie ParcAuto.Voiture

Comme vous le constatez, la mthode retourne par dfaut lespace de noms et le type Voiture. Il peut tre utile davoir un retour personnalis pour la classe Voiture. Nous allons donc redfinir notre propre mthode ToString, il suffit dutiliser le mot-cl override:
public override string ToString(){ return "modle :: " + Modele + " - marque :: " + Marque; }

Ce mot-cl permet doutrepasser la mthode hrite de la classe de base. Ainsi, vous pouvez redfinir cette mthode votre convenance. Il est encore possible dinvoquer la mthode originelle de cette manire:
return "classe :: " + base.ToString()+" - modle :: " + Modele + " - marque :: " + Marque;

Le terme base fait rfrence la classe dont on hrite, dans notre cas cest object.

2.3.6.3 Dclarer des interfaces


Une interface est constitue des signatures de mthodes, de dlgus et dvnements (voir Chapitre 8). Elle reprsente un contrat abstrait dimplmentation. Une classe implmentant une interface doit ncessairement contenir les mmes signatures de mthodes, dlgus et vnements mais avec une dfinition concrte de ceux-ci ( lexception des classes abstraites). Les interfaces (et les classes abstraites) permettent dassouplir le dveloppement et rendent le code plus facile maintenir et volutif. Lutilisation dinterfaces se rvle au final moins dangereux et plus facile grer que lhritage. Pour implmenter une ou plusieurs interfaces, il faudra ajouter un signe: aprs le nom de la classe, suivi du nom des interfaces. Si la classe est hrite dune autre classe, il faudra suivre cet ordre:

36

Partie I

Approches de Silverlight

class MaClasse : ClasseDeBase, interface1, interface2,, interfaceN class Voiture : Vehicule, IUtilitaire, IFamilial

Par convention, on prfixe les noms dinterface de I, ce qui donne plus de lisibilit. Nous nentrerons pas plus dans les dtails de C# au sein de ce chapitre car, comme vous lavez constat, C# est un langage performant dont lapprentissage ncessiterait un livre part entire. Maintenant que vous tes familiaris avec cet environnement, vous allez crer votre premire application Silverlight grce aux outils proposs au sein de la gamme Expression. Dans le prochain chapitre, vous utiliserez Expression Blend et aborderez les bases de la mise en forme XAML, ainsi que larchitecture des projets Silverlight.

3
HelloWorld
Nous allons concevoir une premire application Silverlight avec le logiciel Expression Blend. Ce projet nous servira de base pour dtailler larchitecture par dfaut des projets Silverlight ainsi que lorganisation de linterface Blend. Nous aborderons ensuite la notion darbre visuel et logique ainsi que lutilisation de conteneurs. Nous listerons rapidement les composants de gestion de texte et les options dalignement. Nous finirons ce chapitre par une premire compilation de lapplication, ce qui nous permettra dnumrer les fichiers quelle produit tout en abordant ses mcanismes internes.

3.1 Une premire application Silverlight


Commencez par crer un nouveau rpertoire sur votre disque dur. Vous pouvez le nommer Pra tique_de_Silverlight, par exemple. Cest dans ce rpertoire que seront contenus tous les projets que vous allez crer dans ce livre. Vous devez vous munir de la dernire version dExpression Blend afin de gnrer une solution Silverlight. Celle-ci est disponible en version dessai sur le site de Microsoft: http://www.microsoft.com/france/expression/. De manire gnrale, vous trouverez les pr-requis logiciels sur le blog Tweened.org cette adresse: http://www.tweened.org/ pre-requis-silverlight/. Ils sont mis jour chaque nouvelle version de Silverlight. Une fois que vous avez install Blend et lensemble des pr-requis, dmarrez lapplication. Vous devriez avoir une interface correspondant la Figure 3.1. Blend vous permet dafficher un cran de bienvenue. Cochez la case en bas droite si vous souhaitez quelle apparaisse chaque dmarrage. Vous allez maintenant crer votre premier projet. Pour cela, slectionnez longlet Projects de lcran de bienvenue, puis cliquez sur New Project... Vous devriez voir un nouvel cran safficher (voir Figure 3.2).

38

Partie I

Approches de Silverlight

Figure 3.1
cran de bienvenue d'Expression Blend.

Figure 3.2
Cration d'un nouveau projet.

Dans la bote de dialogue affiche, plusieurs possibilits soffrent vous. Vous pouvez tout dabord choisir entre deux familles de projets: WPF ou Silverlight. Au sein de la famille Silverlight, quatre choix sont accessibles par dfaut. Les solutions de type Silverlight 3 Application ou Silverlight 3 Application + Website sont trs semblables. La premire sera excute dans une page HTML gnre dynamiquement lors de chaque compilation. A contrario, une solution de type site propose des fichiers HTML et JavaScript permettant dintgrer lapplication pour une mise en production et un dploiement rapide (voir Chapitre 4). Le troisime type, Silverlight 3 Control Library, gnre un projet facilitant la centralisation de contrles personnaliss. Crer des contrles personnaliss avec Silverlight est tellement simple que cette manire de procder est assez naturelle. Le dernier type de projet, Silverlight 3 SketchFlow Application, permet de concevoir, de manire efficace et rapide, larchitecture entire dune application Silverlight. Nous aborderons la cration de prototypes avec SketchFlow au Chapitre 10. Choisissez Silverlight 3 Application, puis le langage C# (normalement slectionn par dfaut). Si vous tes dveloppeur Visual Basic, vous avez bien sr la possibilit de choisir ce langage. Il faut galement prciser le chemin daccs au dossier que nous avons prcdemment cr. Il va contenir lensemble de nos projets. Voici un exemple: C:\Documents and Settings\invite\Bureau\

Chapitre 3

HelloWorld

39

Pratique_de_Silverlight\. Pour finir, entrez HelloWorld dans le champ Name, cliquez sur OK. Une autre mthode serait de fermer le panneau, douvrir le menu File, puis de slectionner New Project Il ny a aucune diffrence de rsultat entre ces deux manires de faire. Une fois cette tape ralise, vous accdez linterface de Blend correspondant aux projets de type Silverlight. De lgres diffrences dinterface existent entre les projets WPF et Silverlight. On a coutume de dire que Blend est ralis avec Blend. Cela fait rfrence la nature mme de ce logiciel qui repose sur WPF. Vous devriez rcuprer une interface correspondant la Figure 3.3.
Figure3.3
L'interface d'Expression Blend l'ouverture du projet HelloWorld.

Blend a plac automatiquement, sur votre disque dur, un nouveau rpertoire portant le nom du projet. Crer une application Silverlight, ou WPF, revient gnrer un rpertoire sur votre disque dur contenant un ensemble de fichiers par dfaut. Comme vous le constatez la Figure 3.3, linterface de Blend est constitue de plusieurs parties distinctes:

La barre de menu, situe en haut, permet de crer des boutons et des composants personnaliss, mais donne galement accs aux oprations sur les tracs, aux prfrences du projet et de nombreux autres menus inaccessibles dune autre manire. Compltement gauche de linterface, vous trouverez une barre dicnes. Chaque icne fait rfrence un type doutil. Ceux-ci sont catgoriss en cinq familles: les outils de slection, de manipulation de la vue (le zoom par exemple), de modification, de cration dobjets primitifs (tels que les rectangles, les tracs) et de cration de contrles (du plus simple conteneur aux objets visuels et logiques complexes comme la ListBox). En haut gauche se trouve une srie de panneaux grant les tats visuels, la liste des composants et des ressources, ainsi que larborescence du projet prsent sur le disque dur. Par dfaut, vous trouverez ltat visuel Base qui contient le visuel par dfaut de lapplication. Le panneau Projects contient une arborescence des fichiers ncessaires au fonctionnement de lapplication (voir la section 3.2). La notion dtats visuels, telle quelle est ralise dans Silverlight, est relativement innovante. Nous ajouterons des tats visuels au sein de nos applications afin de scinder visuellement leurs fonctionnalits et de grer les transitions (voir Chapitre 7). En bas gauche se situe le panneau contenant larbre visuel et logique de notre application. Ce panneau affiche lensemble des composants dune application. Ceux-ci sont hirarchiss selon leur ordre dimbrication et leurs liens de parent. On peut considrer que larbre visuel et logique est la reprsentation graphique des liens familiaux entre les objets XAML. Cest galement dans ce panneau que lon pourra concevoir des animations

40

Partie I

Approches de Silverlight

Le centre de lapplication correspond lespace allou aux designers et aux intgrateurs pour concevoir les lments visuels ainsi que larchitecture de linterface utilisateur. Le rectangle blanc au milieu est la grille principale dagencement, nomme LayoutRoot. La couleur darrire-plan par dfaut est le blanc, mais vous pourriez dcider de ne pas en dfinir dans loptique de crer une application Silverlight transparente. Cette vue est donc rellement importante car cest son ergonomie qui rend possible la participation des designers. Cet espace permet galement dafficher le code XAML gnr par Blend lorsque le graphiste cre linterface visuelle. En bas, au centre, le panneau sortie et erreur permet dafficher des informations de sorties lors de la compilation de lapplication Silverlight. Il permet galement dexposer les erreurs leves lors de la compilation ou de lutilisation de Blend.

Compltement droite se concentre une srie donglets: Data, Properties et Resources. En voici le dtail:

Le panneau Data permet de grer des sources de donnes externes ou propres la solution. Il permet galement de crer des jeux de donnes fictives et de simuler un flux RSS ou un tableau dobjets C#. Le panneau Properties est contextuel, cest--dire quil est mis jour en fonction de lobjet slectionn dans larbre visuel et logique ou dans la fentre de design. Il dresse un inventaire complet de toutes les proprits de lobjet en cours de slection. Celles-ci sont parfois si nombreuses quun champ texte de saisie permet de les filtrer. Le panneau Resources est galement contextuel au fichier XAML slectionn ou lobjet slectionn. Il liste lensemble des ressources visuelles ou logiques accessibles. Nous consacrerons le Chapitre 11 aux ressources visuelles et logiques.

3.2 Architecture d'une solution


Le panneau Projects affiche lensemble des fichiers faisant partie de lapplication. Llment hirarchique le plus lev est la solution. Une solution est lunit dorganisation principale. Celle-ci est constitue dau moins un projet. Tous les fichiers ncessaires pour la conception ou produits lors de la compilation sont rpartis au sein de divers projets. Chaque projet a pour but de grer une application, un module, une fonctionnalit ou une bibliothque de contrles facilitant lorganisation du dveloppement. On a donc, en premier lieu, une solution contenant un projet du mme nom (voir Figure 3.4). Voici la liste des fichiers gnrs, par dfaut, au sein du projet lorsque vous crez une application Silverlight:

Le fichier MainPage.xaml. Il contient le code XAML dcrivant les objets graphiques et logiques de linterface utilisateur. Par dfaut, cest galement la premire page charge par lapplication. Le travail du graphiste et de lintgrateur se rpercute dans un premier temps dans ce fichier. Lors de lavancement du projet, dautres fichiers XAML sont ajouts, notamment des dictionnaires de ressources. Le fichier MainPage.xaml.cs contient le code logique C#. Celui-ci assure la partie fonctionnelle de la premire page de lapplication. Ce fichier concerne les dveloppeurs C# et les intgrateurs. Aucun fichier logique JavaScript nest prsent dans ce type de solution. Toutefois, dans le cas de projets Visual Basic, le fichier aura une extension propre ce langage.

Chapitre 3

HelloWorld

41

Le rpertoire References contient toutes les bibliothques C# ou assemblies ncessaires par dfaut. Ce sont des fichiers dll qui permettent dtendre volont les capacits fonctionnelles de lapplication. Si vous souhaitez utiliser des formats de donnes comme XML ou JSON par exemple, vous devrez ajouter une rfrence sous forme de dll. Pour cela, il suffit de faire un clic-droit, puis de choisir Add Reference... ou Add Project Reference... Le rpertoire Properties contient deux fichiers dcrivant lapplication dans ses grandes lignes : auteur, compagnie, objectif, version, etc. Les fichiers App.xaml et App.xaml.cs contiennent et centralisent du code inhrent au projet lui-mme. Ils permettent de prciser quelle est la premire page de lapplication qui va tre charge. Ils peuvent galement contenir des styles ou des modles de composants accessibles pour toutes les pages XAML. Ces fichiers sont importants car ils reprsentent linstance de lapplication Silverlight dans la page HTML. Ils permettent donc de dfinir des comportements prcis linitialisation ou la fermeture de celle-ci.

Les fichiers numrs ci-dessus ne sont pas les seuls pouvant faire partie dune solution. De nombreux types de documents peuvent tre utiliss au sein de solutions Silverlight. Ce sont gnralement des ressources gnres depuis des applications externes, comme Illustrator et Photoshop, ou cres au sein de Blend ou de Visual Studio. Vous pouvez tout moment ajouter une nouvelle ressource, par exemple une police de caractre ou un fichier de code logique, un projet existant.
Figure3.4
Le panneau Projects.

Nous allons maintenant voir ce qui a t gnr sur le disque dur. Ouvrez votre explorateur Windows afin daccder au rpertoire contenant votre solution. Si celui-ci est sur votre bureau et que vous avez suivi la procdure indique, voici son chemin daccs: C:\Documents and Settings\ invite\Bureau\Pratique_de_Silverlight\. Votre rpertoire doit contenir un dossier du nom de la solution. Celui-ci comprend un rpertoire du mme nom (correspondant au projet gnr par dfaut), ainsi que deux autres fichiers: HelloWorld.sln et HelloWorld.suo qui est un fichier cach contenant des paramtres propres la solution (voir Figure 3.5).
Figure3.5
Contenu du rpertoire de la solution Hello World.

42

Partie I

Approches de Silverlight

Lextension .sln indique un fichier solution. Il rfrence les projets contenus par la solution ainsi que diverses informations. Le rpertoire HelloWorld possde un contenu correspondant ce qui apparat dans le panneau projet de Blend plus un rpertoire bin. Celui-ci reoit les fichiers binaires gnrs lors de la compilation (voir section 3.5.3). Lorsque vous ajoutez un fichier de type ressource ou code logique un projet Silverlight, celui-ci est automatiquement plac dans le rpertoire du projet. Cela permet au projet dtre autonome, dplaable librement sur le disque dur ou encore dtre partag.

3.3 Le conteneur racine


Maintenant que nous avons vu larchitecture dune solution, nous allons tudier celle dune page dapplication Silverlight. Lors de linitialisation dune application Silverlight, celle-ci charge une page par dfaut. La page en question est issue de la compilation des deux fichiersMainControl. xaml et MainControl.xaml.cs. Le premier fichier est de type XML, il contient donc un nud racine. Ce nud est le conteneur parent de tous les objets visuels et logiques de la page. Il est de type UserControl. Il dtermine la dimension de la page, si elle possde un fond transparent ou encore tout ce qui a trait directement ou indirectement son affichage. Les composants de type UserControl ne peuvent contenir quun unique objet enfant. Ainsi, dposer un composant directement dans un UserControl efface lenfant qui sy trouve ventuellement. Lors de la cration dun nouveau projet Silverlight, un contrle Grid nomm LayoutRoot lui est ajout, par dfaut, comme lment enfant. Celui-ci peut, contrairement au composant UserControl, contenir plusieurs enfants visuels et logiques.
Figure3.6
Arbre visuel et logique d'une page.
Conteneur racine Conteneur Grille par dfaut Afficher/cacher les composants

Verrouiller/dverrouiller les composants

Comme vous pouvez vous en rendre compte, une page est constitue dlments imbriqus. Il ny a donc pas rellement de notions de calques ou de couches. Un calque (ou une couche) est une unit dorganisation abstraite qui regroupe plusieurs objets sur une mme profondeur visuelle. Les conteneurs Silverlight sont, quant eux, des objets slectionnables ayant un aspect physique et une logique dagencement propre. Ce nest pas un handicap, bien au contraire. Cela force concevoir limbrication ds le dpart et rend plus propre et efficace le dveloppement dapplications ou de sites. Lensemble des lments imbriqus constitue larbre visuel et logique de lapplication.

3.4 Ajouter du texte 3.4.1 Crer le champ texte


Vous allez maintenant ajouter un champ texte centr. Pour cela, vous trouverez une icne de champ texte dans votre barre doutils. Cliquez dessus et maintenez licne enfonce. Trois pictogrammes

Chapitre 3

HelloWorld

43

apparaissent, correspondant aux trois types de champs texte que vous pouvez crer : TextBlock, TextBox et PasswordBox. Le contrle de type TextBlock vous permet dafficher du texte. Les deux autres types autorisent lutilisateur saisir du texte lors de lexcution de lapplication. Le composant PasswordBox est utile pour la saisie de mots de passe utilisateur. Slectionnez le premier type de champ (TextBlock). Nous allons ajouter une instance de type TextBlock dans notre conteneur LayoutRoot. Double-cliquez sur licne. Un nouveau TextBlock est automatiquement cr en haut gauche, dans la grille LayoutRoot. sa cration un TextBlock est en mode dition de texte (voir Figure3.7). Pour en sortir, appuyez sur la touche Esc ou cliquez hors du composant.
Figure3.7
Cration d'un TextBlock.

3.4.2 Alignement
Lors de sa cration via un double-clic et au sein dun contrle de type Grid, un objet est toujours plac en haut gauche. Vous allez centrer le champ texte au sein de la grille. Pour cela, slectionnez-le dans larbre visuel, puis ouvrez longlet Properties. lintrieur de la catgorie Layout, vous trouvez deux sries dicnes refltant les options dalignement ainsi que quatre champs de saisie juste en dessous. Ceux-ci permettent de spcifier des marges extrieures et doivent tre utiliss conjointement avec les options dalignement. Cest le paramtrage de lensemble de ces proprits qui dtermine le positionnement des objets au sein dun conteneur. Assurez-vous que ces champs ont tous une valeur gale zro. Si un quelconque chiffre apparat dans un de ces champs, il faut le remettre zro. Si vous avez cr le champ texte en le dessinant directement au sein de la grille, ces proprits ne sont pas vides. Pour rinitialiser nimporte quelle proprit dans Blend, il vous suffit de cliquer sur licne carre prsente droite de chacune des proprits et de slectionner Rtablir. Cliquez maintenant sur les deux pictogrammes qui permettent lalignement horizontal et vertical (voir Figure 3.8).
Figure3.8
Les options d'alignement.

Votre texte est maintenant centr. Les proprits largeur et hauteur (Width et Height) possdent une valeur Auto. Cela signifie que leur valeur sadaptera automatiquement, soit au contenu du champ texte (la chane de caractres), soit au conteneur, en fonction des marges et de lalignement spcifi. Vous allez paramtrer laffichage de ce champ. Pour cela, ouvrez la catgorie Text du panneau Properties. Vous y trouverez plusieurs options, notamment pour choisir la police de

44

Partie I

Approches de Silverlight

caractre ou encore la mise en forme du texte. Lune dentre elles, FontSize, permet de modifier la taille de la police en pixels. Choisissez une taille dau minimum 24 pixels. Si vous avez correctement configur les options dalignement du texte, celui-ci devrait stendre dans les deux sens, mais rester centr dans la grille principale. Dans longlet Common Properties, pour la proprit Text, entrez la valeur "HelloWorld" ou la chane de caractres de votre choix. Une fois de plus, le TextBlock stend dans les deux directions pour sadapter son contenu (voir Figure3.9).
Figure3.9
Le projet HelloWorld.

3.5 Tester et compiler


Contrairement aux langages tels que HTML ou JavaScript qui sont interprts par le navigateur, le lecteur Silverlight excute des fichiers de type xap compilables par Blend ou Visual Studio. La compilation permet de fusionner les fichiers contenant le code XAML et C# en langage intermdiaire. Cette tape est donc importante.

3.5.1 Premire compilation


Vous allez maintenant compiler votre application. Pour cela, il y a trois solutions:

Dans le panneau Project, aprs un clic droit sur la solution, slectionnez Run Project. Au sein du menu Project, slectionnez Run Project. Utilisez le raccourci clavier F5.

Ces trois mthodes compilent le projet et affichent le rsultat dans votre navigateur configur par dfaut. Un lecteur autonome existe, mais tester ou dboguer une application Silverlight ne peut tre ralis quau sein dun navigateur. Appuyez sur la touche F5. Une srie de messages apparat en fentre de sortie. Ils vous indiquent la progression de la compilation. La page HTML contenant votre application apparat (voir Figure 3.10).
NOTE INFO

Lors de projets plus complexes, il peut arriver qu'une erreur soit leve la compilation. Dans ce cas, l'application ne compile pas. Il vous faudra lire le message d'erreur prsent en fentre de sortie. Toutefois Blend ne bnficie pas d'un dbogueur aussi puissant que celui de Visual Studio. C'est pourquoi les messages d'erreur sont parfois trs gnriques et peuvent ne pas vous donner d'indices suffisants pour rsoudre le bogue.

Chapitre 3

HelloWorld

45

Figure3.10
L'application charge dans le navigateur aprs compilation.

3.5.2 Une application 100 % Silverlight


Vous remarquez quau sein de notre page, le composant TextBlock nest pas centr. En ralit, il est correctement centr, mais par rapport la page de notre application charge par dfaut. Il est donc centr par rapport au conteneur principal du fichier MainControl.-xaml et son composant racine UserControl. Si vous cliquez-droit nimporte o sur la page HTML, vous verrez un menu contextuel Silverlight. Celui-ci vous indique que linstance du plug-in Silverlight occupe toute la place dans la page HTML. Cependant, par dfaut, le UserControl racine possde des dimensions fixes (640 pixels de large par 480 de hauteur). Pour le vrifier, slectionnez dans Blend le UserControl principal et vrifiez les valeurs de ses proprits Width et Height. Pour rsumer, la page HTML gnre par dfaut affiche linstance du plug-in dans une balise de type DIV occupant100% de hauteur et de largeur, cest--dire que linstance Silverlight occupe toute la place au sein du navigateur. Toutefois, le UserControl racine possde des dimensions fixes exprimes en pixels (voir Figure 3.11).
Figure3.11
Mise en page par dfaut d'une application Silverlight.

Si vous souhaitez centrer le TextBlock dans la page HTML, il vous faut donc faire en sorte que le UserControl racine de MainControl.xaml sadapte au navigateur continuellement. Pour cela il vous faut redfinir la largeur et la hauteur du UserControl. Fermez votre navigateur et revenez sous Blend. Slectionnez le UserControl dans larbre visuel, au-dessus du composant Grid, nomm LayoutRoot par dfaut. Ensuite, dfinissez ses proprits Width et Height sur Auto en cliquant sur le pictogramme situ droite. La valeur Auto signifie que la largeur du composant va sadapter lespace qui lui est permis dans la page HTML. Au sein de Blend, la largeur et la hauteur ntant pas fixes en pixels, le composant sadapte pour afficher au minimum le champ texte

46

Partie I

Approches de Silverlight

contenu dans la grille LayoutRoot. Des icnes apparaissent autour du contour, elles indiquent que vous pouvez agrandir les dimensions du UserControl racine (voir Figure 3.12).
Figure3.12
Mise jour des proprits du UserControl.

Manipulateurs de redimensionnement du UserControl racine

Les icnes les plus loignes permettent dtirer le projet pour simulant les dimensions fictives dune page HTML. Vous pourrez par exemple obtenir un aperu du redimensionnement de votre application dans une rsolution plus faible. Pour grer de manire prcise les dimensions daffichage fictives, vous devez passer en mode ddition XAML. Pour cela, Blend propose un mode ddition XAML. Cliquez sur licne reprsentant une balise en haut droite de la fentre de design. Cest la deuxime icne en partant du haut (voir Figure 3.13). Elle permet daccder au mode XAML. La premire icne, en haut, passera la vue en mode cration. Vous pourrez galement utiliser le mode mixte qui affiche la fois le code XAML et le visuel en cliquant sur licne situe en bas.
Figure3.13
Bouton d'accs au mode d'dition XAML.

Une fois en mode XAML, modifiez les proprits d:DesignWidth et d:DesignHeight du nud UserControl racine en leur donnant respectivement les valeurs 800 et 600. Vous pouvez voir un aperu du code ci-dessous :
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="HelloWorld.MainControl" Width="Auto" Height="Auto" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600">

Votre application possde maintenant une rsolution de 800 pixels de large et de 600pixels de hauteur. Toutefois ces valeurs ne sont uniquement prises en compte et utiles que lorsque vous tes sous Expression Blend. Elles sont pratiques pour avoir une prvisualisation de la mise en page dans cette rsolution. Elles ne sont pas prises en compte lors de lexcution de lapplication dans une page HTML. Quoi quil en soit, linstance de lapplication Silverlight est dans une balise 100 %, le UserControl occupera le maximum despace dans la page HTML car les proprits

Chapitre 3

HelloWorld

47

Width et Height sont en mode Auto et son alignement vertical et horizontal est en mode Stretch. Cette fois, le texte est correctement centr au sein du navigateur. De plus, lorsque vous redimensionnez la fentre du navigateur, le texte se repositionne dynamiquement (voir Figure 3.14).
Figure3.14
Repositionnement centr du TextBlock.

3.5.3 Fichiers gnrs


Une fois lapplication compile, votre navigateur se lance et affiche la page Silverlight. Le site saffiche via le serveur web de dveloppement lanc par Blend. Cest licne que vous pouvez apercevoir en bas droite. Tous les fichiers relatifs la cration du site se situent dans le rpertoire Debug (voir Figure 3.15).
Figure3.15
Emplacement des fichiers gnrs.

Rpertoire du projet

Contient les dossiers Debug et Release selon l'avancement du projet

Rpertoire de la solution

Dtient les fichiers compils HelloWorld.xap, HelloWorld.dll en mode Debug ainsi que la page de test TestPage.html et le fichier AppManifest.xaml.

Comme vous pouvez le voir, les fichiers produits la compilation sont situs dans le rpertoire Debug. Lorsque votre projet est en phase finale et prt pour sa mise en ligne, vous pouvez, sous Visual Studio, dfinir lapplication en mode Release. Cela permet de gagner en performances. Les bibliothques ncessaires pour tracer des messages dans la fentre de sortie ou pour dboguer sont ignores, le code est galement beaucoup plus optimis. De plus, cest une bonne pratique, lorsque lon arrive une version stable, de compiler en mode Release, puis de la mettre en production. Dans tous les cas, vous trouverez au moins les fichiers suivants:

TestPage.html est le fichier gnr automatiquement lors de chaque compilation pour tester lapplication Silverlight. Ce fichier propose une intgration minimale. Il contient simplement une balise object dfinissant linstance du plug-in Silverlight dans la page web. Voici un exemple de la balise gnre par dfaut:

48

Partie I

Approches de Silverlight

<div id="silverlightControlHost"> <object data="data:application/x-silverlight-3," type="application/x-silverlight-3" width="100%" height="100%"> <param name="source" value="SL3WebSite.xap"/> <param name="onerror" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="3.0.40304.0" /> <param name="autoUpgrade" value="true" /> <a href="http://go.microsoft.com/fwlink/?LinkID=141205" style="text-decoration: none;"> <img src="http://go.microsoft.com/ fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/></a> </object> </div>

Vous pouvez remarquez que le premier paramtre indique le chemin daccs vers le fichier xap lire (voir HelloWorld.xap au point suivant). Le deuxime paramtre, onerror, redirige quant lui toutes les erreurs lexcution ou lors de louverture du fichier vers une fonction JavaScript qui gre leur affichage dans une balise DIV ddie. Le paramtre autoUpgrade est par dfaut true. Cela signifie que celui-ci permet la mise jour automatique de Silverlight lorsquune nouvelle version est disponible.

HelloWorld.xap. Cest le format de fichier lisible par le lecteur Silverlight. Malgr les apparences, il nest pas le produit direct de la compilation mais un fichier zip renomm avec lextension xap. Il contient la dll de lapplication ainsi quun manifeste dcrivant tout ce qui est lintrieur. Dans notre cas, il possde HelloWorld.dll, le fichier produit par la compilation. HelloWorld.dll. Cest exactement le mme fichier que celui situ dans le document xap. Il peut tre rfrenc par nimporte quel autre projet Silverlight. Cela permet au projet qui le rfrence de pouvoir crer des instances de notre application. Vous pourriez ainsi crer un portfolio de tous les sites que vous avez ralis en Silverlight, simplement en rfrenant leur dll et en les instanciant sous forme de miniature au sein dExpression Blend. AppManifest.xaml. Le code montr ci-dessous expose le contenu de ce fichier:
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="HelloWorld" EntryPointType="HelloWorld.App" RuntimeVersion="3.0.40624.0"> <Deployment.Parts> <AssemblyPart x:Name="HelloWorld" Source="HelloWorld.dll" /> </Deployment.Parts> </Deployment>

Comme vous le constatez, il dfinit les informations indispensables permettant au lecteur Silverlight de lire le fichier xap. Le lecteur compare la version de Silverlight expose par lattribut RuntimeVersion la valeur de la proprit minRuntime Version dfinie dans la balise object au sein du document TestPage.html. Si les versions dfinies dans chacun de ces fichiers ne correspondent pas, le lecteur peut lever une erreur.

Chapitre 3

HelloWorld

49

3.5.4 Processus de compilation


3.5.4.1 Les classes partielles
Les classes partielles sont nes avec lapparition de .Net 2. Elles avaient dj pour but de sparer le fond et la forme au sein de fichiers distincts. Pour cela, le dveloppeur pouvait glisser/dposer nimporte quel composant .Net au sein dune fentre reprsentant linterface visuelle. Le code logique tait bien spar du code dcrivant linterface visuelle mais ce dernier nhritait pas du XML (contrairement XAML). Lorsque le dveloppeur compilait son application, celle-ci tait donc gnre partir de deux fichiers. Ce mcanisme, permis grce aux classes partielles, est exactement le mme que celui utilis aujourdhui par Silverlight. Toutefois ce concept est bien plus efficace et pertinent avec cette technologie. Comme nous lavons dit lors du prcdent chapitre, une classe est un modle dobjet. Une classe partielle est donc une partie dun modle dobjet contenue, la plupart du temps, dans un fichier spar. Examinons le code XAML de notre projet HelloWorld:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Class="HelloWorld.MainPage" Width="Auto" Height="Auto" mc:Ignorable="d"> </UserControl>

Vous remarquez que le UserControl principal contient la proprit x:Class qui a pour valeur HelloWorld.MainPage. Cela signifie que ce nud est une dfinition de la classe MainPage hritant de la classe UserControl, et que cette dfinition est contenue dans lespace de noms Hel loWorld. Tout ce qui est dclar dans le fichier XAML est donc un nouveau membre de cette classe. Le fichier MainPage.xaml.cs permet dajouter du code logique lapplication et aux objets dclars dans MainPage.xaml. Cest lui qui permet les interactions utilisateur et la cration dalgorithmes complexes. Voici un extrait de ce texte:
namespace HelloWorld { public partial class MainPage : UserControl { public MainPage() { // Required to initialize variables InitializeComponent(); } } }

Cette classe se nomme MainPage. Elle hrite, elle aussi, de la classe UserPage et elle est contenue dans lespace de nom HelloWorld. Vous remarquez lutilisation du mot-cl partial. Ce mot signifie que la classe est partielle. Il sagit donc de la mme classe au sein de deux fichiers spars. Chacun a pour but de dfinir une partie de celle-ci et non la totalit. Cest une approche trs performante car XAML est bien plus pratique pour grer larbre visuel et logique ainsi que les animations. C# sera, quant lui, beaucoup plus performant pour dvelopper laspect fonctionnel et les interactions complexes. Nous allons maintenant tudier les mcanismes du compilateur permettant de grer deux langages aussi diffrents que C# et XAML.

50

Partie I

Approches de Silverlight

3.5.4.2 Just In Time Compiler


La compilation dun projet Silverlight seffectue toujours en deux tapes. La premire consiste transformer les langages de haut niveau grs par la CLR comme C#, VB, XAML ou les langages gres par la DLR, comme IronPython en langage intermdiaire. Quel que soit le langage dorigine, le langage intermdiaire rsultant de la compilation est le mme pour tous les langages grs par .NET. La compilation est ralise par le compilateur propre au langage dans lequel vous dveloppez. Ce langage intermdiaire est contenu dans la dll qui est encapsule au sein du fichier xap. Dans notre cas, elle se nomme "HelloWorld.dll" que nous avons voque plus haut. La deuxime tape est une compilation effectue lors de la lecture du fichier xap par le plug-in Silverlight. Limplmentation du lecteur Silverlight diffre selon les systmes dexploitation et le navigateur utilis. Cette compilation est donc chaque fois diffrente mais lobjectif est le mme: transformer le langage intermdiaire en langage machine. Cest le Just In Time Compiler qui gre cette tape. Son but est de compiler au dernier moment en langage machine afin dobtenir les meilleures performances possibles selon le systme. Comme il est diffrent et spcialis selon les systmes et les navigateurs, il produit du code machine plus adapt quun compilateur gnrique (voir Figure 3.16).
Figure3.16
Compilation Silverlight en deux tapes.

Processus de Compilation Silverlight


Classe partielle XAML Compilateur XAML Classe partielle C# Compilateur C# Classe partielle Visual Basic Compilateur Visual Basic

tape 1
Solution.dll

Langage intermdiaire

AppManifest.xaml Solution.xap

Lecteur Silverlight Just In Time Compiler

tape 2
Langage machine
Windows Mac OS Linux

Dans le prochain chapitre, nous plongerons dans linterface dExpression Blend pour crer un site Silverlight trs simple et grer le redimensionnement des lments visuels.

4
Un site plein cran en 2 minutes
Au sein de ce chapitre, vous allez crer votre premier site Silverlight, puis vous identifierez les diffrences et avantages existants avec les projets de type application. Vous apprendrez crer des boutons au sein de conteneurs spcifiques. Ceux-ci joueront le rle de menus et rafrachiront le contenu de la page principale. Lun deux permettra notamment laffichage du site en mode plein cran. Le navigateur ne sera plus visible et lapplication occupera tout lespace sur lcran lorsque ce mode sera activ. Vous verrez donc comment grer le redimensionnement ou le repositionnement des objets dans la grille principale. Linteractivit utilisateur est aborde travers trois mthodologies diffrentes: les comportements, lutilisation du XAML ou la cration de code logique C#. Pour finir, nous listerons les fichiers qui doivent tre dploys sur le serveur.

4.1 Les projets de type site Internet


Les projets de type site permettent aux designers interactifs de se passer partiellement dun dveloppeur .Net ou dun intgrateur HTML CSS. Ils fournissent par dfaut les mcanismes dintgration des applications Silverlight au sein dune page web. Crez un nouveau projet de type Silverlight Application + Web Site. Nommez-le AgencePort folio. Vrifiez bien que le type de langage choisi est C# et que le rpertoire contenant le projet sappelle Pratique_de_Silverlight. Pour finir, cliquez sur OK. Votre panneau Projects affiche le visuel correspondant la Figure4.1 aprs un court instant. Vous remarquez quil existe une nette diffrence avec les applications Silverlight 3 standard. La solution est constitue de deux projets au lieu dun seul. Le premier projet est lapplication Silverlight elle-mme. Vous pouvez le constater car sa structure est la mme que celle tudie au Chapitre 3. Le deuxime projet reprsente le site web lui-mme. Son nom est le mme que celui de la solution, mais se termine par le suffixe Site. Trois fichiers sont visibles: Default.html, favicon. ico et Silverlight.js. Le premier reprsente la page HTML intgrant lapplication Silverlight. Le deuxime correspond licne par dfaut du site dans la barre dadresse. Le troisime fichier est un document JavaScript qui facilite et amliore lintgration de Silverlight.

52

Partie I

Approches de Silverlight

Figure4.1
Arborescence dun projet de type site Silverlight.

Dans le prcdent type de projet, la page HTML se nommait TestPage.html au lieu de Default.html. Elle tait gnr par dfaut lors de chaque compilation. Lorsque vous le modifiez directement dans le rpertoire Debug, pour amliorer la mise en page ou lintgration Silverlight, ces modifications taient crases chaque compilation. Elles ntaient donc pas prises en considration. Cela ntait pas pratique et rendait obligatoire la sauvegarde de TestPage.html sous un nom diffrent. Vous navez pas ce type de problme avec notre projet, vous pourrez modifier loisir Default.html car il nest pas recr chaque compilation. Un serveur web est lanc avec sa racine pointant sur le dossier site. Le serveur web pointe directement sur le fichier quand le navigateur souvre. Appuyez sur la touche F5 pour tester votre site Internet. Le navigateur affiche une page blanche car aucun lment visuel nest contenu au sein de LayoutRoot. Au moment o vous testez votre site, le projet Application est compil en premier, puis le projet AgencePort folioSite, qui est dfini en tant que projet de dmarrage, est lanc. Le projet en gras au sein dune solution est toujours le projet de dmarrage. Ce projet est donc excut au sein du navigateur aprs la compilation russie du projet Application. Le deuxime projet vous sert donc de base pour produire une intgration HTML performante. En interne, son code est quivalent celui utilis pour lancer les applications classiques car il rfrence le fichier JavaScript Silverlight.js pour vrifier que le plug-in est dj install sur le poste client ou demander sa mise jour. Le fichier Silver light.js donne galement accs aux proprits de linstance du plug-in reprsent par la balise Object. Voil les proprits apports par ce fichier:

Il contient un mcanisme de dtection du lecteur Silverlight, de sa version (si celui-ci est dj prsent) et propose linstallation du lecteur. Il facilite la conception dune intgration avance et permet lutilisation de Javascript comme langage logique. Au mme titre que la balise Object, il permet de grer le prchargement de lapplication Silverlight. Vous pourrez donc afficher un indicateur de prchargement pour les applications Silverlight complexes et celles dont le poids excde une certaine valeur. La dcision concernant la valeur limite vous incombe et dpend du rseau sur lequel lapplication est dploye ou le type de public cibl. Il donne accs aux mmes paramtres avancs que la balise Object. Cest le cas de la proprit IsWindowLess, quivalente windowless pour la balise Object (permettant la cration dapplications transparentes).

Chapitre 4

Un site plein cran en 2 minutes

53

Lorsque vous avez compil, un rpertoire ClientBin a t automatiquement ajout dans le projet Internet. Ce rpertoire contient uniquement le fichier xap. Il est recopi par dfaut la fin de la compilation du projet de type application. Dans ce rpertoire, vous ne trouverez aucun fichier dll ou propre au dbogage car lobjectif est de rester le plus simple possible. Le dossier ClientBin est le dossier de publication. Les fichiers du dossier bin\debug sont empaquets dans le fichier xap qui est dploy dans ClientBin. Vous obtenez ainsi le meilleur des deux mondes. Le projet Internet reste simple et pur, mais le dbogage et la rutilisation demeurent toutefois possibles.

4.2 Crer des conteneurs redimensionnables


Pour crer une interface redimensionnable, plusieurs possibilits soffrent vous. Vous pourriez, par exemple, positionner les menus directement lintrieur de la grille principale. Il est pourtant prfrable de centraliser les objets ayant la mme fonctionnalit au sein dun conteneur ddi. Cela permet de les manipuler tous ensemble plus facilement, si besoin il vaut mieux prvenir que gurir. Nous allons crer deux types de conteneurs. Le premier, un StackPanel, contiendra les lments du pied de page, essentiellement des champs texte cliquables. Le deuxime sera un conteneur de type WrapPanel. Il contiendra et agencera les menus prsents dans le haut de notre page. Ceux-ci seront en ralit des composants de type Button. Notre site correspondra la Figure4.2. Cette figure est un croquis plus ou moins fidle du rsultat escompt. Ne vous formalisez donc pas sur les dimensions ou les rapports de proportions. Ce visuel nous sert avant tout de base de conception. Il a t ralis avec SketchFlow, le nouvel outil de prototypage conu par Microsoft, que tudierons au Chapitre10.
Figure4.2
Croquis du site plein cran.
Menus du haut de page - WrapPanel Bouton plein cran

Croquis du site plein ran

Pied de page StackPanel

4.2.1 Crer le pied de page


4.2.1.1 Crer et configurer le StackPanel
Vous allez commencer par les menus les plus simples : ceux du pied de page. Ils sont contenus dans un StackPanel. Ce type de conteneur permet dempiler verticalement ou horizontalement un ensemble dobjets. Dans notre cas, il sagira de champs texte de type TextBlock. Tout contrle visuel est cliquable au sein des projets Silverlight ou WPF. Le TextBlock nchappe pas cette

54

Partie I

Approches de Silverlight

rgle, il peut donc jouer le rle de liens ou de boutons. Commencez par crer un composant StackPanel. Dans la barre doutils de Blend, cliquez en laissant appuyer sur licne reprsentant le composant Grid. Une srie dicnes apparat. Slectionnez licne reprsentant le StackPanel (voir Figure4.3).
Figure4.3
Icne du StackPanel.

Licne StackPanel remplace licne Grid au 1er niveau, double-cliquez dessus. StackPanel est automatiquement plac en haut gauche de la grille principale LayoutRoot. Il possde des dimensions de 100 pixels de hauteur comme de largeur. Vous allez dfinir une largeur et une hauteur en mode Auto, pour cela cliquez sur licne droite de la proprit Width et Height. Le StackPanel na plus de largeur ni de hauteur, il sest adapt son contenu. Comme il nen a pas encore, il possde des dimensions en largeur et hauteur gales zro pixel. Ce comportement est li au fait quil est align en haut gauche et quil nest pas en mode Stretch (tirement).
NOTE INFO

Lorsquun conteneur vide possde une largeur en mode Auto, cela signifie que la valeur sadapte, soit par rapport au contenu du conteneur, soit par rapport au conteneur parent de celui-ci. Au sein dune grille, si son alignement horizontal est gauche, droite ou centr, cela implique quil sadapte par rapport son contenu. Si loption dalignement est en mode tirement (Stretch) et que des marges sont dfinies, il stirera pour correspondre la largeur de son conteneur, moins les dimensions des marges qui sont dfinies gauche et droite. Cest exactement le mme principe pour la proprit hauteur (Height). Le mode Auto est spcifique aux proprits largeur et hauteur. Pas toujours facile assimiler, il possde le mme comportement que celui existant en XHTML. Il est bidirectionnel car les valeurs en pixels sous-jacentes sont rcupres, soit par le conteneur parent, la grille LayoutRoot dans notre cas, soit par le contenu. Ce mode permet de grer des comportements avancs tout en tant cohrent.

Cliquez sur licne correspondant un alignement horizontal droite dans les options dalignement ( ), puis dfinissez une marge droite de 30 pixels. Spcifiez ensuite un alignement vertical vers le bas ainsi quune marge de 10 pixels par rapport la bordure basse de la grille LayoutRoot. Ne spcifiez aucune marge gauche (entrez la valeur 0). Pour finir, vrifiez bien que Orientation est en mode Horizontal. Ce mode indique la direction dempilement des lments contenus.

Chapitre 4

Un site plein cran en 2 minutes

55

4.2.1.2 Ajouter des champs texte et notion de contexte conteneur


Lorsque vous avez double-cliqu sur licne du StackPanel, vous lavez directement imbriqu dans la grille LayoutRoot. Ce nest pas un hasard. Vous avez pu raliser cette opration car cette grille tait slectionne comme contexte conteneur. Le contexte conteneur est toujours entour dun liser bleu ou jaune. Cela signifie que toutes les actions du graphiste, la cration de composants, leur slection ou encore leur modification, seront ralises dans le conteneur slectionn comme contexte actif. Pour crer une srie de menus lintrieur du StackPanel, il vous faut donc cliquer sur celui-ci dans la vue de design pour le dfinir en tant que contexte actif. Ensuite, vous pouvez double-cliquer sur licne TextBlock dans la barre doutils. Lors de chaque double-clic, vous imbriquez une nouvelle occurrence de TextBlock au sein du StackPanel. Rptez cette opration trois fois. Une fois les trois champs texte crs, dfinissez des marges droite de 20 pixels pour les deux premiers. Vous pouvez slectionnez les deux lments et spcifier leurs marges en mme temps dans le panneau des proprits. Ensuite, changez la valeur contenue dans la proprit Text, qui est accessible via le panneau des proprits ou directement par double-clic sur le composant TextBlock dans la fentre de design (voir Figure4.4). Vous pouvez galement choisir une police afin daffiner le visuel. Je vous conseille la police Trebuchet MS dans un premier temps car cela vite davoir lembarquer puisquelle est intgre par dfaut Silverlight.
Figure4.4
Menu bas du site reprsent par un StackPanel contenant plusieurs contrles TextBlock.

Vous remarquez que le StackPanel sagrandit vers la gauche automatiquement chaque nouvel lment visuel ajout en son sein.

4.2.2 Crer le menu du haut


Nous allons maintenant crer le menu du haut. Le composant bouton (Button) propose des interactions visuelles avantageuses informant lutilisateur que ce menu est ractif. Par exemple, le menu pourrait changer de couleur lorsquil est survol.

4.2.2.1 Principe du WrapPanel et du mode Auto


Comme la navigation de notre site repose essentiellement sur le menu du haut, nous allons imbriquer des boutons au sein dun conteneur. Afin de grer les redimensionnements extrmes de notre site, nous allons utiliser un composant WrapPanel. Celui-ci est proche du StackPanel dans son principe, cest--dire quil empile les lments les uns aprs les autres. Toutefois, il met la ligne un lment visuel si jamais celui-ci tend dpasser le bord droit ou le bord bas du conteneur selon son orientation (voir Figure4.5). Coupl au mode de redimensionnement Auto, propre aux proprits largeur et hauteur, nous pourrions ajuster les dimensions dynamiquement chaque remise la ligne. Par exemple, si nous dfinissons la hauteur (Height) du WrapPanel sur Auto et son orientation horizontale et un aligne-

56

Partie I

Approches de Silverlight

ment vertical haut (viter le mode Stretch dans ce cas, ainsi que les marges), alors le WrapPanel sajustera en hauteur pour chaque nouvelle ligne dlments visuels. Vous pouvez voir lexemple prcdent mis jour en utilisant le mode Auto (voir Figure4.6).
Figure4.5
Principe dimbrication au sein dun WrapPanel.

WrapPanel avec orientation horizontale

WrapPanel avec orientation verticale

Figure4.6
Principe dimbrication au sein dun WrapPanel avec la valeur Auto active.

WrapPanel avec orientation horizontale, hauteur en mode Auto et alignement vertical haut

WrapPanel avec orientation verticale, largeur en mode Auto et alignement horizontal gauche

Comme vous pouvez le constater, sur le premier schma de la Figure4.6, les rectangles (22, 23, 24) ne sont plus coups, la hauteur est rajuste en fonction du nombre de lignes. Sur le second schma, il ne reste plus aucun espace droite de llment 18 car la largeur du WrapPanel sajuste au contenu.

4.2.2.2 Crer et configurer le WrapPanel


Pour crer un conteneur de ce type, vous devez utiliser la bibliothque de composants car il ne se trouve pas dans la liste des conteneurs proposs par dfaut. Cliquez sur la dernire icne de la barre doutils, celle ressemblant une double flche ( ). Elle vous permet douvrir la bibliothque de composants. Slectionnez le mode daffichage avec grandes icnes pour identifier les contrles disponibles (voir Figure.4.7).
Figure4.7
Bibliothque de composants Silverlight.

Chapitre 4

Un site plein cran en 2 minutes

57

Le champ de recherche sert de filtre, entrez-y les lettres wr. Le contrle de type Wrap Panel nest pas visible dans la liste. Cest en fait trs logique, il nest pas instanciable par dfaut au sein des projets Silverlight. Pour y remdier, il vous suffit de tlcharger et dinstaller la bibliothque nomme Silverlight Toolkit. Elle est maintenue par lquipe Silverlight de Microsoft et regroupe de nombreux avantages dont certains contrles qui ne sont par dfaut accessibles quau sein des projets WPF. Afin dassurer un maximum de fonctionnalits au sein de Silverlight, ces composants ont t redvelopps et mis disposition dans le Silverlight ToolKit. Vous le trouverez ladresse: http://www.codeplex.com/Silverlight/. Cliquez sur le menu Download (voir Figure4.8).
Figure4.8
Le portail CodePlex hbergeant le projet Silverlight ToolKit.

Une fois la bibliothque installe, sauvegardez votre projet et relancez Blend. Cette fois-ci, le composant WrapPanel est affich. Cela prend parfois quelques secondes car Blend doit explorer les nouvelles bibliothques de contrles installes. Slectionnez le contrle WrapPanel, son icne apparat juste en dessous de celle permettant laccs la bibliothque. Double-cliquez dessus, une instance de type WrapPanel est automatiquement cre au sein du contexte conteneur slectionn. Dans notre cas, cela doit tre LayoutRoot.
NOTE INFO

Vous pouvez galement accder la liste des contrles via le panneau Assets situ en haut gauche. Ce panneau est parfois plus pratique d'utilisation, cela dpendra essentiellement de la manire dont vous utilisez Blend.

Nous allons lancrer sur les bordures droite, gauche et haute de la grille principale. Pour cela, vous allez dfinir une largeur et une hauteur en mode Auto, comme nous avons fait pour le menu du bas avec le composant StackPanel. Ensuite, cliquez sur licne dalignement vers le haut et spcifiez une marge de 10 pixels par rapport au bord haut. Cliquez sur licne tirement horizontal pour activer ce mode. Dfinissez des marges 30 pixels pour la bordure gauche et 90 pixels pour la bordure droite. Cliquez sur licne droite des proprits Width et Height. Le WrapPanel na plus de hauteur. Il sest adapt son contenu qui est vide. Il possde donc une hauteur gale 0 pixel. Au contraire, comme nous avons dfini des marges gauche et droite ainsi quun alignement horizontal tir, il possde une largeur gale la largeur totale de lapplication moins les marges (voir Figures 4.9 et 4.10).

58

Partie I

Approches de Silverlight

Figure4.9
Configuration des options de mise en forme du WrapPanel.

Figure4.10
Visuel du composant WrapPanel Configur.

Comme vous pouvez le voir, le WrapPanel est ancr en haut, gauche et droite. Les icnes reprsentant un verrouillage indiquent lancrage des objets ou non sur les bords du conteneur Grid principal. Elles sont accompagnes de nombres indiquant la valeur en pixel de chaque marge. Elles sont cliquables et permettent de modifier les options dalignement horizontal et vertical.

4.2.2.3 Ajouter et configurer les boutons du menu


Vous allez maintenant ajouter des boutons correspondant chacun des menus de la Figure4.2. Slectionnez le WrapPanel, puis double-cliquez cinq fois sur licne reprsentant un bouton au sein de la barre doutils. Vous venez linstant dimbriquer cinq boutons dans le conteneur WrapPanel. Vous auriez pu les dessiner directement au sein de ce conteneur. Cette manire de faire prsente lavantage dviter de prciser, pour chaque bouton, les dimensions en hauteur et largeur. Avec cette mthode, celles-ci ont t dfinies en mode Auto pour chacun deux. Les valeurs des proprits Width et Height sajustent en fonction de leur contenu textuel, qui est par dfaut la chane de caractre Button. Ds cet instant, le WrapPanel possde une hauteur qui sajuste chaque bouton. Si vous dfinissez une police diffrente ou une taille diffrente, le bouton rajustera sa hauteur qui rajustera celle du WrapPanel. Si vous avez dfini des marges verticales sur lun des boutons, celles-ci affecteront directement la hauteur finale du WrapPanel. Slectionnez chaque bouton en maintenant la touche Maj enfonce. Ensuite, au sein du panneau des proprits, dans longlet des proprits communes, spcifiez la police Trebuchet MS, ainsi quune hauteur de caractres de 14 pixels.
NOTE INFO

Le corps des polices est exprim par dfaut en pixels et non en points. Il est toutefois possibles de le modifier. Pour cela, ouvrez le menu Tools > Options, choisissez ensuite l'onglet Units. Dans la liste slectionnez Points au lieu de Pixels.

Dslectionnez tous les boutons en cliquant nimporte o sur la scne, puis cliquez sur le premier bouton et entrez la chane de caractres Nouveauts dans la proprit Content. Procdez de

Chapitre 4

Un site plein cran en 2 minutes

59

mme avec tous les autres afin davoir un menu correspondant la Figure4.2. Ensuite, crez un dernier bouton lextrieur du WrapPanel au sein du conteneur Layout Root. Il doit tre ancr en haut droite et possder des marges de 10pixels en haut et de 8 droite. Dans sa proprit Content, insrez la chane de caractres Plein cran. Ce bouton ne fait pas partie directement du WrapPanel car il ne donne pas accs au mme niveau dutilisation. Il nous permettra de passer alternativement du mode plein cran au mode daffichage normal. Vous devriez maintenant avoir un visuel similaire la Figure4.11.
Figure4.11
Menu du haut avec un bouton Plein cran.

Pour finir, slectionnez le UserControl racine et dfinissez une largeur et une hauteur en mode Auto, cela vous permettra de profiter du navigateur 100 %. tirez ensuite la vue de design avec les manipulateurs pour simuler une largeur de 640 pixels et une hauteur de 320 pixels. Voici le code XAML gnr en arrire-plan par Blend, pour la totalit de la grille principale:
<Grid x:Name="LayoutRoot" Background="#FFFFFFFF" Margin="0,0,0,0" > <controlsToolkit:WrapPanel Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="Auto" Margin="30,10,90,0" d:LayoutOverrides="Width"> <Button Height="Auto" Width="Auto" Content="Nouveauts" Margin="0,0,20,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible"/> <Button Height="Auto" Width="Auto" Content="Portfolio" Margin="0,0,20,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible"/> <Button Height="Auto" Width="Auto" Content="Mdias" Margin="0,0,20,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible"/> <Button Height="Auto" Width="Auto" Content="Savoir faire" VerticalAlignment="Center" Margin="0,0,20,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible"/> <Button Height="Auto" Width="Auto" Content="Contact" Margin="0,0,0,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible"/> </controlsToolkit:WrapPanel> <StackPanel Height="Auto" HorizontalAlignment="Right" Margin="0,0,30,8" VerticalAlignment="Bottom" Orientation="Horizontal"> <TextBlock Text="A propos " TextWrapping="Wrap" Margin="0,0,30,0" FontFamily="Trebuchet MS" Foreground="#FF6C6C6C" FontWeight="Bold" FontSize="12" TextDecorations="Underline"/> <TextBlock Text="Qui sommes nous ? " TextWrapping="Wrap" Margin="0,0,30,0" FontFamily="Trebuchet MS" Foreground="#FF6C6C6C" FontWeight="Bold" FontSize="12"/> <TextBlock Text="Newsletter" TextWrapping="Wrap" FontFamily="Trebuchet MS" Foreground="#FF6C6C6C" FontWeight="Bold" FontSize="12"/> </StackPanel> <Button Height="45" Width="60" Content="Plein cran" Margin="0,10,8,0" HorizontalAlignment="Right" VerticalAlignment="Top" FontSize="10" Visibility="Visible"/> <Grid Margin="30,70,30,50" Background="#FF8C8C8C" Visibility="Collapsed"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Contenu des Pages" TextWrapping="Wrap" FontSize="36" FontFamily="./segoepr.ttf#Segoe Print" Foreground="#FFE2E0E0"

60

Partie I

Approches de Silverlight

FontWeight="Bold"/> </Grid> </Grid>

En trs peu de lignes, nous sommes parvenus crer une interface redimensionnable. Vous remarquez que la balise WrapPanel est prfixe de controlsToolkit. Cela signifie quil nest pas rfrenc dans lassembly System.Windows.dll par dfaut. En ralit, lorsque vous avez ajout ce composant dans lapplication, Blend a automatiquement rfrenc deux bibliothques issues du Silverlight ToolKit : System.Windows.Controls.dll et System.Windows.Controls.Toolkit.dll. Pour le vrifier, il suffit douvrir votre panneau projet et de dplier le rpertoire Reference. Blend a galement fait en XAML lquivalent dun using C# pour rfrencer lespace de noms controls Toolkit. Voici le code ajout dans le UserControl racine:
xmlns:controlsToolkit="clr-namespace:System.Windows.Controls; assembly=System.Windows.Controls.Toolkit"

Lorsque vous concevrez et partagerez vos composants personnaliss, les personnes dsirant les utiliser agiront de la mme manire. Elles devront donc ajouter la bibliothque contenant vos composants en tant que nouvelle rfrence. Toutefois Blend fait ce travail pour vous dans la plupart des situations. Pour linstant, ce visuel est un peu brut, mais nous apprendrons rapidement crer des composants et des styles personnaliss.

4.2.3 Crer la grille centrale


Vous allez crer un conteneur Grid situ au centre de la grille principale. Il contiendra le contenu des pages de notre site plein cran. Slectionnez le conteneur LayoutRoot pour le dfinir comme contexte conteneur, puis dessinez une grille au centre.

4.2.3.1 Grer le redimensionnement


Affectez cette grille une hauteur et une largeur automatique avec un alignement tir (Stretch). Pour viter quelle ne recouvre les autres objets, elle doit possder des marges denviron 30 pixels gauche, 60 pixels en haut, 30 pixels droite et 30 pixels en bas (voir Figure4.12).
Figure4.12
Paramtrage de lalignement de la grille centrale.

Pour finir, crez un composant TextBlock centr et sans marges au sein de la grille avec dimensions en mode Auto.

Chapitre 4

Un site plein cran en 2 minutes

61

4.2.3.2 Modifier la couleur darrire-plan


Afin de rendre la grille plus visible lors de la compilation, dfinissez une couleur darrire-plan gris clair. Pour cela slectionnez, en haut du panneau des proprits, lattri-but Background prsent dans linspecteur de couleurs. Ensuite, cliquez sur la deuxime icne en partant de la gauche. Elle permet de spcifier une couleur unie (voir Figure4.13). Comme vous pouvez le remarquer, le code couleur hexadcimal est cod sur 4 octets soit #FFFFFFFF.
Figure4.13
Paramtrage de la couleur darrire-plan de la grille centrale.

NOTE INFO

Un octet reprsente 8 bits, cest pour cela que lon parle dimages 32 bits (48). Un bit possde une valeur 0 ou 1. Une valeur 8 bits reprsente donc une combinaison de 8chiffres possibles de 0 ou 1, soit 28 possibilits. En hexadcimal, cela se traduit par FF, ce qui donne en tout 256possibilits, de 0 255. Dans la plupart des logiciels de graphisme, la couche de transparence nest pas directement affiche dans le code hexadcimal mais elle est plutt affiche sur une chelle qui va de 0 100 % dopacit. Blend propose les deux affichages, ce qui vite les ambiguts. La couleur #00FF0000 ne sera donc pas visible car le premier couple de 0 indique quil ny a aucune opacit.

4.3 Le composant bouton


tudier les proprits du composant bouton permet de comprendre de nombreux principes propres au framework Silverlight car celles-ci sont communes de nombreux autres composants.

4.3.1 Dfinir un nom dexemplaire


Donner un nom dexemplaire aux objets permet dy accder facilement depuis le code logique. Une fois nomms, les objets deviennent des champs de la classe associe au UserControl. Ces champs sont dfinis par dfaut avec le modificateur daccs internal. Ainsi vous pourrez atteindre leurs mthodes, cibler leurs proprits dynamiquement ou encore couter les vnements quils diffusent (comme le clic de la souris). Slectionnez le bouton plein cran, celui-ci ne possde pour linstant pas de nom dinstance. Pour savoir si un composant possde un nom dexemplaire, il suffit de regarder dans larbre visuel. Si le composant est dcrit par son type entre crochet,

62

Partie I

Approches de Silverlight

cela signifie quil nest pas nomm. Vous pouvez galement regarder dans le panneau des proprits si son attribut Name, situ tout en haut, est dfini. Dfinir un nom dinstance est assez simple, vous pouvez soit double-cliquer sur loccurrence directement dans larbre visuel, soit insrer une chane de caractres dans sa proprit Name. Dfinissez Plein EcranBT comme nom dinstance. Par la suite, nous dfinirons un comportement propre ce bouton pour passer en mode plein cran (voir Figure4.14).
Figure4.14
Diffrence daffi chage entre objets nomms et anonymes.

4.3.2 Afficher une bulle dinformation au survol


On peut assigner un ToolTip tout lment visuel. Cette proprit est dite attache, elle nest pas dfinie sur lobjet, elle est fournie par la classe statique ToolTipService. Pour mieux comprendre ce principe, insrez la phrase suivante dans lattribut ToolTip: "Ce bouton permet de passer dun mode daffichage normal un mode daffichage plein cran". Ouvrez le mode ddition XAML. Voici ce que vous pouvez voir dans la balise Button :
ToolTipService.ToolTip="Ce bouton permet de passer dun mode daffichage normal un mode d'affichage plein cran"

Compilez votre application en appuyant sur le raccourci F5 (voir Figure4.15).


Figure4.15
Affichage de linfo bulle au survol du bouton.

Chapitre 4

Un site plein cran en 2 minutes

63

Comme vous pouvez le constater, la proprit ToolTip est fournie par ToolTipService:
ToolTipService.ToolTip=""

Pour finir, si vous souhaitez aligner le bouton Newsletter et le bouton plein cran verticalement gauche (voir Figure4.15), il suffit de dfinir une marge de 30 pixels droite pour le bouton PleinEcranBT.

4.3.3 Choisir un curseur de survol personnalis


Tout lment visuel possde par dfaut la proprit Cursor. Celle-ci permet de dfinir un curseur systme lors du survol dun objet. Selon le systme dexploitation sur lequel vous serez, vous aurez donc des curseurs avec des visuels diffrents. Cela peut vous permettre, par exemple, dindiquer lutilisateur un chargement de donnes en cours de progression. Il vous suffirait de spcifier un curseur dattente (Wait) pour une liste de donnes. Lors de la rception des donnes, vous pourriez ensuite redfinir un curseur standard. Cette proprit prend comme valeur une constante de la classe Cursors (au pluriel).

4.3.3.1 Dfinir un curseur en C#


Si vous ntes pas un familier de .Net, cette mthode est intressante car elle permet de redfinir lexcution le curseur dun objet. La classe statique Cursors liste tous les curseurs disponibles lors du survol dun objet graphique. Double-cliquez sur MainPage.xaml.cs et insrez le code en gras suivant :
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); PleinEcranBT.Cursor = Cursors.Hand; } }

Assigner une valeur dans le XAML est quivalent affecter une valeur dans le constructeur. Pour rappel, le constructeur dune classe reprsente sa mthode dinitialisation, celle qui se lance linstanciation de lobjet. Lintrt daffecter les valeurs dans le code C# est de coupler lassignation de ces valeurs une logique mtier.

4.3.3.2 Dfinir un curseur avec Expression Blend


Expression Blend permet de simplifier le processus pour accomplir cette opration. Il vous suffit douvrir le panneau des proprits propre au bouton plein cran, puis de dfinir un curseur de type Hand (voir Figure4.16).

64

Partie I

Approches de Silverlight

Figure4.16
Affectation dun curseur de survol.

4.3.4 La proprit Content


La proprit Content est assez difficile cerner au premier coup dil. Jusqu maintenant, nous lavons utilise pour afficher un texte au sein des boutons, ce qui constitue son comportement par dfaut. Nous pourrions donc nous demander pourquoi cette proprit ne se nomme pas Label ou Title. Dans les faits, elle est capable de stocker beaucoup plus quune simple chane de caractres. Elle est type Object, ce type reprsente la classe situe au niveau le plus haut de larbre dhritage. Des classes aussi diffrentes que String, Panel ou Button Base hritent par consquent de la classe Object. La proprit Content permet donc dafficher nimporte quel objet visuel ou non. Si lobjet afficher nest pas de type visuel (UIElement), il est converti en chane de caractres de type string, et cette dernire est affiche. Toutefois, la proprit Content ne peut contenir quun seul enfant. Tous les objets hritant de la classe abstraite ContentControl hritent par dfaut de la proprit Content. Nous y reviendrons au Chapitre 5 ddi larbre visuel et logique.
NOTE INFO

Une classe abstraite est une classe dont on ne peut pas crer dinstances directement. Ces classes servent de modle et contiennent du code qui sera, soit surcharg par les classes qui en hritent, soit directement rutilis. Panel, ButtonBase, RangeBase sont des classes abstraites qui sont hrites par de nombreuses classes classes dont on peut crer des instances. Par exemple, Slider ou ProgressBar sont des classes que lon peut instancier et qui hritent des mthodes et des proprits de la classe abstraite RangeBase. En programmation oriente objet, une classe abstraite est lun des moyens mis en uvre en vue de la rutilisation. Toutefois, lhritage multiple ntant pas permis (contrairement C++), ce nest pas toujours le moyen le plus souple.

4.3.4.1 Crer licne de redimensionnement


Nous allons crer une icne de redimensionnement que nous placerons au sein du bouton plein cran. Cette icne est trs simple raliser, et elle va nous permettre dapprendre les oprations de base que Blend propose pour les tracs vectoriels (voir Figure4.17).

Chapitre 4

Un site plein cran en 2 minutes

65

Figure4.17
Icne de redimensionnement.

Dans un premier temps, faites un carr de 16 pixels de ct via la primitive Rectangle. Ensuite, lgrement en dessous, crez deux rectangles allongs de 6 pixels de hauteur par 14 de longueur. Alignez-les horizontalement cte cte en gardant un espace entre eux de 8 pixels (voir Figure4.18).
Figure4.18
Cration de licne, tape 1.

Une fois les rectangles raliss, slectionnez-les, puis ouvrez le menu Object et, au sein de longlet Combine, cliquez sur loption Unite. Vous obtenez une primitive de type Path. Les deux rectangles ont donc t convertis en trac vectoriel. Dans larbre visuel, en lieu et place des deux rectangles, vous remarquez quest apparu un objet [Path]. Slectionnez le carr, puis le nouveau trac, et cliquez-droit dessus. Grce au menu Align, centrez les deux objets horizontalement et verticalement. Ensuite, au sein du panneau des proprits, dans longlet des transformations RenderTransform, cliquez sur la deuxime icne en partant de la gauche. Vous ouvrez ainsi le panneau qui gre la rotation des objets. Longlet RenderTransform est commun tous les objets graphiques. Entrez la valeur de 45 degrs dans le champ Rotation (voir Figure4.19).
Figure4.19
Cration de licne, tape 2.

66

Partie I

Approches de Silverlight

Pour finir, dslectionnez tout, et dans lordre, cliquez sur le trac (les deux anciens rectangles), puis sur le carr, en maintenant la touche Maj enfonce. Ensuite, ouvrez le menu Object, puis Combine et slectionnez loption Substract. Le carr sest vu retirer tout lespace occup par le trac vectoriel (voir Figure4.16). Il ne nous reste plus qu insrer cette image dans notre bouton plein cran en laffectant sa proprit Content. Cela est assez simple faire: glissez licne au-dessus du bouton. Ds que le message vous indiquant la possibilit dimbriquer llment apparat, cliquez sur la touche Alt. Relchez le bouton de la souris. Cest fait, licne est intgre au bouton plein cran. Afin dobtenir un visuel lgant, vous pouvez redimensionner le bouton 18 pixels de hauteur et de largeur, puis slectionner le trac lintrieur et lui affecter des dimensions en mode Auto. Cette dernire modification lui permet de sadapter son conteneur (le bouton). Pour ma part, jai galement dfini des marges extrieures (Margin) en haut et droite de 8 pixels sur le bouton (voir Figure4.20).
Figure4.20
Application finale sans interactivit.

Finalement, on considre les objets bnficiant de la proprit Content comme des conteneurs enfant unique. Au sein de la plateforme Silverlight, de nombreux composants utilisateur en bnficient. Les primitives chappent assez logiquement cette particularit. Le site, sans interaction logique, est disponible en ouvrant pleinEcran_maquette.zip dans le chap4 des exemples du livre.

4.3.4.2 Affecter la proprit Content en C#


Vous laurez compris, au sein de Silverlight presque tous les objets sont imbricables les uns dans les autres. Mais comment faire en C# pour affecter la proprit Content avec un lment existant ou instanci dynamiquement? Pour rpondre cette question, nous allons affecter un composant Image la proprit Content du bouton Contact. Ce type de composant permet dafficher des images bitmap. Pour cela, nommez le bouton ContactBtn, puis tlchargez dans votre rpertoire projet limage IconeContact.png, prsente dans le dossier chap4 des fichiers dexemples. Ensuite, au sein de Blend, cliquez-droit sur le projet et slectionnez loption Add Existing Item Dans la fentre dexploration, slectionnez limage tlcharge et cliquez sur OK. Cette opration vous a permis dajouter limage en tant que ressource. Double-cliquez sur MainPage.xaml.cs. Voici le code C# comment permettant daffecter limage la proprit Content:
public MainPage() { InitializeComponent(); PleinEcranBT.Cursor = Cursors.Hand;

Chapitre 4

Un site plein cran en 2 minutes

67

//on coute l'vnement Loaded diffus lors du premier affichage //du UserControl soit this Loaded +=new RoutedEventHandler(MainPage_Loaded); } private void MainPage_Loaded(object sender, RoutedEventArgs e) { // 1 - ici on cre un composant Image Image myImage = new Image(); // 2 - puis on dfinit son mode de redimensionnement myImage.Stretch = Stretch.None; // 3 - on cre ensuite un objet Uri qui pointe vers // notre fichier image utiliser Uri adresseImage = new Uri("IconeContact.png",UriKind.Relative); // 4 - on cre un objet de type ImageBitmap en lui spcifiant // l'adresse relative que nous venons de dfinir BitmapImage bi = new BitmapImage( adresseImage ); //5 - on prcise au composant la source de l'image qu'il doit afficher myImage.Source = bi; //6 - pour finir, on ajoute le composant Image la // proprit Content de notre bouton Contact ContactBtn.Content = myImage; }

Vous remarquez que limage na pas t copie dans le rpertoire ClientBin. En ralit, elle a t compile au sein du fichier xap, plus exactement dans le fichier dll contenu dans le xap. Il faudra toujours utiliser un objet de type BitmapImage que lon affectera ensuite la proprit Source du composant Image. Finalement, la partie la plus simple est dattribuer le composant Image la proprit Content de notre bouton. Pour affecter un composant plus complexe, tel que Grid, cette proprit, nous aurions simplement pu crire ContactBtn.Content = new Grid();. Cette grille aurait pu, son tour, contenir des objets visuels, il ny a pas limite. Le code nest pas entirement expliqu car nous ferons rfrence au mode redimensionnement ainsi quau chargement dimage ultrieurement.

4.4 Ajouter de linteractivit


Nous allons, dans un premier temps, utiliser les comportements. Depuis sa version 3, Blend permet de coder dans les langages C# et Visual Basic. Comme Visual Studio, il propose une aide au code, IntelliSense, pour ces deux langages ainsi que pour le code dclaratif XAML. Nous utiliserons le C# pour passer du mode plein cran au mode daffichage normal.

4.4.1 Utiliser les comportements


Nous allons nous contenter de simuler le changement de page. chaque fois que nous cliquerons sur un bouton, le champ texte situ au milieu de la page sera mis jour. Nommez le champ texte contenu dans la grille au centre de notre site, TitrePage. Ensuite, ouvrez la bibliothque, puis longlet Behaviors. Celui-ci contient une liste de comportements. Glissez, puis dposez le comportement [ChangePropertyAction] sur le premier bouton du menu. Le comportement apparat ds lors dans larbre visuel (voir Figure4.21).

68

Partie I

Approches de Silverlight

Figure4.21
Ajout dun comportement au premier menu.

Nous allons maintenant configurer ce comportement pour quil change le champ texte TitrePage lors dun clic sur le bouton. Pour cela, aprs avoir slectionn le comportement dans larbre visuel, ouvrez le panneau des proprits. chaque fois que lutilisateur cliquera sur le premier menu, nous affecterons dynamiquement la proprit Text du champ TitrePage avec la valeur Nouveau ts (voir Figure4.22).
Figure4.22
Configuration du comportement.

Lvnement Click reprsente linteraction utilisateur qui dclenchera le changement de valeur. Le paramtre SourceName est optionnel, il indique quel objet est la source de lvnement diffus. Comme le comportement est cr sur le bouton, cest lui qui, par dfaut, diffusera lvnement Click. PropertyName permet de spcifier la proprit affecte lors du Click. Pour modifier le contenu textuel dun composant TextBlock, il faut affecter la proprit Text. Le champ Va lue reprsente la valeur de cette proprit. TargetName est lobjet cibl, dans notre cas cest le champ texte TitrePage. Licne avec les trois points, situe droite du champ de saisie ( ), vous permet de naviguer dans larbre visuel et logique afin de rechercher lobjet cible. Vous devez maintenant rpter cette opration pour les autres menus. Pour accomplir cette tche rapidement, vous pouvez copier-coller ce comportement sur les autres menus, puis changer le paramtre Value pour chaque menu.

Chapitre 4

Un site plein cran en 2 minutes

69

4.4.2 Mode plein cran


Le mode daffichage plein cran est trs pratique pour certains types dapplications, par exemple pour afficher de la vido ou un contenu ncessitant une grande rsolution. Cela permet lutilisateur de simmerger compltement dans lapplication en faisant abstraction des menus propres au navigateur. Pour des raisons de scurit, certaines possibilits du lecteur Silverlight sont dsactives dans ce mode. Pour passer dun affichage normal au mode plein cran, une seule ligne de code C# et un paramtrage XAML suffisent. La premire chose faire est de dfinir une mthode C# qui se dclenchera lorsque lvnement Click est diffus par le bouton plein cran. Pour cela, slectionnez ce bouton, puis ouvrez le panneau des proprits. Cliquez sur licne en forme dclair qui se trouve en haut droite de ce panneau. Vous venez douvrir la liste des vnements disponibles pour le bouton plein cran. Pour lvnement Click, dfinissez la mthode SetFullScreen (voir Figure4.23).
Figure4.23
Le panneau Events.

Voici le code du bouton gnr en XAML:


<Button x:Name="PleinEcranBT" Height="18" Width="18" Margin="0,8,8,0" HorizontalAlignment="Right" VerticalAlignment="Top" FontSize="10" Visibility="Visible" ToolTipService.ToolTip="Ce bouton permet de passer dun mode daffichage normal un mode d'affichage plein cran" BorderThickness="1,1,1,1" BorderBrush="#FFACACAC" Click="SetFullScreen" > <Path Stretch="Fill" Stroke="{x:Null}" Height="Auto" Width="Auto" UseLayoutRounding="False" Data="M4.242609,0 L16,0 L16,11.757387 L12.94972,8.7071075 L8.7070818,12.949746 L11.757336,16 L0,16 L0,4.2426682 L3.0502257,7.2928939 L7.2928643,3.0502553 z"> <Path.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FFC1C1C1" Offset="0"/> <GradientStop Color="#FF9E9E9E" Offset="1"/> </LinearGradientBrush> </Path.Fill> </Path> </Button>

XAML permet de dclarer des mthodes dcoute sur les vnements diffuss. Ce nest pas toujours lidal car C# offre plus de souplesse de ce point de vue. Toutefois, dans une certaine mesure, cela donne aux designers interactifs une certaine autonomie. En phase finale de dveloppement, cest plutt au dveloppeur de grer la diffusion et lcoute des vnements. Les performances de lapplication sont en partie lies la notion de programmation vnementielle (voir Chapitre 8). Lorsque vous avez dfini la fonction dcoute, Blend a automatiquement cr une mthode corres-

70

Partie I

Approches de Silverlight

pondante dans le fichier MainPage.xaml.cs et a ouvert ce fichier. Supprimez la ligne commente et remplacez-la par la ligne en gras du code suivant:
private void SetFullScreen(object sender, RoutedEventArgs e) { App.Current.Host.Content.IsFullScreen = !App.Current.Host.Content.IsFullScreen; }

Le code prcdent est dclench lorsque lutilisateur clique sur le bouton. La ligne C# en gras est assez simple, la proprit boolenne IsFullScreen est affecte de loppos de sa valeur actuelle. Par exemple, si celle-ci est false (donc si lapplication nest pas en mode plein cran), alors elle passe en mode plein cran. Si elle est true, cest--dire en mode plein cran, alors on repasse en mode normal. Cette syntaxe nous a vit dutiliser une condition if, ainsi quun code fastidieux. Testez votre site, redimensionnez la fentre du navigateur et cliquez sur les menus. Le positionnement et laffichage des menus sadaptent automatiquement, mme au sein dune fentre de 640 par 480 pixels. Le WrapPanel gre le retour la ligne des menus si besoin. Pour finir, cliquez sur le bouton plein cran plusieurs fois pour vrifier que le code logique C# correspond au besoin.

4.4.3 Spcificits du mode plein cran


Pour des raisons de scurit, ds lors que vous tes passs en mode plein cran, un message vous lindiquant est apparu durant quelques secondes (voir Figure4.24).
Figure4.24
Message dindication plein cran.

Ce nest pas la seule contrainte de scurit impose par le mode plein cran. Ce mode ne peut pas tre dfini par dautres vnements que ceux dcoulant des interactions utilisateur. Ainsi, vous ne pouvez pas forcer le mode plein cran ds le dmarrage de lapplication par exemple. Dans ce cas, affecter la proprit IsFullScreen ne provoque aucun changement daffichage. Le mode plein cran limite galement lutilisation du clavier. Cela vite lutilisateur de saisir des donnes confidentielles. Ce mode daffichage peut en effet simuler nimporte quel type dinterface. Voici la liste des touches auxquelles vous pouvez accder:

le pav des flches directionnelles (Up, Down, Left et Right) ; la barre despace (Spacebar) ;

Chapitre 4

Un site plein cran en 2 minutes

71

la touche Tabulation (Tab) ; les touches Page Prcdente et Suivante (Page Up, Page Down) la touche Maison et Fin (Home, End) ; la touche Entre (Enter).

Plusieurs instances du plug-in Silverlight ne peuvent pas tre en mme temps en mode plein cran. En ralit, lorsquune application Silverlight plein cran perd le focus, celle-ci revient un mode daffichage normal. Par exemple, le simple fait, sur Windows de basculer, via la combinaison de touches Alt+Tab, dune application une autre fait perdre le focus lapplication Silverlight. Deux applications Silverlight ne peuvent donc pas tre en mode plein cran en mme temps car lune dentre elles a forcment perdu le focus utilisateur.
ATTENTION
La dernire particularit du mode daffichage plein cran est dempcher laffichage dapplications transparentes (via la proprit windowless). Larrire-plan de lapplication sera alors compltement opaque. Lorsque lutilisateur quittera ce mode, lapplication pourra nouveau bnficier de la transparence.

4.4.4 Dtecter le changement daffichage


Il peut tre trs utile dcouter lvnement FullScreenChanged de linstance du plug-in. Cet vnement est dclench lors du changement de mode. Le code suivant permet dafficher la rsolution de lcran utilisateur dans le champ TitrePage chaque changement de mode:
private void MainPage_Loaded(object sender, RoutedEventArgs e) { //cette ligne permet dcouter lvnement FullScreenChanged App.Current.Host.Content.FullScreenChanged += new System. EventHandler(Content_FullScreenChanged); } private void Content_FullScreenChanged(object sender, EventArgs e) { double l = App.Current.Host.Content.ActualWidth; double h = App.Current.Host.Content.ActualHeight; TitrePage.Text = "largeur :: " + l + " - hauteur :: " + h; }

Comme vous le constatez, les dimensions de lapplication ne sont pas rcupres grce aux proprits Width et Height car celles-ci ont t dfinies en mode Auto. Par contre, elles peuvent ltre via les proprits ActualWidth et ActualHeight. Ces proprits contiennent les valeurs absolues en pixels du conteneur racine UserControl. Le Chapitre8 fournit plus dinformation sur lcoute dvnements.

72

Partie I

Approches de Silverlight

NOTE INFO

Un autre vnement existe, Resized, mais il nest pas diffus lors du changement de mode daffichage. Il est diffus lors que lutilisateur redimensionne linstance du plug-in Silverlight. Il permet, par exemple, de repositionner des objets contenus de manire anime en fonction des nouvelles dimensions du plug-in.

4.5 Fichiers dploys


Les fichiers dployer sont tous contenus dans le projet AgencePortfolioSite. Pour dployer votre application, il vous suffit de copier le contenu de ce rpertoire sur votre serveur web via une connexion FTP. Au sein de votre rpertoire distant, vous devrez donc avoir les fichiers:

Default.html, la page HTML qui contient lapplication Silverlight. Silverlight.js, fichier JavaScript qui facilite et amliore lintgration de Silverlight. ClientBin/AgencePortfolio.xap, le fichier Silverlight compil.

Le site finalis est disponible dans larchive pleinEcran_interactif.zip du chap4 des exemples. Au prochain chapitre, nous tudierons les mcanismes lis larbre visuel et logique, ainsi que les mthodes permettant de manipuler la liste daffichage. Comme nous le verrons, Blend propose de nombreux outils permettant aux designers de faire des applications contextuelles capable dadapter laffichage aux besoins et contraintes des utilisateurs.

5
Larbre visuel et logique
Jusqu maintenant, nous avons construit des interfaces sans rellement nous proccuper de larchitecture ou de limbrication des composants. Dans ce chapitre, nous listerons les familles de contrles graphiques, de la simple forme primitive jusquau composant de donnes labor, en affinant notre analyse au fur et mesure de notre avance. Nous aurons ainsi une ide plus prcise de leur rle et de leurs capacits. Puis, nous utiliserons le projet prcdent, SiteAgencePortfolio, pour apprendre y manipuler, ajouter et modifier les enfants dun composant conteneur. Nous aborderons les mthodes et les moyens techniques offerts par Silverlight pour concevoir limbrication, larchitecture et le design visuel de manire complmentaire. cette fin, nous tudierons chaque cas aussi bien du point de vue dun designer interactif que de celui dun dveloppeur C#.

5.1 Composants visuels


Au sein de Silverlight, tous les objets visuels sont des composants et font donc rfrence une classe. La moindre primitive, qui semble pourtant anodine au premier abord, est un composant aux comportements tendus. Connatre les familles de composants est une chose naturelle pour un dveloppeur car cette notion est directement lie larchitecture de lapplication quil dveloppe. Pour un designer, cette dmarche est moins intuitive car il est moins soumis la technique quau rsultat visuel final. Toutefois, un designer interactif doit se faire force de proposition sur lexprience utilisateur et sur un ensemble de notions directement lies larchitecture de lapplication. Il est galement trs souvent conduit modifier des composants existants pour arriver ses fins. Il lui est donc ncessaire de connatre au moins partiellement les familles et types de contrles visuels dont il peut profiter. Tous les composants que nous allons maintenant tudier peuvent et feront sans doute partie de larbre visuel dune de vos applications Silverlight.

5.1.1 Familles de composants


De manire gnrale, on classe les composants par genre. Voici une classification possible des familles du point de vue dun graphiste ou dun ergonome. Toutefois, nous verrons que ces catgories ne sont pas si videntes.

74

Partie I

Approches de Silverlight

Les primitives vectorielles. Les formes de type Rectangle, Path, Line ou Ellipse sont considres comme des composants car elles font bien plus quafficher une forme ou un trac. Elles sont interactives et possdent des proprits complexes que nous allons tudier. Les conteneurs. Il sagit de composants enfants uniques ou multiples. Ils sont la base de tout visuel. Par exemple, le composant racine UserControl est considr comme le conteneur principal de lapplication. Nous verrons quil nest pas forcment facile de les rpertorier car de nombreux composants inattendus sont des conteneurs enfants uniques. Les contrles de gestion et daffichage de texte. Ils vous permettront dafficher du texte de diffrentes manires. Les composants de liste de donnes. Cette catgorie regroupe les listes (ListBox), les listes droulantes (ComboBox) et les grilles de donnes (DataGrid). Le composant AutoComplete Box en fait galement partie, il est mi-chemin entre le champ de saisie et la liste droulante. Les gestionnaires de mdias. Silverlight est une plateforme plurimdias avant tout : elle peut diffuser du son, des images et de la vido dans divers formats, grce trois composants essentiels : Image et MediaElement pour le son et la vido et MultiScale Image bas sur la technologie DeepZoom. Les composants dinterfaces utilisateur. Cest la catgorie fourre-tout dans laquelle vous trouverez les boutons (Button), les barres de dfilement (ScrollBar), les cases cocher (CheckBox) ou encore les barres de progression (ProgressBar) Pour rsumer, cest tout ce qui nest pas dfini dans les catgories cites prcdemment.

Rpertorier nest toutefois pas si simple. Pour le dmontrer, nous allons essayer de catgoriser certains des composants que nous avons utiliss dans le projet SiteAgencePortfolio. Prenons, par exemple, le cas de la grille (Grid). Elle peut-tre classe dans le genre conteneur. Cela est dautant plus visible quelle peut contenir plus dun objet enfant. Le WrapPanel ou le StackPanel sont eux aussi dans cette catgorie. La seule diffrence entre ces contrles concerne les contraintes dagencement subies par leurs objets enfants. Le bouton semble tre facile classer lui aussi car cest avant tout un objet assurant la gestion de comportement utilisateur. Il se retrouve donc dans la dernire catgorie des composants dinterface utilisateur. Toutefois, les boutons, comme de nombreux autres composants, possdent la facult de contenir un unique objet enfant. Deux des boutons que nous avons instancis sur la scne ont t utiliss de cette manire et possdent un enfant. Cest grce la proprit Content que nous avons pu imbriquer un enfant en leur sein. Cela fait-il deux des conteneurs ? Dans une certaine mesure, oui. Grce diverses techniques de programmation oriente objet, dont la composition et lhritage, ces boutons possdent naturellement cette capacit. Toutefois, leur rle premier nest pas dagencer des objets. Ils nont pas la vocation des conteneurs spcialiss. De la mme manire, le pied de page de notre site est constitu de menus reprsents par des TextBlock. Comme tous les objets visuels, ces TextBlock sont cliquables et rien ne nous empche de les utiliser comme des boutons sans interactions visuelles. De plus, chaque TextBlock contient du texte, soit via sa proprit Text, soit en imbriquant des balises de type Run. Lutilit principale du TextBlock est dafficher du texte, nous le classons donc dans la catgorie des gestionnaires de texte. La nature mme du XAML gnre ce type dambigit de par les relations familiales propres aux arborescences XML, mais facilite la construction dinterfaces riches et non rigides. Dans la section suivante de ce chapitre, nous allons essayer de comprendre pourquoi cette classification est simpliste en tudiant larbre dhritage des objets daffichage.

Chapitre 5

Larbre visuel et logique

75

5.1.2 Arbre dhritage des classes graphiques


5.1.2.1 De Object FrameworkElement
La notion dhritage remonte aux dbuts de la programmation oriente objet. Lorsquune classe hrite dune autre classe, elle rcupre les mthodes, les champs et les proprits de celle-ci. Ainsi, le code cr pour la classe mre, et chu aux classes filles, nest crit quune seule fois par le dveloppeur. Lhritage fait partie des nombreuses techniques de rutilisation de code existantes en POO. Comme de nombreuses autres plateformes, Silverlight est bas sur ce concept et les ingnieurs layant conu ont privilgi cette mthodologie. En tant que designer interactif ou dveloppeur, la connaissance de la bibliothque vous permettra de concevoir vos propres composants de manire optimise et perspicace en hritant de la classe adquate, qui naura ni trop ni pas assez de fonctionnalits. La classe mre de toutes les autres est Object. Elle possde plusieurs mthodes dont toutes les autres classes hritent et quelles utilisent. En voici une liste non exhaustive :

Equals. Cette mthode permet de comparer les valeurs contenues par deux rfrences dobjet. GetType. Renvoie le type de linstance qui linvoque, ce qui est trs pratique pour tudier et numrer lavance un type inconnu. MemberwiseClone. Renvoie une nouvelle rfrence clone partir de linstance qui linvoque. ReferenceEquals. Permet de comparer deux rfrences pour savoir si elles possdent la mme allocation mmoire. ToString. Lors de son appel, elle renvoie la valeur de linstance sous forme de chane de caractres. Il peut tre pratique doutrepasser la mthode fournie par dfaut pour gnrer une reprsentation personnalise si celle implmente ou hrite par dfaut ne correspond pas votre besoin.

Nous allons maintenant dtailler les classes graphiques qui hrite de Object. Dans le schma de la Figure5.1, en dessous de Object, vous trouvez DependencyObject. Cette classe est abstraite, cela signifie quelle ne peut pas tre directement instancie. Elle fournit les mcanismes de base propres aux objets graphiques de la plateforme Silverlight, dont le principe de DependencyPro perty, aux classes en hritant. Lanimation, limbrication et la notion de liaison (Binding) prennent appui sur ce principe. Cest l le cur de la puissance et de la souplesse de Silverlight. Hritant de DependencyObject, la classe abstraite UIElement dfinit les mcanismes daffichage propres aux objets graphiques. Elle possde les mthodes et proprits permettant de calculer la taille et le positionnement de son instance dans lespace, elle pose donc les bases du systme dagencement graphique. Cest dans cette classe que les proprits dopacit, de visibilit et de masque de dcoupe sont, par exemple, pourvues. Elle dfinit galement les vnements propres aux interactions utilisateurs : MouseEnter, Mouse Leave, MouseLeftButtonUp, KeyUp, etc. La classe abstraite FrameworkElement hrite son tour de UIElement et y ajoute le systme de disposition visuel de Silverlight: le SLS pour Silverlight Layout System. Le SLS ou systme dagencement de Silverlight repose sur les mthodes Arrange Override, MeasureOverride, sur les proprits Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight, ActualWidth, ActualHeight et, enfin, sur lvnement Size Changed. La classe FrameworkElement dfinit galement Loaded, diffus lorsquune nouvelle instance est initialise au sein de larbre visuel et logique de lapplication. Pour finir, bien que les bases de la liaison de donnes soient dfinies en majeure partie dans la classe Dependency Object, cest la classe FrameworkElement qui rsout laccs aux membres de classe en fournissant la proprit DataContext ncessaire la liaison de donnes. Finalement,

76

Partie I

Approches de Silverlight

FrameworkElement donne naissance la majeure partie des classes concrtes donc des composants visuels instanciables dans Silverlight.
Figure5.1
Arbre dhritage des classes dobjets graphiques.

Chapitre 5

Larbre visuel et logique

77

5.1.2.2 Formes primitives


Commenons par les primitives. Elles hritent toutes de la classe abstraite Shape, qui fournit les proprits ncessaires pour affecter le remplissage du fond et le contour dune forme primitive grce aux proprits Stroke et Fill. Shape permet galement de personnaliser la forme du contour, ses extrmits et ses sommets. Toutes les classes hritant de Shape sont verrouilles, il est donc impossible de les tendre via lhritage. La classe Path est particulire car le trac vectoriel est dfini par la proprit Data. Toutefois, les proprits Width et Height sont tout de mme utilises. Il faudra modifier la proprit Stretch de lobjet Path pour dterminer de quelle manire le trac remplit les dimensions imposes en largeur et en hauteur. Par dfaut, la proprit Strech a pour valeur Fill. Cela signifie que le trac stirera pour remplir compltement les dimensions du composant Path en largeur et en hauteur.

5.1.2.3 Conteneurs primitifs


Cette catgorie concerne une dizaine de classes qui, pour la majorit, sont fermes lextension et hritent en droite ligne de FrameworkElement. Elles ont pour but dafficher ou de mettre en valeur un contenu simple et spcifique. Ainsi, vous pouvez y trouver les composants suivants:

TextBlock. Affiche du texte. Glyph. Composant de gestion de texte bas niveau. Il permet dafficher et de mettre en forme nimporte quel caractre via ses proprits UnicodeString et Indices. Il offre plus doptions et plus de capacits que TextBlock, mais il est plus complexe mettre en uvre. Image. Afficher et charger des images aux formats JPEG et PNG. Le format PNG 32 bits est support, ce qui vous permettra dafficher des icnes transparentes par exemple. MediaElement. Contrle qui permet de lire de la vido et du son aux formats WMV, WMA, MP3, ainsi que les fichiers encods en H.264, ce qui tend ses capacits au format MP4 depuis la version 3 de Silverlight. Le logiciel Expression Encoder possde la capacit dencoder la vido dans tous ces formats. MultiScaleImage. Communment appel composant DeepZoom, il prend en paramtre un ensemble dimages quil chargera par la suite dynamiquement afin de proposer une exprience utilisateur spcifique. Pour vous familiariser avec ce comportement utilisateur, vous pouvez vous rendre sur le site http://www.laguna-coupe.com/. Popup et Border. Conteneurs enfant unique. Ils possdent tous les deux la proprit Child qui leur permet de contenir nimporte quel UIElement. Border peut tre considr comme un rectangle amlior car il possde des proprits de remplissage et daffichage avantageuses. Popup permet, quant lui, dafficher une information au-dessus des autres composants constituant larbre visuel et logique. Il ne sagit pourtant pas dune fentre modale. ItemsPresenter. Ce composant est assez particulier. Il est intgr au sein des composants de type ItemsControl et des classes en hritant. Il permet dtablir la position et lespace allous aux objets (ListBoxItem) dune ListBox par exemple. Il est donc troitement li la proprit ItemsSource dune ListBox. ContentPresenter. Gre le comportement de glisser-dposer et limbrication denfants uniques propres aux composants de type ContentControl. Il fait donc partie intgrante de leur structure.

78

Partie I

Approches de Silverlight

5.1.2.4 Composants personnalisables


Parmi les contrles que nous avons voqus, seuls quelques-uns implmentent la capacit dtre personnalisable tant au niveau de leur style que dans leur forme visuel. Si lon prend le cas du composant Image, celui-ci ne peut tre directement paramtr pour possder une bordure ou un fond. Pour cela, vous devrez utiliser la technique de composition propre la programmation oriente objet. Vous devrez donc crer un contrle, qui sappellera par exemple Visionneuse et qui en interne possdera un Border ainsi quun composant Image. Si vous souhaitez que votre contrle Visionneuse soit paramtrable par un designer interactif, vous devrez le faire hriter de la classe Control. Celle-ci hrite de Framework Element et apporte, en plus, tous les mcanismes inhrents la personnalisation du visuel dun composant. Tous les contrles que nous allons prsent voquer hritent de cette classe et sont donc personnalisables par un graphiste, un designer ou un intgrateur. Nous ne traiterons pas de tous les composants car ils sont nombreux. En voici une liste non exhaustive:

AutoCompleteBox est un composant mi-chemin entre un TextBox et une liste droulante (ComboBox). De ce fait, il hrite directement de Control et non de la classe ItemsControls ou Selector. Il sagit en fait dun champ de saisie qui propose une liste de choix au fur et mesure de la saisie utilisateur. RangeBase est une classe abstraite apportant les mcanismes, mthodes et proprits de base propres aux objets de dfilement ou de progression tels que Slider ou Progress Bar. Si vous souhaitez faire un Slider double curseur, vous devrez tendre cette classe. ItemsControl constitue le fondement des composants exposant une liste dobjets. Ceux-ci sont, la plupart du temps, relis un contexte de donnes ou directement fournis par le dveloppeur partir dun fichier XML, dune base de donnes ou dun service web. TextBox et PasswordBox sont deux composants permettant la saisie de donnes utilisateur. Alors que TextBlock nest reprsent visuellement que par le texte quil affiche, ceux-ci possdent en leur sein une bordure extrieure ainsi quun fond et de nombreuses proprits leur permettant dtre personnaliss. ContentControl est une classe abstraite apportant avec elle la capacit de contenir nimporte quel objet enfant. Cette capacit fait que, par dfaut, tous les objets en hritant possdent en interne un composant de type ContentPresenter et une proprit Content. Cette dernire est type Object. Lorsque vous glissez un trac vectoriel dans un bouton, vous affectez sa proprit Content, elle-mme lie au ContentPresenter situ au sein du bouton. Cette capacit en fait une classe trs puissante et trs souple dutilisation. De trs nombreux composants hritent de cette classe du fait de cette capacit. Il arrivera sans doute que vous ayez besoin dtendre cette classe pour vos propres besoins. ButtonBase hrite de ContentControl et apporte une gestion simplifie et directe du clic gauche de la souris. Les classes en dcoulant, comme Button, RadioButton ou CheckBox, constituent la majeure partie des contrles utilisateur au sein dune interface. Il est noter quil ny a pas de diffrence fonctionnelle entre un ToggleButton et une CheckBox. La seule diffrence entre ces deux composants est purement visuelle. ToolTip est un peu spcifique. Cette classe permet dafficher une bulle dinformation lorsque la souris survole un objet graphique. Toutefois, il est impossible dinstancier cette classe directement, vous devrez passer par la classe statique ToolTipService et ses mthodes SetTool

Chapitre 5

Larbre visuel et logique

79

Tip et GetToolTip. ToolTip hrite de ContentControl, elle peut donc afficher nimporte quel enfant de type UIElement ou hritant de UIElement. Pour ajouter une bulle dinformation un objet graphique, il vous suffira daffecter la proprit ToolTip (du mme nom que la classe, attention donc aux confusions) de cet objet. Cette proprit est attribue par dfaut aux objets de larbre visuel par la classe ToolTipService. ToolTip est une proprit dite attache, elle nest pas hrite mais attribue dynamiquement. Nous reviendrons sur cette notion tout au long de ce chapitre.

5.1.2.5 Conteneurs de mise en forme


Comme nous lavons vu lors des chapitres prcdents, les conteneurs enfants multiples facilitent la mise en page et la cration dapplications redimensionnables. Ce chapitre leur est ddi en grande partie, car ils constituent le fondement de toute application Silverlight. Ces conteneurs particuliers hritent de la classe abstraite Panel. De nombreuses notions et proprits propres ces composants sont bases sur les mmes concepts existant au sein du langage HTML. Lorsque vous imbriquez un contrle au sein dun conteneur, lobjet imbriqu reoit automatiquement des proprits dites attaches. Par exemple, lorsque nous avons utilis la grille dalignement au Chapitre2, les objets imbriqus en son sein ont automatiquement reu des proprits attribues par la grille (voir Figure5.2).
Figure5.2
Proprits hrites dynamiquement dun conteneur Grid.

Exemples de proprits attribues dynamiquement un objet par son conteneur de type Grid

Voici la liste des conteneurs de type Panel les plus courants:

Canvas. Cest le conteneur le moins contraignant et le plus simple. Il faut considrer le conteneur Canvas comme un point dans lespace partir duquel les objets qui y sont contenus sont positionn. Les enfants de ce conteneur peuvent donc avoir des coordonnes positives ou ngatives. Il peuvent donc tre en dehors du Canvas, mais sont affichs dans tous les cas. Le redimensionnement dun Canvas via ses proprits Width et Height naffecte en rien la position ou laffichage de ses enfants (voir Figure5.3). Les objets contenus au sein dun Canvas rcuprent automatiquement les proprits Top et Left attribues par celui-ci. Lorsquune proprit est de type attache, cela est visible dans le XAML. Les proprits Top et Left sont prfixes de Canvas, comme le montre le code XAML ci-dessous:
<Canvas Margin="75,110,161,80"> <Button Height="27" Width="72" Content="Button" Canvas.Left="45" Canvas.Top="29"/> </Canvas>

80

Partie I

Approches de Silverlight

Figure5.3
Composants imbriqus au sein dun Canvas.

DockPanel permet de docker des objets en leur attribuant un espace dans une des quatre directions. Les composants quil contient pourront tre docks gauche, en haut, droite ou en bas du DockPanel. Lordre dans lequel ceux-ci sont imbriqus, ainsi que les valeurs Width et Height de ces composants, dterminent lespace qui leur est allou et celui restant pour les autres composants du DockPanel. cette fin DockPanel bnficie de la proprit boolenne LastChildFill, qui permet de spcifier si le dernier lment imbriqu remplit ou non la totalit de lespace restant. Par dfaut cette proprit est true, ce qui nest pas le cas pour le DockPanel de la Figure 5.4 puisquil reste une place libre.

Figure5.4
Composants imbriqus au sein dun DockPanel.

Grid est un composant dagencement trs puissant et souple dutilisation. Il est assez complexe et permet de rsoudre la majorit des problmatiques dagencement. Cest pour cette raison que ce composant est directement plac au sein du UserControl racine lors de la cration dun projet Silverlight. Ce composant propose des options de mise en page trs semblables ce que vous pouvez raliser en HTML et CSS avec les balises de type DIV. Il sagit en ralit dune grille qui peut contenir un nombre indfini de colonnes et de lignes. Comme vous avez pu le voir dans les chapitres prcdents, il contraint automatiquement les objets qui sont imbriqus en son sein. StackPanel permet dempiler les objets les uns aprs les autres dans la direction horizontale ou verticale. Comme vous lavez constat, les options de marges influencent directement le positionnement des objets empils les uns par rapport aux autres. WrapPanel possde le mme comportement que StackPanel, mais renvoie la ligne automatiquement (voir Chapitre 4).

Chapitre 5

Larbre visuel et logique

81

Ces composants rpondent la grande majorit des besoins en matire dagencement. Toutefois, vous devrez tendre la classe Panel pour crer vos propres conteneurs personnaliss. Cette classe possde cette fin deux mthodes virtuelles, MeasureOverride et ArrangeOverride. Vous devrez donc les surcharger lorsque vous crerez vos propres conteneurs. Tous les composants hritant de Panel partagent la proprit Children. Cette dernire est un ensemble de contrles UIElement donnant accs aux enfants du conteneur, qui seront forcment accessibles car ce sont des objets graphiques. Ils sont donc au moins de type UIElement. Ce quon appelle larbre visuel et logique dune application est en fait lensemble des objets affichs ainsi que leurs relations enfant parent. Trois proprits permettent ainsi dimbriquer les lments: Content pour les contrles de type ContentControl, Children pour les conteneurs hritant de Panel et Child pour tous les autres conteneurs spcifiques, tels que ViewBox par exemple. Nous allons maintenant nous intresser la proprit Children et apprendre grer la liste daffichage dun conteneur de type Panel.

5.2 Principe dimbrication 5.2.1 Ordre dimbrication


La proprit Children de la classe Panels tant une collection, il est possible daccder ses enfants par un index numrique correspondant son ordre dimbrication. Lordre dimbrication influe sur deux ples: le design pur et la conception.

5.2.1.1 Du point de vue design


Le design est influenc car lordre dimbrication impacte directement lordre de superposition des objets les uns par rapport aux autres, de la mme manire que les calques sous Photoshop ou Expression Design (voir Figure5.5). Voici un exemple dagencement au sein dune grille. Comme vous le remarquez, rectangle0 est en dessous des autres dun point de vue visuel. Il est situ lindex 0 de la liste daffichage, toutefois au sein de Blend il est reprsent en haut de la liste daffichage dans larbre visuel. Blend affiche par dfaut larbre visuel en respectant lordre de cration XAML. Le code XAML ci-dessous correspond larbre visuel affich la Figure5.5:
<Grid x:Name="LayoutRoot" Background="#FFFFFFFF"> <Rectangle x:Name="rectangle0" Fill="#FF4B7145" Stroke="#FF000000" Height="108" HorizontalAlignment="Left" Margin="137,89,0,0" VerticalAlignment="Top" Width="118"/> <Rectangle x:Name="rectangle1" Fill="#FF5F9657" Stroke="#FF000000" Height="89" HorizontalAlignment="Left" Margin="198,146,0,0" VerticalAlignment="Top" Width="122"/> <Rectangle x:Name="rectangle2" Fill="#FF8CAC95" Stroke="#FF000000" Margin="255,201,249,191"/> <Rectangle x:Name="rectangle3" Fill="#FFB0BF9D" Stroke="#FF000000" Margin="306,239,218,167"/> <Rectangle x:Name="rectangle4" Fill="#FF8DDB86" Stroke="#FF000000" Height="67" HorizontalAlignment="Right" Margin="0,0,180,136" VerticalAlignment="Bottom" Width="95"/> </Grid>

82

Partie I

Approches de Silverlight

Lordre propos par dfaut est donc assez logique dun point de vue architecture. Larbre visuel peut au dpart vous induire en erreur si vous tes habitu dautres logiciels car lobjet le plus haut dans larbre est celui situ le plus larrire-plan par rapport aux autres. Vous pouvez tout moment changer ce mode de prsentation en cliquant sur le bouton situ en bas gauche de larbre visuel ( ). Toutefois, vous vous habituerez trs vite cette reprsentation car elle est cohrente avec lordre des balises XAML gnres.
Figure5.5
Ordre dimbrication et index daffichage.

5.2.1.2 Du point de vue conception


Dun point de vue conception, lordre dimbrication est dterminant car il impose souvent le positionnement des objets au sein des conteneurs. Lagencement des enfants au sein dun contrle StackPanel ou WrapPanel, par exemple, en est une consquence directe comme vous avez pu le constater au Chapitre4 (voir Figure5.4 et 5.6).
Figure5.6
Influence de lindex de lobjet enfant au sein dun WrapPanel.

Le bouton le plus droite au sein du WrapPanel est ContactBtn. Il sagit en fait du dernier bouton imbriqu et du seul qui est nomm. Il possde lindex 4. Lindex influence donc galement larchitecture mme de lapplication. Voici le code XAML reprsent la Figure5.6:
<controls:WrapPanel Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="Auto" Margin="30,10,90,0" d:LayoutOverrides="Width"> <Button Height="Auto" Width="Auto" Content="Nouveauts" Margin="0,0,20,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible" /> <Button Height="Auto" Width="Auto" Content="Portfolio" Margin="0,0,20,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible"/> <Button Height="Auto" Width="Auto" Content="Mdias" Margin="0,0,20,0"

Chapitre 5

Larbre visuel et logique

83

FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible"/> <Button Height="Auto" Width="Auto" Content="Savoir faire" VerticalAlignment="Stretch" Margin="0,0,20,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible"/> <Button x:Name="ContactBtn" Height="Auto" Width="Auto" Content="Contact" Margin="0,0,0,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible"/> </controls:WrapPanel>

NOTE INFO

Nommer les objets est dune aide prcieuse dans de nombreux cas. Mme si ce nest pas toujours obligatoire dun point de vue technique, cela permet aux dveloppeurs et aux designers interactifs de communiquer simplement et dviter les malentendus. Ces deux profils sont concerns par le nommage. Donner un nom un objet consiste dfinir sa fonctionnalit et par consquent une partie de larchitecture. Le dveloppeur est en gnral trs concern par cette phase, il doit donc veiller ce que les intgrateurs ne perdent pas de temps sur la comprhension de larbre visuel.

Parfois, le dveloppeur voudra manipuler un objet non nomm ou rorganiser une interface en arrangeant la liste daffichage. Le graphiste, quant lui, souhaitera tout de mme grer la superposition des lments les uns entre les autres sans soccuper directement de larchitecture ou de la conception technique. Nous allons aborder les mthodes et techniques qui rpondent ces problmatiques en nous efforant de garder un flux de production souple et en prservant les rles de chacun.

5.2.2 Accder aux objets de larbre visuel


5.2.2.1 Accder un composant nomm
Un objet nomm est facile cibler car lorsquun objet est nomm, il devient un champ priv de la classe de lapplication. Il faut en effet garder lesprit que tout ce que nous produisons au sein du fichier XAML est en ralit cr au sein de la classe partielle. Un dveloppeur na qu crire le nom dun objet dclar dans le XAML suivi dun point pour accder tous ses membres. Nous pourrions de cette manire facilement accder au bouton ContactBtn (voir Figure5.7).
Figure5.7
Accder aux objets nomms.

84

Partie I

Approches de Silverlight

Toutefois, vous naurez pas toujours la possibilit de connatre le nom dun objet lavance ou encore de nommer tous les objets dans Blend. Nous allons donc apprendre accder un objet anonyme.

5.2.2.2 Accder un composant anonyme


Ouvrez le projet SiteAgencePortfolio cr lors du prcdent chapitre. Pour atteindre un objet prsent au sein de la liste daffichage dun conteneur, il suffit de cibler son index. Nous allons changer le texte du bouton anonyme reprsentant les nouveauts par le texte Accueil en procdant par tape. tudions larbre visuel et logique de notre projet (voir Figure5.8). Le bouton des nouveauts est situ lindex 0 du WrapPanel. Pour latteindre, nous devrons utiliser la proprit Children du WrapPanel. Cependant, le WrapPanel nest lui-mme pas nomm. Nous devrons donc galement utiliser lindex enfant de celui-ci au sein du conteneur nomm LayoutRoot.
Figure5.8
Arbre visuel du projet SiteAgencePortfolio.

Voici comment accder lindex 0 via la proprit Children dun composant de type Panel:
MonConteneur.Children[0]

Pour accder lobjet WrapPanel, qui est le premier enfant de LayoutRoot, on crira donc:
LayoutRoot.Children[0];

Pour des raisons de conception, Children est une collection dUIElement. Les enfants dun conteneur peuvent tre de type diffrent les uns en les autres, mais ils hritent tous de la classe UIElement mre de toutes les classes daffichage. Elle semble donc idale pour reprsenter le type gnral des objets stocks dans la proprit Children. Nous naurons donc pas accs dans un premier temps aux membres de la classe WrapPanel mais plutt aux membres de la classe UIE lement. Nous devrons transtyper la rfrence rcupre en WrapPanel, puis stocker sa valeur au sein dune rfrence de mme type:
WrapPanel menuHaut = LayoutRoot.Children[0] as WrapPanel;

Vous pouvez tous moments rcuprer le type dun objet via la mthode hrite de Object, Get Type(). Voici comment faire:

Chapitre 5

Larbre visuel et logique

85

LayoutRoot.Children[0].GetType();

La mthode GetType() renvoie un objet Type. Cet objet fournit toutes les informations que vous souhaitez obtenir sur la classe relle de lobjet. Vous pouvez rcuprer le nom de la classe via sa proprit Name. Il suffit ensuite de lafficher dans le champ texte au centre du site, de cette manire:
WrapPanel menuHaut = LayoutRoot.Children[0] as WrapPanel; if (menuHaut != null) { string nomType = menuHaut.GetType().Name; TitrePage.Text = nomType; }

Lorsque vous compilez, vous pouvez constater quil sagit bien dun WrapPanel. Si vous souhaitez vrifier quil contient les menus, il faut regarder le nombre de ses enfants grce la proprit Count de Children:
WrapPanel menuHaut = LayoutRoot.Children[0] as WrapPanel; if (menuHaut != null) { string nomType = menuHaut.GetType().Name; TitrePage.Text = nomType+" - Nb enfants : "+ menuHaut.Children.Count; }

Pour modifier le champ texte du premier bouton, nous devons le cibler via Children, accder sa proprit Content et affecter celle-ci:
Button un = menuHaut.Children[0] as Button; un.Content = "Accueil";

5.2.2.3 Grer les erreurs d'accs


Que se passe-t-il lorsque nous essayons daccder un index indfini de la liste daffichage ? Pour le savoir, il vous suffit dessayer daccder lindex 5 de la liste denfants du WrapPanel. Celuici ne possdant que 5 enfants, le dernier index utilis est 4. Pour gnrer cette erreur, il faut donc crire:
Button Un = menuHaut.Children[5] as Button;

Compilez via le raccourci F5. Aucune exception nest leve en apparence, mais si vous regardez en bas gauche du navigateur Internet Explorer, vous apercevrez une icne jaune . Celle-ci vous indique une erreur au sein de lapplication Silverlight. Double-cliquez dessus pour faire apparatre le dtail de lerreur rencontre (voir Figure5.9). En ralit, Blend ne possde pas de vrai dbogueur comme Visual Studio. Les erreurs sont leves, mais ninterrompent pas lexcution de lapplication. Il nest donc pas possible de poser des points darrt, dafficher les valeurs des variables durant lexcution ou dafficher directement la ligne de code fautive ou lexception leve. Le designer qui ne remarquerait pas licne davertissement aurait la fausse impression quil sagit dun chec en silence. De plus, ainsi que vous pouvez le constater la Figure5.9, le numro de ligne spcifi dans le panneau derreur dans le navigateur nest pas vraiment le bon. Cependant, un designer interactif trouvera cela dj trs utile car lerreur renvoye est la bonne:

86

Partie I

Approches de Silverlight

Largument spcifi ntait pas dans les limites de la plage de valeurs valide. nom du paramtre : index

Figure5.9
Erreur leve au sein du navigateur.

Visual Studio offre un environnement plus confortable pour dboguer une application. Nous allons compiler la solution dans ce logiciel. Cliquez-droit sur la solution dans le panneau Projet et slectionnez Ouvrir dans Visual Studio. Une fois le projet ouvert sous Visual Studio, recompilez-le via le raccourci F5. Ds le chargement de lapplication, le dbogueur lve une exception et affiche la ligne de code posant problme (voir Figure5.10).
Figure5.10
Erreur leve par le dbogueur.

Il est ainsi plus rapide et pratique de trouver do vient notre erreur car si le message est le mme, la ligne de code fautive est correctement localise.
NOTE INFO

Lun des avantages majeurs du dbogueur est de pouvoir rcuprer les valeurs des rfrences durant lexcution de lapplication. Il suffit pour cela de positionner votre souris au-dessus dune variable lorsquune erreur est leve ou lorsque vous avez pos un point darrt. Pour poser un point darrt, cliquez gauche de la ligne sur laquelle vous le souhaitez dans lditeur de code. Vous pouvez galement cliquer droit sur la ligne o vous dsirez que lexcution soit stoppe, puis slectionner Breakpoint (Point darrt) et Insert Breakpoint (Ajouter un point darrt) voir Figure5.11.

Chapitre 5

Larbre visuel et logique

87

Figure5.11
Insrer un point darrt.

Examinons maintenant la valeur de linstance du bouton Un lexcution. Pour cela, positionnez votre souris au-dessus de sa rfrence (voir Figure5.12).
Figure5.12
Valeur de la rfrence Un de type Button.

La valeur du bouton Un est null. Lexpression droite du signe gal ne renvoie donc aucune valeur. Positionnez votre souris au-dessus de la proprit Children pour explorer son contenu (voir Figure5.13).
Figure5.13
Exploration de la proprit Children dun conteneur grce au dbogueur.

Nous nous apercevons que cette proprit ne possde que 5 lments, indexs de 0 4. Cibler lindex 5 revient cibler un sixime lment indfini dans cette collection. Nous mettons donc facilement en vidence lerreur leve. Parfois, pour diverses raisons, par exemple pour montrer lapplication une tierce personne, vous ne souhaiterez pas lancer le dbogueur de Visual Studio. Il suffit dans ce cas dutiliser le raccourci Ctrl+F5. Celui-ci permet une compilation quivalente celle fournie par Blend en ne lanant pas le dbogueur.

5.2.3 Parcourir la liste des enfants


Nous allons maintenant apprendre parcourir la liste des enfants grce aux boucles. Il peut tre trs pratique de parcourir la collection denfants Children pour affecter ou rcuprer les proprits de ceux-ci. Nous allons procder par tapes. Tout dabord, nous allons crer une mthode de parcours dans la classe MainPageMainPage. Celle-ci aura pour but de crer une reprsentation de larbre visuel sous forme de chane de caractres. Pour visualiser la chane de caractres, il vous faudra crer un composant TextBlock qui nous affecterons la proprit Text. La mthode doit

88

Partie I

Approches de Silverlight

recevoir comme paramtre le conteneur de type Panel que nous souhaitons parcourir ainsi que la valeur de tabulation. En voici une bauche:
private void ParcoursArbreVisuel ( Panel container, string tab ) { }

Voyons comment lcrire avec une boucle for:


private void ParcoursArbreVisuel ( Panel container, string tab ) { // Les deux critures suivantes sont utilisables //int Lng = container.Children.Count; var Lng = container.Children.Count; for (var i=0; i < Lng; i++) { } }

Crez maintenant le TextBlock nimporte o dans la grille principale LayoutRoot et nommez-le ArbreTxt. Ce champ texte va nous permettre dafficher notre arbre visuel. Chaque fois que nous trouverons un enfant, nous concatnerons le nom de sa classe suivi de son nom dinstance si celleci est nomme:
private void ParcoursArbreVisuel ( Panel container, string tab ) { // Les deux critures suivantes sont utilisables //int Lng = container.Children.Count; var Lng = container.Children.Count; for (var i=0; i < Lng; i++) { //on rcupre le nom de la classe de chaque enfant ArbreTxt.Text += tab + container.Children[i].GetType().Name; // On rcupre le nom de l'instance rcupre string nom = (container.Children[i] as FrameworkElement ).Name; // si l'instance est nomme if (!String.IsNullOrEmpty(nom)) { ArbreTxt.Text += " - " + nom; } //On va la ligne grce au caractre d'chappement n ArbreTxt.Text += "\n";

} }

Loprateur + au dbut de la boucle permet de concatner des chanes de caractres. Concatner une chane revient gnrer une chane en juxtaposant plusieurs autres chane de caractres les unes aux autres. La proprit Name est utilise deux fois dans la boucle: la premire fois pour rcuprer le nom de lobjet Type retourn, la seconde fois pour retrouver le nom de linstance.

Chapitre 5

Larbre visuel et logique

89

Toutefois, la proprit Name nest pas hrite de UI Element, mais de FrameworkElement. Nous sommes donc oblig de transtyper (convertir le type) UIElement en FrameworkElement. Le motcl as permet de considrer un type en lieu et place dun autre type. Pour finir, grce au caractre dchappement \, le caractre n est considr comme un retour la ligne. Cette mthode nous permet de lister tous les objets situs dans LayoutRoot. Il nous faut maintenant lappeler au sein de la mthode MainPage_Loaded:
private void MainPage_Loaded(object sender, RoutedEventArgs e) { ArbreTxt.Text = LayoutRoot.GetType().Name+" - "+LayoutRoot.Name+"\n"; //appel de la mthode ParcoursArbreVisuel( LayoutRoot, "\t" ); }

Lors de cet appel, nous listons le premier niveau dimbrication, soit tous les objets prsents dans LayoutRoot. Pour cette raison, nous passons la chane de caractres "\t" correspondant une seule tabulation (voir Figure5.14).
Figure5.14
Affichage des enfants de LayoutRoot.

Nous navons affich que le premier niveau dimbrication, mais il serait intressant de parcourir larbre visuel dans sa totalit. Pour cela, nous pouvons transformer notre mthode en mthode rcursive. Une mthode rcursive est une fonction capable de sappeler ellemme tant quune condition est ralise. Notre condition est simple : chaque fois que nous listons un enfant, nous pouvons vrifier sil est de type Panel. Dans ce cas il peut donc contenir des objets enfants. Vrifier le type Panel est pratique : que lenfant soit un WrapPanel, un Stack Panel ou un DockPanel importe peu car notre mthode sera r-invoque dans tous ces cas. Voici la mthode de parcours amliore:
private void ParcoursArbreVisuel ( Panel container, string tab ) { // Les deux critures suivantes sont utilisables //int Lng = container.Children.Count; var Lng = container.Children.Count; for (var i=0; i < Lng; i++) { //on rcupre le nom de la classe de chaque enfant ArbreTxt.Text += tab + container.Children[i].GetType().Name;

90

Partie I

Approches de Silverlight

// On rcupre le nom de l'instance rcupre string nom = (container.Children[i] as FrameworkElement ).Name; // si l'instance est nomme if (!String.IsNullOrEmpty(nom)) { ArbreTxt.Text += " - " + nom; } // On saute une ligne grce au caractre d'chappement n ArbreTxt.Text += "\n"; // Si l'enfant que l'on vient de lister est aussi un Panel // alors on appelle nouveau la mthode de parcours Panel panel = container.Children[i] as Panel; if (panel != null) { ParcoursArbreVisuel( panel,"\t\t"); } } }

Vous devriez obtenir un rsultat proche de la Figure5.15.


Figure5.15
Affichage rcursif.

La boucle for nest pas la plus adquate car Children de type UIElementCollection implmente linterface IEnumerable. Celle-ci dcrit les mthodes permettant le parcours de la collection avec une boucle foreach. Le code est bien plus simple crire dans ce cas, le voici mis jour:
private void ParcoursArbreVisuel ( Panel container, string tab ) { foreach (UIElement enfant in container.Children) { ArbreTxt.Text += tab + enfant.GetType().Name; string nom = (enfant as FrameworkElement ).Name; if (!String.IsNullOrEmpty(nom)) { ArbreTxt.Text += " - " + nom; }

Chapitre 5

Larbre visuel et logique

91

ArbreTxt.Text += "\n"; Panel panel = enfant as Panel; if (panel != null) { ParcoursArbreVisuel( panel,"\t\t"); } } }

Nous allons en rester l pour le parcours de larbre visuel. Toutefois, trois proprits permettent limbrication, comme nous lavons dit au dbut de ce chapitre : Children, Child et Content. Pour parcourir la totalit de larbre visuel de notre application, nous devrions galement tester si lenfant est de type ContentControl ou si celui-ci possde la proprit Child. Derrire ces proprits peut se cacher une imbrication labore et complexe. Vous pouvez tlcharger lexercice pleinEcran_parcours.zip dans le dossier chap5 des exemples.

5.3 Ajouter des enfants la liste daffichage


Ajouter des enfants en cours dexcution est une opration courante. Cela nous permet de faire vivre et voluer lapplication. Les applications dynamiques apportent une exprience utilisateur trs diffrente car elles voluent lors de leur utilisation, dans des directions quelquefois surprenantes. Cela ajoute une profondeur aux applications et les rend plus attractives, donnant envie den explorer tous les recoins. Nous allons maintenant apprendre raliser ces oprations en ajoutant des objets la vole, puis en reconstruisant la totalit de notre menu de manire dynamique.

5.3.1 Mcanisme dinstanciation dobjets graphiques


Cela peut paratre trange, mais lorsque le graphiste cre des objets graphiques au sein de Expression Blend, il accomplit en ralit deux choses diffrentes. Il commence par instancier lobjet en le dcrivant au sein dune balise:
<Button Height="Auto" Width="Auto" Content="Portfolio" Margin="0,0,20,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible" />

Toutefois, cela ne suffit pas, le bouton ne safficherait pas sil ne faisait pas partie de larbre visuel. Il doit donc appartenir lun des objets de cet arbre. Un conteneur de type Grid fait laffaire. La deuxime tape ralise sans rellement y prter attention est donc la cration du lien de parent avec son conteneur:
<Grid x:Name="LayoutRoot" Background="#FFFFFFFF" Margin="0,0,0,0" > <Button Height="Auto" Width="Auto" Content="Portfolio" /> </Grid>

Au sein de Blend, cette tape est naturelle puisque lon ne peut crer des objets quau sein de larbre visuel (voir Figure5.16).

92

Partie I

Approches de Silverlight

Figure5.16
Mcanisme dajout dobjets graphiques larbre visuel.

Instance de App

tape 2 : Affectation du bouton un objet parent prsent dans l'arbre visuel Hello Button

Proprit RootVisual

UserControl racine de MainControl.xaml

Grille principale LayoutRoot

tape 1 : Instanciation du bouton Hello Button WrapPanel

Rectangle

TextBlock

ATTENTION

Linstance du plug-in Silverlight possde la proprit RootVisual hrite de la classe Appli cation. Celle-ci renvoie une instance du UserControl racine du fichier MainPage.xaml. Tout objet appartenant directement ou indirectement la proprit RootVisual fait partie de larbre visuel de lapplication. Lors de linitialisation de lapplication, cette proprit est en fait affecte au sein du fichier App.xaml.cs, dans la classe App :
private void OnStartup(object sender, StartupEventArgs e) { // Chargement de larborescence contenue dans MainPage.xaml this.RootVisual = new MainPage(); }

Cette proprit est galement accessible en C# partir de nimporte quel fichier XAML. Vous pouvez latteindre en ciblant la proprit statique Current de la classe App:
App.Current.RootVisual

La proprit statique Current de la classe App renvoie linstance actuelle de lapplication.

5.3.2 Ajouter et insrer des objets dans larbre


Ajoutons un nouveau menu dans la barre. Nous allons raliser la premire tape consistant instancier un bouton via C#:

Chapitre 5

Larbre visuel et logique

93

WrapPanel menuHaut = LayoutRoot.Children[0] as WrapPanel; // on instancie le bouton Button clientMenu = new Button(); // on lui spcifie de nouvelles marges clientMenu.Margin = new Thickness(20,0,0,0); // on lui affecte une nouvelle police clientMenu.FontFamily = new FontFamily("Trebuchet MS"); // on dfinit une taille de police clientMenu.FontSize = 14; // on affecte sa proprit Content pour afficher une chane de caractres clientMenu.Content = "Nos Clients";

Dans tous les cas nous utiliserons le mot-cl new. Cela semble trange, mais la proprit Margin est de type Thickness. Cest une manire dconomiser le poids du lecteur Silverlight car la valeur est structure de la mme manire quun objet dpaisseur, de type Thickness. Le premier chiffre indique la marge gauche, puis le deuxime la marge haute, et ainsi de suite dans le sens des aiguilles dune montre. Comme nous pouvons le voir, affecter une police est assez simple. La police Trebuchet MS possde lavantage dtre embarque par dfaut dans le lecteur Silverlight. Il est donc facile de laffecter au bouton. Vous remarquez que nous navons spcifi aucune largeur ou hauteur. Lorsque vous ne prcisez pas ces valeurs, celles-ci sont par dfaut en mode Auto. Pour finir, il suffit dafficher un texte au sein de notre bouton. La seconde phase est plus facile, nous allons utiliser la mthode Add:
// on ajoute ce bouton la liste des enfants du WrapPanel menuHaut.Children.Add(ClientMenu);

La mthode Add najoute pas les objets au hasard, en fait elle ajoute lobjet la fin de la liste denfants, donc un nouvel index. Notre menu contenait 5 lments indexs de 0 4. la fin du chargement de lapplication, le menu contient dsormais 6 lments. Le sixime lment ajout dynamiquement est situ au dernier et nouvel index, soit 5. Cela est particulirement facile constater dans un conteneur de type WrapPanel car lindex affecte directement lordre des objets imbriqus (voir Figure5.17).
Figure5.17
Ajout dune rubrique Button avec la mthode Add.

La mthode Add nappartient pas lobjet lui-mme mais sa proprit de type UI ElementCollection. Lorsque vous voudrez manipuler les enfants ou la liste elle-mme, il faudra utiliser les membres (proprits et mthodes) de celle-ci. Cette opration est finalement assez facile, toutefois, notre nouveau menu nest pas vraiment sa place. Il serait plus judicieux de le placer entre les menus Savoir faire et Contact. Cela est facile raliser grce la mthode Insert:
menuHaut.Children.Insert(4,ClientMenu);

Il faut commencer par prciser lindex auquel lobjet sera positionn, puis le composant graphique insrer. Modifiez si besoin la proprit Margin pour une mise en forme adapte (voir Figure5.18).

94

Partie I

Approches de Silverlight

Figure5.18
Insertion dune rubrique Button avec la mthode Insert.

Lorsque vous accomplissez une telle opration, vous dcalez de 1 chaque objet imbriqu suivant lindex dinsertion au sein de la liste denfants.

5.3.3 Erreurs leves


Plusieurs erreurs peuvent tre leves lors de lappel de ces mthodes. La premire arrive lorsque vous passez un index aberrant la mthode Insert. Lorsque vous spcifiez un index dpassant le nombre denfants, soit Children.Count, le compilateur lve une erreur correspondant celle leve lors dune tentative daccs un index indfini (voir section "Grer les erreurs daccs", plus haut dans ce chapitre). Il est en effet illogique dinsrer un objet un index suprieur au nombre denfants. Si vous souhaitez connatre lindex du dernier enfant de la collection, il suffit de retrancher 1 Children.Count. Insrer un enfant lindex Children.Count revient utiliser la mthode Add. La deuxime erreur est leve si vous essayez de dplacer un objet graphique dj prsent dans la liste denfants dun autre conteneur. Ce cas est plus pernicieux. Lune des rgles daffichage est quune rfrence dobjet graphique ne peut tre situe en mme temps dans deux conteneurs diffrents. Lorsque vous attribuez un objet prsent dans larbre visuel un autre conteneur, une exception est leve. Elle vous indique que lobjet est dj prsent ailleurs (voir Figure5.19). Pour vous en convaincre, il suffit dajouter au StackPanel, notre pied de page, un lment prsent dans le WrapPanel, notre menu du haut de page:
WrapPanel menuHaut = LayoutRoot.Children[0] as WrapPanel; StackPanel footer = LayoutRoot.Children[1] as StackPanel; Footer.Children.Add(menuHaut.Children[0] );

Figure5.19
Exception leve lors de limbrication dun lment appartenant dj un autre conteneur.

Pour rsoudre cette problmatique, vous devrez supprimer lenfant de la liste de son ancien conteneur, puis invoquer la mthode Add ou Insert. Pour savoir si un enfant est contenu au sein dune liste de type UIElementCollection (Children est de ce type), il suffit dutiliser les mthode Contains ou IndexOf:

Chapitre 5

Larbre visuel et logique

95

menuHaut.Children.Contains(Toto); // renvoie false car Toto n'existe pas menuHaut.Children.Contains(ContactBtn); // renvoie true car Contact est bien un enfant de menuHaut menuHaut.Children.IndexOf(Titi); // renvoie -1 car Titi n'est pas prsent dans la liste des enfants menuHaut.Children.IndexOf (ContactBtn); // renvoie 4 car ContactBtn est le 5ime lments contenu

Pour de plus amples informations sur la suppression dobjets graphiques, vous pouvez consulter la section 5.4.

5.3.4 Crer un menu dynamique


Nous allons maintenant recrer le menu principal de toutes pices. Pour cela, depuis la fentre de design, supprimons tous les boutons de menu du WrapPanel. Dans la mthode MainPage_Loaded, il nous faut galement supprimer toutes les rfrences vers ces menus sauf la ligne permettant de rcuprer une rfrence du WrapPanel:
WrapPanel menuHaut = LayoutRoot.Children[0] as WrapPanel;

Pour crer un menu lexcution, il est plus pratique de crer un tableau de chane de caractres. Ensuite, nous pourrons le parcourir. chaque fois que nous trouverons un lment contenu dans le tableau, nous instancierons dynamiquement un nouveau bouton dans le WrapPanel. Le tableau doit tre un champ priv de la classe MainPage, ainsi il sera accessible et modifiable partir de nimporte quelle mthode de la classe. Voici comment le dclarer:
public partial class MainPage : UserControl { string [] tabMenus = new string[]{"Accueil", "Portfolio", "Medias", "Savoir faire","Contact"}; public MainPage() { InitializeComponent(); Loaded +=new RoutedEventHandler(MainPage_Loaded); } private void MainPage_Loaded(object sender, RoutedEventArgs e) { PleinEcranBT.Cursor = Cursors.Hand; WrapPanel menuHaut = LayoutRoot.Children[0] as WrapPanel; } }

Ensuite, nous pouvons dfinir la nouvelle mthode CreateMenus sur la classe MainPage et lappeler lors du chargement de lapplication. La variable MenuHaut est une variable locale la mthode MainPage_Loaded. Cela signifie que la variable nexiste et nest accessible que dans cette mthode. Pourtant, nous en avons besoin au sein de la mthode Create Menus pour ajouter des lments graphiques sa liste denfants. ce stade, vous avez trois choix : soit vous crez un champ MenuHaut dans votre classe, puis vous laffectez au sein de la mthode MainPage_Loaded, soit vous passez MenuHaut comme paramtre de la mthode CreateMenus ou alors vous faites

96

Partie I

Approches de Silverlight

les deux. Il peut tre pratique de crer les boutons de menu dans un autre conteneur si besoin. La mthode CreateMenus mrite donc un paramtre. Toutefois, nous pourrions galement vouloir supprimer tous les objets contenus au sein du WrapPanel dans une autre fonction. Cela peut donc tre utile den stocker une rfrence en tant que membre de la classe MainPage. Voici comment procder :
public partial class MainPage : UserControl { string [] tabMenus = new string[5]{"Accueil", "Portfolio", "Medias", "Savoir faire","Contact"}; // on dclare un champ de type WrapPanel WrapPanel menuHaut; public MainPage() { InitializeComponent(); Loaded +=new RoutedEventHandler(MainPage_Loaded); } private void MainPage_Loaded(object sender, RoutedEventArgs e) { PleinEcranBT.Cursor = Cursors.Hand; // on affecte le champ de type WrapPanel menuHaut = LayoutRoot.Children[0] as WrapPanel; if (menuHaut!=null) { // on passe le conteneur menuHaut comme paramtre de CreateMenus CreateMenus(menuHaut); } } // cette mthode pourra crer des menus quel que soit le conteneur ;) private void CreateMenus(Panel conteneur) { } }

Typer le paramtre en tant que Panel est pratique car nous pourrons spcifier nimporte quel conteneur hritant de ce type, pour centraliser les menus. La mthode Insert nest pas idale dans notre cas car il faudrait que des composants soient dj prsents dans notre WrapPanel. La mthode Add est la plus adquate car elle ajoute les menus au fur et mesure. Lordre de notre tableau sera donc respect. Voici la dfinition de la mthode CreateMenus:
private void CreateMenus(Panel conteneur) { foreach(string titre in TabMenus) { // on instancie le bouton Button monMenu = new Button(); // on lui spcifie de nouvelles marges monMenu.Margin = new Thickness(0,0,20,0); // on lui affecte une nouvelle police monMenu.FontFamily = new FontFamily("Trebuchet MS"); // on dfinit une taille de police

Chapitre 5

Larbre visuel et logique

97

monMenu.FontSize = 14; // on affecte sa proprit Content pour afficher // une chane de caractres monMenu.Content = titre; // on ajoute ce bouton la liste des enfants du WrapPanel conteneur.Children.Add(monMenu); } }

Comme vous pouvez le voir, mis part spcifier les marges de chaque bouton, nous navons rien coder concernant le placement des menus. Cest le conteneur WrapPanel qui soccupe de cette partie.
NOTE INFO

Dans cet exercice, nous aurions pu utiliser une classe Rubrique et crer un tableau dinstances de rubrique. Lavantage est non seulement de pouvoir dcrire et afficher plus quune simple chane de caractres, mais aussi de dfinir des vnements et mthodes spcifiques. Ce genre dinstance est appele Value Object. Ce sont des instances dont le rle majeur est de contenir les enregistrements rcuprs depuis une base de donnes tout en les adaptant au modle objet. Cest gnralement la mthodologie suivre lorsque le site est vritablement mis jour depuis lextrieur.

Vous trouverez le projet finalis dans larchive pleinEcran_dynamique.zip du dossier chap5.

5.3.5 Affecter les proprits Child et Content


Nous allons voquer rapidement les proprits Child et Content. Elles occupent une place importante en matire dimbrication. Il suffit de voir le nombre dobjets hritant de ContentControl ou assurant une logique dimbrication spcifique pour sen convaincre. Ces proprits pourraient en effet stocker un conteneur enfants multiples, qui lui-mme contiendrait de nombreux objets. Il ny a pas de limites en la matire. La Figure5.20 illustre un exemple dimbrication ralis dans Blend par un graphiste, avec les trois proprits Children, Child et Content.
Figure5.20
Exemple darbre visuel utilisant les trois proprits dimbrication.

Dans lexemple de la Figure 5.20, le composant Border permet de grer laffichage et le graphisme de la barre de lecture. Sa proprit Child est affecte dun StackPanel empilant horizontalement des boutons personnaliss via sa proprit Children. Le bouton stop utilise sa proprit Content pour tre affect dun simple rectangle. Vous remarquez que le bouton playPause est un bouton de type ToggleButton. Pour rappel, la classe CheckBox hrite de ToggleButton et ne se diffrencie que par son visuel fait pour simplifier la vie au graphiste. Il possde deux tats, lun reprsentant une icne de lecture, lautre une icne pause. Pour ajouter un enfant via les proprits Child et Content en C#, il suffit de les affecter:

98

Partie I

Approches de Silverlight

MonBorder.Child = new StackPanel(); MonBoutonStop.Content = new Rectangle();

Noubliez pas cependant que si vous raffectez ces proprits lexcution, le nouvel objet affect remplacera lancien:
MonBorder.Child = new StackPanel(); MonBorder.Child = new grid(); //

Le StackPanel ne sera jamais utilis dans le code prcdent car il est directement remplac par une grille. Vous naurez pas derreur leve : le nouvel enfant crase lancien.

5.3.6 vnement diffus


Lorsque vous ajoutez une instance de type FrameworkElement larbre visuel, elle diffuse lvnement Loaded. Nous allons couter lvnement Click sur le bouton ContactBtn. Lorsquil sera diffus, nous ajouterons le bouton ContactBtn dans le WrapPanel :
public partial class MainPage : UserControl { private Button clientMenu; public MainPage() { InitializeComponent(); Loaded +=new RoutedEventHandler(MainPage_Loaded); } private void MainPage_Loaded(object sender, RoutedEventArgs e) { // on instancie le bouton clientMenu = new Button(); // nous coutons l'vnement Loaded sur le bouton ClientMenu clientMenu.Loaded +=new RoutedEventHandler(clientMenu_Loaded); ContactBtn.Click +=new RoutedEventHandler(ContactBtn_Click); } private void ContactBtn_Click(object sender, RoutedEventArgs e) { WrapPanel menuHaut = LayoutRoot.Children[0] as WrapPanel; if (menuHaut!=null) { // on ajoute ce bouton la liste des enfants du WrapPanel menuHaut.Children.Insert(4,ClientMenu); } } private void clientMenu_Loaded(object sender, RoutedEventArgs e) { // Lorsque le bouton est ajout l'arbre visuel, // l'vnement Loaded est diffus pour le montrer // on affecte le champ texte central TitrePage.Text="Le bouton a t ajout et initialis."; }

Chapitre 5

Larbre visuel et logique

99

Toutefois, il faut faire attention au fait que nous parlons bien darbre visuel et non de la proprit Children. Si jamais la proprit Children, laquelle vous ajoutez un enfant, nappartient pas un objet de larbre visuel, alors lvnement Loaded ne sera pas diffus:
private void ContactBtn_Click(object sender, RoutedEventArgs e) { StackPanel unConteneur = new StackPanel(); // on ajoute ce bouton la liste des enfants du StackPanel menuHaut.Children.Insert(4,clientMenu); } private void clientMenu_Loaded(object sender, RoutedEventArgs e) { // Lorsque le bouton est ajout au StackPanel // l'vnement Loaded n'est pas diffus car // le StackPanel ne fait pas partie de l'arbre visuel TitrePage.Text="Ce message ne doit pas tre trac."; }

Ainsi, le mme bouton ajout un conteneur absent de larbre visuel et logique ne diffusera pas dvnement Loaded.

5.4 Supprimer des objets de larbre visuel


Nous allons maintenant apprendre supprimer les enfants dun conteneur. Comme nous allons le voir, les mthodologies sont trs proches de celles que nous avons utilises pour ajouter des enfants.

5.4.1 Les diffrentes mthodes


5.4.1.1 Supprimer des enfants de conteneur Panel
Trois mthodes sont accessibles pour supprimer un objet de larbre visuel et logique: Remove, RemoveAt et Clear. Ces mthodes sont invoques par la proprit Children dun conteneur de type Panel. Voici leur syntaxe:
// 1 - La mthode Remove reoit la rfrence l'lment contenu menuHaut.Children.Remove( ContactBtn ); // 2 - La mthode RemoveAt doit recevoir l'index menuHaut.Children.RemoveAt( 2 ); // 3 - Clear n'a besoin d'aucun argument, la collection // de UIElement est simplement vide de son contenu menuHaut.Children.Clear( ); (ContactBtn.Parent as Panel).Children.Remove(ContactBtn);

La dernire ligne permet un objet dappeler la mthode Remove de son conteneur. Tous les objets de type FrameworkElement possdent la proprit Parent. Celle-ci renvoie la rfrence du conteneur parent de lobjet. Dans certains cas, il peut arriver que vous ne connaissiez pas la rfrence du conteneur lavance. Cette mthode rpond cette problmatique car chaque objet de larbre visuel possde une proprit parent non nulle.

100

Partie I

Approches de Silverlight

5.4.1.2 Supprimer des enfants uniques


Supprimer lenfant dun conteneur tel que Border ou ContentControl est trs simple. Pour ajouter un enfant au sein dun conteneur enfant unique, il nous a suffi daffecter une instance dUI Element aux proprits Content ou Child. Cette fois, il nous suffira daffecter la valeur null:
MonBorder.Child = null; MonBouton.Content = null;

ATTENTION

Lorsque vous excutez les mthodes de suppression de la liste denfants, vous ne supprimez que la valeur des proprits Children, Child ou Content. Les rfrences des enfants qui taient imbriqus existent toujours en mmoire si celles-ci taient des membres de classe. Nous verrons comment dsactiver des objets en mmoire la section "Dsactiver des objets".

5.4.2 Leffondrement de la liste denfants


5.4.2.1 Principe
Comme vous avez pu le remarquer lorsque vous avez compil votre application, la suppression dun objet au sein du StackPanel a dcal chaque index suivant de 1. Si, par exemple, vous avez supprim le bouton lindex 2, les objets prsents lindex 3 et 4 ont vu leur index passer respectivement 2 et 3 (voir Figure5.21).
Figure5.21
Principe deffondrement de la liste denfants.
Avant suppression de l'enfant l'index 1 Panel.Children - 5 enfants Enfant 4 Enfant 3 Enfant 3 Enfant 2 Enfant 2 Enfant 1 Enfant 0 Suppression de l'enfant l'index 1 via la mthode Children.RemoveAt(1) Enfant 1 Rfrence de l'ancien enfant 1 Enfant 0 Effondrement des index Aprs suppression de l'enfant, on assiste l'effondrement des index de la liste d'enfants Panel.Children - 4 enfants

Lorsque la liste denfants est modifie, lagencement du composant se met automatiquement jour, ce qui peut tre pratique pour mettre en forme des contenus dynamiques.

Chapitre 5

Larbre visuel et logique

101

5.4.2.2 Trier une liste d'enfants


Vous serez donc souvent tent dutiliser leffondrement des index pour mettre en forme ou dynamiser une application. Nous allons voir les limites et les contraintes de leffondrement des index. Vous allez utiliser ce comportement pour supprimer des champs texte contenus dans un Stack Panel. Ceux dont la proprit Text ne possde pas une chane de caractres prcise seront effacs de la liste. Le StackPanel nous servira cette occasion de liste de tri. Au sein dun nouveau projet nomm TriChildren, instancions le tableau suivant comme champ de la classe MainPage, dans le code logique:
string[] moisAnnee = new string[12] { "janvier", "fvrier" , "mars", "avril", "mai", "juin", "juillet", "aot", "septembre", "octobre", "novembre","dcembre"};

Positionnons un nouveau StackPanel dans LayoutRoot. Nous pouvons soit linstancier dynamiquement, via C#, soit le crer via linterface visuelle de Blend. Appelez-le MonStackPanel. Il serait pratique de limbriquer au sein dun Border afin de dfinir un contour visuel. Nous allons parcourir le tableau et crer une occurrence de TextBlock pour chaque lment du tableau lu par la boucle:
string[] moisAnnee = new string[12] { "janvier", "fvrier" , "mars", "avril", "mai", "juin", "juillet", "aot", "septembre", "octobre", "novembre","dcembre"}; private void MainPage_Loaded(object sender, RoutedEventArgs e) { foreach (string mois in moisAnnee) { TextBlock moisTexte = new TextBlock(); moisTexte.Foreground = new SolidColorBrush(Colors.Gray); moisTexte.FontSize = 16; moisTexte.FontFamily = new FontFamily("Trebuchet MS"); moisTexte.Text = mois; monStackPanel.Children.Add(moisTexte); } }

Plaons maintenant un composant de champ texte de saisie, TextBox, au-dessus du StackPanel dans linterface visuelle de Blend. Nous pouvons l aussi crer ces lments par code. Appelons le champ de saisie FiltreMois (voir Figure5.22).
Figure5.22
Arbre visuel et interface de TriChildren.

102

Partie I

Approches de Silverlight

Ajoutez maintenant la logique ncessaire pour trier les mois affichs dans le Stack Panel. Pour cela, vous pouvez ajouter une mthode dans le panneau des vnements du champ de saisie. Les champs de saisie TextBox possdent lvnement TextChanged. Il vous suffit dcrire le nom de la mthode, droite de TextChanged. Elle pourrait se nommer OnChangedFiltre. Blend ajoute directement le code correspondant dans la classe MainPage:
private void OnChangedFiltre(object sender, TextChangedEventArgs e) { // TODO: Add event handler implementation here. }

Lorsque le champ de saisie sera modifi par lutilisateur, supprimez tous les champs texte du StackPanel ne contenant pas la chane de caractres entre par lutilisateur. Toutefois, vous neffectuerez le tri qu partir dun minimum de 3 caractres saisis:
private void OnChangedFiltre(object sender, TextChangedEventArgs e) { // on vrifie qu'il y a au minimum 3 caractres entrs if ( FiltreMois.Text.Length>2 ) { //on parcourt les enfants foreach (TextBlock moisTextBlock in MonStackPanel.Children) { // on rcupre chaque chane de caractres string mt = moisTextBlock.Text as string; // si l'un des TextBlock du StackPanel ne contient pas la chane if ( !mt.Contains( FiltreMois.Text ) ) { // on le supprime MonStackPanel.Children.Remove( moisTextBlock ); } } } }

Vous remarquez le typage TextBlock dans la dfinition de la boucle foreach. Aprs tout, Text Block est une sous-classe du type UIElement. Il faudra juste faire attention ne positionner aucun autre type dobjet dans le StackPanel sous peine de lever une erreur. Compilez et testez votre application. Vous le constatez assez rapidement, le comportement du filtre est trange. Une erreur est mme leve (voir Figure5.23).
Figure5.23
Erreur leve lorsque le type attendu ne correspond pas lenfant.

Le message est clair, vous parcourez la liste et vous la modifiez en mme temps pour la mettre en forme. Toutefois, vous ne ralisez pas une modification anodine dans le cas prsent, vous supprimez dfinitivement un enfant de la liste. La boucle ne peut donc pas tre lue correctement et vous

Chapitre 5

Larbre visuel et logique

103

gnre des erreurs daccs. Dans ce cas prcis, la mthode que nous employons nest pas la bonne car noubliez pas que supprimer des objets modifie la mise en forme certes, mais affecte surtout larbre visuel de lapplication et donc son architecture. Nous allons tudier une mthode plus approprie ce cas de figure dans la section suivante.

5.4.2.3 Suppression vs. Collapsed


Toute sous-classe de UIElement possde la proprit Visibility, qui doit tre affecte dune valeur de lnumration Visibility. Attention ne pas confondre la proprit dobjet et lnumration (une liste de valeurs, voir Chapitre 3). Lnumration possde les valeurs Visible et Collapsed. Lorsque vous crivez:
MonUIElement.Visibility = Visibility.Collapsed;

vous pratiquez un pseudo effondrement. Dans ce cas prcis, le systme dagencement de Silverlight (Silverlight Layout System) ne prend pas en compte lobjet. Ses marges, sa largeur, sa hauteur et ses enfants sont simplement ignors, lobjet nest pas affich et ninfluence pas les autres. Pourtant celui-ci reste un lment de la collection Children, vous naffectez donc en rien larchitecture de votre application. Il faut privilgier cette proprit aux mthodes de suppression lorsque vous souhaitez accomplir des oprations lies la mise en forme. Cela est simplement plus intuitif, plus pertinent et plus simple. Voici notre code pour la liste de tri, mis jour en utilisant cette proprit:
private void OnChangedFiltre(object sender, TextChangedEventArgs e) { // on parcourt le tableau foreach (TextBlock MoisTextBlock in MonStackPanel.Children) { // on rcupre chaque chane de caractres string Mt = MoisTextBlock.Text as string; // si l'un des TextBlock du StackPanel ne contient pas la chane if ( !Mt.Contains( FiltreMois.Text ) ) MoisTextBlock.Visibility = Visibility.Collapsed; else MoisTextBlock.Visibility = Visibility.Visible; } }

Le code est beaucoup plus simple dans ce cas. Avec les mthodes Remove et RemoveAt, nous aurions d stocker les enfants supprims dans un tableau temporaire pour obtenir un rsultat quivalent et ne pas perdre leur rfrence.

5.4.3 Dsactiver des objets


Nous pourrions nous demander lintrt que prsente la dsactivation des objets. Il faut admettre que plus une application est performante, plus elle est conviviale. Dun point de vue utilisateur, rien nest plus nervant queffectuer des actions et voir leur rsultat apparatre avec un temps de latence. Cela peut parfaitement se comprendre pour des accs distants aux bases de donnes mais cest une problmatique que lon sait traiter et que lutilisateur comprend. Pour des actions plus simples, comme naviguer dans un site ou dplier un menu par exemple, il est anormal davoir des temps de latence et cela rvle un dveloppement un peu trop hasardeux. Il faut optimiser au maximum les performances de votre application. Pour cette raison, allger les allocations mmoire

104

Partie I

Approches de Silverlight

est une tche rellement importante. Sans cela, lapplication pourrait utiliser de plus en plus de mmoire vive et ralentir lexcution. Dsactiver des objets est le processus inverse de celui consistant ajouter des objets larbre visuel. Pour ajouter un objet la liste daffichage, nous avons dabord instanci cet objet, puis nous lavons affect comme enfant dun conteneur Panel grce aux mthodes Add et Insert. Les mthodes de suppression Remove et RemoveAt ne sont donc pas suffisantes pour dsactiver compltement un objet en mmoire. Il faut faire exactement loppos de linstanciation, toutefois une mthode aussi directe nexiste pas. Les allocations mmoire sont gres par le ramasse-miettes (ou Garbage Collector). Cest lui qui surveille et dcide si un objet est dsactiv ou non de la mmoire. Nous devons juste permettre au ramasse-miettes de jouer son rle. Pour cela, la premire tape consiste supprimer de larbre visuel linstance que vous souhaitez dsactiver. Tant que celle-ci est prsente dans larbre visuel, elle ne peut tre dsactive puisquelle est rfrence par une collection de composants UIEle ment. Nous invoquons donc en premier la mthode Remove ou RemoveAt. La seconde tape est de passer la valeur de la rfrence null :
MonConteneur.Children.Remove(UnUIElement); UnUIElement = null;

Cette mthode est saine, toutefois vous ne saurez pas quand lobjet sera supprim de la mmoire. Le langage C# est manag, cela signifie que les allocations mmoire ne sont pas gres par le dveloppeur C#, mais par le ramasse-miettes. Celui-ci gre la dsactivation des instances de classes en fonction de leur occupation mmoire. Moins une rfrence prend de mmoire, moins elle est prioritaire. Une mauvaise pratique consiste utiliser la mthode Collect du ramasse-miettes, pour forcer son passage. Cela est trs coteux en performances car le ramasse-miettes doit parcourir toutes les rfrences et dcider de les supprimer ou non:
MonConteneur.Children.Remove(UnUIElement); UnUIElement = null; GC.Collect();

Lorsque vous concevrez vos propres composants, vous devrez faire attention ce quils suppriment bien tous les couteurs internes dvnements propres lapplication ou des rfrences externes. Sans cela, vos instances de composants personnaliss pourraient ne pas tre collectes par le ramasse-miettes (voir Chapitre12).

5.4.5 vnement diffus


Nous avons vu qu chaque fois quun objet est ajout larbre visuel, soit lobjet RootVisual, celui-ci diffuse lvnement Loaded. Il vous suffira donc dcouter cet vnement pour savoir si lobjet est ajout larbre visuel. Un vnement semblable nest pas diffus lorsquun objet est supprim de larbre visuel. Vous pouvez la place utiliser lvnement LayoutUpdate. Toutefois, cet vnement est diffus lors de chaque modification dagencement. Il est donc diffus de nombreuses fois, mme lorsquun objet est ajout larbre visuel. Voici une mthode pour vrifier quun enfant vient dtre supprim de larbre visuel:
private void MainPage_Loaded(object sender, e) { MonStackPanel.LayoutUpdated += MonStackPanel_LayoutUpdated;

Chapitre 5

Larbre visuel et logique

105

} private void MonStackPanel_LayoutUpdated(object sender, EventArgs e) { if (MonStackPanel.Children.Contains(MonBouton) { /* objet non supprim */ } else { /* objet supprim */ } }

Dans tous les cas, il vous faudra tester si lobjet a t supprim. Ce nest pas lidal dun point de vue performance car lvnement LayoutUpdate est diffus trs souvent.

5.5 changes dindex


Nous avons abord de nombreux mcanismes de larbre, mais nous navons pas pratiqu dchanges dindex de la liste denfants. En fait, Children ne possde pas une mthode spcifique assurant directement cette opration. Nous allons tudier les diffrentes manires de procder dans cette section.

5.5.1 change dindex du point de vue conception


Comme aucune mthode nexiste, nous allons coder notre change dindex en prenant soin dviter les erreurs daccs, dajout ou mme de suppression que nous connaissons bien maintenant. Voici le code permettant deffectuer cette opration dlicate:
public partial class MainPage : UserControl { public Button ClientMenu; public WrapPanel MenuHaut; public MainPage() { InitializeComponent(); Loaded +=new RoutedEventHandler(MainPage_Loaded); } private void MainPage_Loaded(object sender, RoutedEventArgs e) { menuHaut = LayoutRoot.Children[0] as WrapPanel; ContactBtn.Click +=new RoutedEventHandler(ContactBtn_Click); } private void ContactBtn_Click(object sender, RoutedEventArgs e) { // on rcupre l'un des enfants dont on veut changer l'index Button Enfant1 = menuHaut.Children[1] as Button; // on stocke les index dont nous aurons besoin par la suite int IndexContact = menuHaut.Children.IndexOf( ContactBtn ); // Ensuite on supprime les enfants de la liste menuHaut.Children.Remove( Enfant1 ); menuHaut.Children.Remove( ContactBtn );

106

Partie I

Approches de Silverlight

// Puis on les rinsre en respectant un ordre prcis // toujours commencer par rinsrer l'lment // que l'on souhaite positionner l'index le plus bas menuHaut.Children.Insert(1,ContactBtn); // pour finir, on ajoute la liste d'enfant l'lment // qui a l'index le plus haut menuHaut.Children.Insert(IndexContact,Enfant1); } }

Comme vous pouvez le voir, nous suivons un ordre vraiment trs prcis pour viter au maximum les erreurs daccs la liste. changer lordre des enfants modifie larbre visuel, mais ne lui retire pas denfants. Nous aurons donc le mme nombre denfants au dpart de notre code qu larrive. Il nous faut dans un premier temps stocker les index que nous souhaiterons changer par la suite. Si nous le faisions aprs avoir supprim un enfant de la liste, ceux-ci ne correspondraient pas au bon emplacement dans la liste. La deuxime tape consiste supprimer les enfants changer de la liste. Lordre importe peu. Pour finir, on les rinsre, mais pas nimporte comment. Dans notre cas, nous avons chang le dernier enfant de la liste avec un enfant situ en plein milieu. Si nous commenons par rinsrer llment le plus haut dans la liste, nous courons le risque de spcifier un index hors de la porte maximale qui correspond notre nombre denfants, Children.Count. Le code suivant renvoie une erreur car nous essayons dinsrer Enfant1 un index qui nest pas encore accessible:
private void ContactBtn_Click(object sender, RoutedEventArgs e) { // on rcupre l'un des enfants dont on veut changer l'index Button Enfant1 = menuHaut.Children[1] as Button; // on stocke les index dont nous aurons besoin par la suite int IndexContact = menuHaut.Children.IndexOf( ContactBtn ); // Ensuite on supprime les enfants de la liste menuHaut.Children.Remove( Enfant1 ); menuHaut.Children.Remove( ContactBtn ); menuHaut.Children.Insert(IndexContact,Enfant1); menuHaut.Children.Insert(1,ContactBtn); }

Cette mthode est assez fastidieuse. Raliser un change dindex sans connatre lavance les objets changer nous forcerait galement prvoir toutes les erreurs possibles. Avoir une mthode de UIElementCollection qui accomplirait directement cette opration serait un plus. Cest ce que nous allons aborder ds maintenant.

5.5.2 Une mthode dextension pour UIElementCollection


Les mthodes dextension sont apparues avec C# 3. Cest un nouveau pas en avant pour rendre C# souple et faciliter lajout de mthodes personnalises aux classes normalement fermes lextension. Voici la signature de la classe UIElementCollection:

Chapitre 5

Larbre visuel et logique

107

public sealed class UIElementCollection : PresentationFrameworkCollection<UIElement>

Comme vous pouvez le constater, cette classe empche tout hritage. Pourtant, les mthodes dextension nous permettent de lui ajouter des fonctionnalits sans pour autant gnrer du code spaghetti. Cliquez-droit sur votre projet et slectionnez Ajouter un nouvel lment. Dans la fentre qui vient de souvrir, choisissez Class. Nommez-la UtilsMethod.cs, vous pouvez galement la glisser dans un dossier spcifique pour viter de mlanger les genres (voir Figure5.24). La cration de rpertoires est accessible par un simple clic-droit sur le projet ou un autre rpertoire.
Figure5.24
Arborescence de dossier pour le fichier Utils.cs.

Comme vous pourriez avoir besoin de notre mthode plus tard, il vaut mieux inclure la future classe qui contiendra notre mthode dans un espace de nom spcifique. Voici le code contenant la dfinition de notre mthode dextension:
namespace Org.Tweened.Utils { public static class UtilsMethod { public static void SwapChildren(this UIElementCollection E, UIElement child1, UIElement child2 ) { if ( E.Contains(child1) && E.Contains(child2) ) { int Index1 = E.IndexOf(child1); int Index2 = E.IndexOf(child2); E.Remove(child1); E.Remove(child2); if (Index1>Index2) { E.Insert(Index2,child1); E.Insert(Index1,child2); } else { E.Insert(Index1,child2); E.Insert(Index2,child1); } } else

108

Partie I

Approches de Silverlight

thrownew NotImplementedException("Au moins l'un des deux enfants n'est pas contenu dans la liste d'enfants."); } } }

Crer une mthode dextension est relativement simple. Lobjectif de ces mthodes est la dcoration. Pas au sens artistique, bien sr, mais dun point de vue technique. Dcorer signifie ajouter de nouvelles fonctionnalits et proprits un objet. La dcoration est un concept permettant de rsoudre de nombreuses problmatiques de conception objet. Le mot-cl static est obligatoire aussi bien pour la classe que pour la mthode. Grce ce mot-cl, le simple fait de rfrencer notre espace de noms permet la mthode dextension dtre utilise. La signature dune mthode dextension contient toujours au moins un premier argument commenant par this, celui-ci est suivi du type puis du nom du paramtre. Le mot-cl this indique au compilateur que le type qui le suit pourra utiliser la mthode. Les paramtres qui suivent sont quant eux utiliss lors de lappel. ce moment, noubliez pas de rfrencer lespace de noms via le mot-cl using:
MenuHaut.Children.SwapChildren(Enfant1, ContactBtn);

Vous naurez sans doute pas dIntelliSense pour les mthodes dextension au sein dExpression Blend, mais vous en aurez au sein de Visual Studio. Compilez et testez votre application. Vous constatez que les boutons changent bien leur place, toutefois contrairement notre premire version, la logique est compltement rutilisable au sein dautres projets.

5.5.3 change dindex du point de vue design


Comme nous lavons vu la section 5.2, lordre dimbrication est directement li lordre de superposition. Toutefois cela nest pas forcment pratique car lordre dimbrication est galement li aux contraintes de positionnement au sein dun conteneur. Nous allons le dmontrer travers un mini exemple et trouver des solutions adaptes aux designers et aux dveloppeurs.

5.5.3.1 Crer le projet


Crez un nouveau projet de type application et nommez-le SuperpositionOrder. Dans le conteneur principal, crez un StackPanel avec une orientation horizontale. Celui-ci doit sadapter son contenu, vous devrez donc lui affecter une largeur et une hauteur en mode Auto. Faites en sorte quil soit centr horizontalement au sein de la grille principale. Ensuite, imbriquez lintrieur du StackPanel cinq objets Rectangle de diffrentes couleurs. Chacun doit faire 100 pixels de largeur par 100 pixels de hauteur. Pour finir, espacez-les en leur spcifiant une marge droite (voir Figure5.25). Il faudrait agrandir un rectangle afin de voir comment ceux-ci se superposent, par exemple celui du milieu. Ceci nest pas aussi facile faire quil ny parat.

Chapitre 5

Larbre visuel et logique

109

Figure5.25
Exercice pratique de superposition.

5.5.3.2 Introduction aux RenderTransform


Notre problme est simple: agrandir la largeur dcalera les autres rectangles les uns par rapport aux autres car la largeur et la hauteur sont lies au comportement dempilement du StackPanel. Cest une impasse si nous nous contentons de ces proprits. Heureusement un autre type de transformation existe, les transformations vectorielles. Nous aborderons en profondeur ces transformations au Chapitre6. Pour linstant, nous nous contentons de les utiliser. Slectionnez le rectangle du milieu, puis dans le panneau des proprits, ouvrez longlet Transform (voir Figure5.26).
Figure5.26
Longlet des transformations.

Cet onglet vous propose deux types de transformation : les transformations vectorielles de type RenderTransform et les transformations de type Projection qui permettent de grer laffichage dobjets en pseudo3D (voir Chapitre9). Nous allons utiliser les transformations vectorielles pour nous librer partiellement des contraintes dagencement propres au StackPanel. Cliquez sur licne de transformation dchelle ( ), puis saisissez la valeur 1,4 dans les deux champs de saisie (voir Figure5.27).

110

Partie I

Approches de Silverlight

Figure5.27
Longlet des transformations dchelle.

Les transformations de type RenderTransform sont totalement indpendantes de lagencement impos par le contexte conteneur. Elles permettent donc aux graphistes de saffranchir des contraintes lies la conception et larchitecture. Notre Rectangle mesure dsormais 40 % de largeur et de hauteur de plus et il ne dcale plus les autres (voir Figure5. 28).
Figure5.28
Rectangle avec changement dchelle.

5.5.3.3 La proprit ZIndex


Comme vous pouvez le constater, notre Rectangle tant en troisime position dans lordre dimbrication XAML, il apparat au-dessus du rectangle sa gauche et sous le rectangle sa droite. Nous allons lafficher au-dessus des autres rectangles. Sur Internet, vous trouverez de nombreux exemples dans lesquels un menu se superpose aux autres lors du survol de la souris. Pour raliser ce type de menu, il faudrait nous affranchir, une nouvelle fois, des contraintes lies limbrication. Tous les conteneurs pouvant contenir plus dun enfant possdent la proprit attache ZIndex, fournie par la classe Canvas. Par dfaut, la proprit Zindex contient la valeur 0. Comme tous les enfants dun conteneur possdent ZIndex 0, cest lordre dimbrication XAML qui prime dans un premier temps. Il existe ainsi une comptition constante entre lordre dimbrication, soit lindex de lenfant dans la collection Children, et la proprit ZIndex. Lorsque deux enfants possdent le mme ZIndex, lordre de superposition est dtermin par lindex enfant de chacun. Au contraire, sils possdent un ZIndex diffrent, lordre de superposition est dfini par le ZIndex. La valeur ZIndex la plus haute reprsente lobjet affich au-dessus des autres. Toutefois, cette proprit nexerce son influence quau sein dun mme conteneur. Il nous faut la modifier pour le rectangle central. Pour cela, il vous suffit douvrir le panneau des proprits, dans les options dagencement, puis de passer sa valeur 1 (voir Figure5.29).
Figure5.29
Rectangle avec changement dchelle et modification de la proprit ZIndex.

Chapitre 5

Larbre visuel et logique

111

Pour mieux comprendre la comptition entre lindex enfant et le ZIndex, vous pouvez slectionner tous les rectangles et passer leur ZIndex 1. Notre rectangle du milieu passe nouveau en dessous du rectangle de droite. Les ZIndex tant tous gaux, cest lordre dimbrication XAML qui prime nouveau. Vous tes maintenant familiaris avec les diffrents composants visuels propos par le framework Silverlight. Dans le prochain chapitre, nous tudierons les mcanismes lis lanimation propres la plateforme Silverlight. Nous verrons en quoi Silverlight se rvle tre un puissant moteur danimation vectorielle. Nous aborderons donc la cration danimations dans Expression Blend ou avec C#.

Partie II Interactivit et cration graphique 6


Animations
Dans ce chapitre, nous tudierons en profondeur les mcanismes dinterpolations vectorielles propres Silverlight. Pour cela, nous allons apprendre les principes fondamentaux de lanimation. Nous utiliserons notre projet de site plein cran comme point de dpart pratique pour acqurir les concepts de base, ainsi quune aisance technique. Nous aborderons tout dabord lanimation du point de vue dun designer interactif via Blend. Dans un second temps, nous verrons que C# facilite et dynamise la cration danimations, mais quil simplifie et optimise galement le flux de production sans dlaisser le travail des designers ou des animateurs. Nous apprendrons en quoi les transformations relatives sont efficaces et incontournables en matire danimation et comment les gnrer lexcution. Pour finir, nous aborderons et utiliserons le gestionnaire dtats visuels dont la bonne comprhension repose sur lensemble des notions apprises auparavant. Nous verrons quel est son impact en matire de conception applicative ou de flux de production dans notre quotidien.

114

Partie II

Interactivit et cration graphique

6.1 Introduction
Silverlight est, entre autres, un moteur danimations vectorielles. Depuis sa version 3, il permet de grer la projection dobjets vectoriels en pseudo 3D. Cela signifie quil est capable de reprsenter un objet au sein des quatre dimensions que nous connaissons tous, soit x, y, z (la profondeur) et t pour le temps. Dans ce chapitre, nous ntudierons pas les animations dans un espace 3D, mais uniquement 2D pour des raisons de clart (si besoin, vous pouvez consulter le Chapitre9 ddi la 3D).

6.1.1 Quest-ce quune animation?


Quel que soit lenvironnement de dveloppement, crer une animation revient toujours modifier la valeur dune proprit dun objet au cours du temps. Nous verrons la section6.3.2 que la valeur de dpart peut-tre rcupre implicitement. Cette particularit propre au lecteur Silverlight permet des comportements trs puissants et beaucoup de souplesse de conception. Dans le langage courant, une animation est forcment fluide, mais cest un raccourci un peu rapide et incorrect. Gardez lesprit que cest avant tout une proprit dobjet qui varie au cours du temps quel que soit le laps de temps coul entre deux valeurs de cette proprit. Ainsi, le rebond dune balle se rsume aux variations de ses coordonnes dans lespace au cours du temps. La nature offre de nombreux exemples danimations invisibles nos yeux, comme lrosion dune montagne ou la croissance dun arbre. Les proprits de ces objets voluent tellement lentement dans le temps que voir ces phnomnes est simplement impossible lil nu. Certains mouvements sont tellement rapides quil est galement difficile de les analyser. Le galop du cheval en est un exemple flagrant, il ne fut rellement compris scientifiquement par tienne Jules Marey et Eadweard Muybridge qu la fin du xixe sicle. Le naturaliste tienne Jules Marey pensait quau grand galop aucune des pattes du cheval ne touchait le sol en mme temps durant un cours instant. Cela est vrai, mais le dmontrer ntait pas si simple. Pour le prouver, Eadweard Muybridge a dcoup son mouvement laide dappareils photographiques aligns les uns ct des autres. Les appareils photographiques de ces scientifiques taient dclenchs de manire dcale dans le temps selon un intervalle rgulier (voir Figure 6.1).
Figure6.1
Dcoupage du galop dun cheval par Muybridge.

La dcomposition et ltude des mouvements amena de grandes dcouvertes et perspectives. Ce laps de temps constant entre chaque photographie a introduit la notion de cadence de prise de

Chapitre 6

Animations

115

vues. Plus ce laps est court, plus la cadence est leve. Par la suite, Muybridge inventa le premier appareil permettant dafficher les images rapidement les unes aprs les autres. Cette invention prfigurait sans doute les prmisses du cinma et de lanimation. Dans la mme veine, les premiers dessins anims Disney taient en huit images par seconde car cela vitait un travail de dessin trop fastidieux. Toutefois, lil humain ne percevant plus leffet de saccade partir de24images par seconde, ces 8 images par seconde taient perues par les spectateurs malgr le talent des animateurs. Les premiers films des frres Lumire connaissaient des limites quivalentes. Les cadences daffichage, de prise de vues et danimations furent, durant au moins 50 ans, le centre de nombreux efforts de la part des cinastes et techniciens car celles-ci engendrent lillusion du mouvement et son ralisme. Aujourdhui encore, leur matrise permet de concevoir des effets visuels impressionnants et de mieux connatre notre environnement naturel.

6.1.2 La cadence des animations au sein de Silverlight


Au sein de Silverlight, la cadence des animations est de 60 images par seconde par dfaut. Le laps de temps scoulant thoriquement entre deux images affiches est donc de 1/60 de seconde. Cette valeur est accessible travers la proprit MaxFrameRate de linstance Silverlight. Vous pouvez galement afficher la cadence en bas de la fentre du navigateur via la proprit EnableCounter FrameRate linstanciation du lecteur Silverlight:
<div id="silverlightControlHost"> <object data="data:application/x-silverlight," type="application/ x-silverlight-2" width="100%" height="100%"> <param name="source" value="ClientBin/sitet.xap"/> <param name="onerror" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="3.0.40128.0" /> <param name="autoUpgrade" value="true" /> <param name="maxFrameRate" value="30" /> <param name="enableFrameRateCounter" value="true" /> <a href="http://go.microsoft.com/fwlink/?LinkID=141205" style="text-decoration: none;"> <img src="http://go.microsoft. com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/> </a> </object>

Vous pouvez galement dfinir ces deux paramtres lexcution en C#:


public MainPage() { InitializeComponent(); Loaded +=new System.Windows.RoutedEventHandler(MainPage_Loaded); MouseLeftButtonDown+= MainPage_MouseLeftButtonDown; } private void MainPage_Loaded(object sender, RoutedEventArgs e) { App.Current.Host.Settings.EnableFrameRateCounter = true; } private void MainPage_MouseLeftButtonDown (object sender, MouseButtonEventArgs e) { App.Current.Host.Settings.MaxFrameRate = 30; }

116

Partie II

Interactivit et cration graphique

Toutefois, comme dans nimporte quel autre moteur danimation, et ainsi que vous pouvez le constater grce la proprit EnableFrameRateCounter, la cadence nest pas constante. Ceci est d aux algorithmes de calcul et aux fluctuations de performance des systmes dexploitation, mais galement de nombreux autres facteurs, comme loccupation mmoire et processeur linstant o lanimation est visionne. La cadence maximum nest en ralit rien dautre quune valeur souhaite idale. Silverlight nest volontairement pas conu pour grer les animations traditionnelles de prime abord, cest--dire les animations image par image. Il est orient vers la diffusion dapplications riches avant tout. Il en dcoule deux spcificits essentielles propres Silverlight. La premire est que lunit de temps est exprime en secondes et non en images affichables comme sous Flash. La seconde particularit est que Silverlight dispose dun moteur vectoriel "autodgradable". Cela signifie que si une animation est trop lourde pour tre affiche correctement selon sa cadence, dans tous les cas, le moteur respectera au maximum le temps qui lui est imparti, mme sil lui faut ignorer laffichage dimages intermdiaires de lanimation. Autrement dit, mme saccade, une animation ne dpassera pas une dure dfinie, car Silverlight privilgie le temps plutt que laffichage de toutes les tapes. De manire gnrale, lil peroit lintervalle entre deux images si la cadence est infrieure 25images par seconde. Il vaut donc mieux viter les cadences trop faibles pour ne pas crer un effet saccad disgracieux.

6.1.3 Une premire animation


Vous allez maintenant crer votre premire animation. Pour cela, ouvrez Blend et crez un projet de type application. Nommez-le PremiereAnimation par exemple. Nous allons commencer par un peu de pratique, puis nous examinerons ce qui a t produit ct XAML par Blend. Vous pouvez passer en espace de travail Animation via le raccourci F6. Dans le conteneur LayoutRoot, crez un champ texte de type TextBlock, puis entrez la chane de caractres animation dune valeur numrique dans sa proprit Text. Nous allons crer une nouvelle animation de champ texte. Pour cela cliquez sur licne plus () dans le panneau au-dessus de larbre visuel et logique. Une nouvelle fentre souvre, vous proposant de nommer la nouvelle animation que vous souhaitez crer. Nommez-la AnimationNumerique (voir Figure 6.2).
Figure6.2
Fentre de cration dune nouvelle animation.

Vous remarquez que crer une nouvelle animation revient crer une nouvelle ressource de type Storyboard. Cliquez sur OK. Linterface de Blend affiche dsormais une ligne de temps exprime en secondes. Celle-ci est situe droite de larbre visuel et logique. Chaque lment de larbre visuel peut possder sa propre animation qui sera accessible dans la fentre de la ligne de temps. Une animation peut cibler une ou plusieurs proprits. Un cadre rouge entoure la fentre de design (il est reprsent en noir la Figure 6.3).

Chapitre 6

Animations

117

Figure6.3
Arbre visuel attenant au panneau de la ligne du temps.

Dans la partie gauche de linterface, lencadr rouge indique que toute modification des objets entranera la cration dune nouvelle cl danimation ou la modification dune cl existante. Attention ne pas changer le type de valeur contenu par la proprit. Un dgrad ne peut pas tre interpol en couleur unie. Il faut un dgrad au dpart et en fin danimation. Dplacez linstance du TextBlock de la gauche vers la droite. Ds que vous avez ralis cette tape, une nouvelle cl danimation est cre la seconde 0. Elle est reprsente par un ovale gris clair, droite du champ texte (voir Figure 6.4).
Figure6.4
Une nouvelle cl danimation est cre la seconde 0.

Lorsquun objet possde une cl danimation, un point rouge apparat en bas gauche de son icne dans larbre visuel et logique.
ATTENTION
Une cl danimation indique une modification de la valeur dune proprit un instant donn. Crer une cl danimation alors quaucun changement ne survient peut tre utile si vous poursuivez un but prcis. Toutefois, vitez de polluer la ligne de temps en ajoutant des cls nindiquant aucun changement de proprit.

Dplacez maintenant la tte de lecture la seconde 2, reprsente par une ligne jaune surmonte dun triangle. La position de la tte de lecture permet dafficher les objets vectoriels un instant donn de lanimation. La dplacer revient faire un arrt sur image nimporte quel instant de lanimation. Slectionnez le champ texte, puis repositionnez-le nimporte o ailleurs au sein du conteneur LayoutRoot. Vous gnrez nouveau une image cl, mais cette fois elle est positionne la seconde 2. Limage cl est automatiquement cre car Blend est en mode enregistrement danimation. Vous pouvez voir le rsultat de vos actions en jouant lanimation. Pour cela, il suffit de cliquer sur le bouton de lecture situ au-dessus de la ligne de temps (voir Figure 6.5). Laperu de la lecture est moins performant que celui que vous obtiendrez en compilant le projet. Toutefois, compiler le projet ne dclenche pas lanimation au chargement. Il vous faudra dclencher lanimation lexcution, soit par C#, soit grce aux comportements (voir section6.2). Comme nous lavons vu jusqu prsent, tout ce qui est cr par le designer ou lintgrateur au sein

118

Partie II

Interactivit et cration graphique

de Blend est traduit en langage XAML. Nous allons maintenant tudier ce qui a t produit, ainsi que les classes de la plateforme Silverlight utilises pour animer les objets.
Figure6.5
Contrler une animation sous Blend.

6.1.4 Les diffrents types danimation


Fermez lanimation en cours pour viter de la modifier. Il suffit pour cela de cliquer sur licne de fermeture de lanimation () situe droite du nom de lanimation dans larbre visuel et logique. Lorsque vous avez cr lanimation, elle a t ajoute en tant que ressource. Une ressource est un type dobjet particulier dont le but est de pouvoir tre accessible et rutilisable au sein de votre projet. Il existe plusieurs types de ressources, mais elles possdent toutes une porte dutilisation. Dans le cas des animations, les ressources sont en majorit dfinies comme ressource de llment visuel le plus haut dans larbre visuel. Dans notre cas, lanimation sera stocke dans le composant UserControl racine. Elle sera donc utilisable et accessible lintrieur du nud XAML User Control racine. Voici le code XAML correspondant notre animation:
<UserControl.Resources> <Storyboard x:Name="AnimationNumerique"> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard. TargetName="textBlock" Storyboard. TargetProperty="(UIElement.RenderTransform). (TransformGroup.Children)[3].(TranslateTransform.X)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-25"/> <EasingDoubleKeyFrame KeyTime="00:00:02" Value="75"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard. TargetName="textBlock" Storyboard. TargetProperty="(UIElement.RenderTransform). (TransformGroup.Children)[3].(TranslateTransform.Y)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-20"/> <EasingDoubleKeyFrame KeyTime="00:00:02" Value="60"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </UserControl.Resources>

Comme vous le constatez, lanimation est reprsente par une ressource de type Story board. Elle possde un nom linstar des objets vectoriels que nous avons utiliss. lintrieur du nud lment Storyboard, deux squences danimation de type DoubleAnimationUsingKeyFrames cohabitent. Lune cible la proprit X du nud Render Transform, lautre la proprit Y de ce mme nud (voir section6.3). Un nud DoubleAnimationUsingKeyFrames dcrit une animation dune proprit de type Double par lutilisation de cls danimations. Comme nous le verrons dans ce chapitre, un changement peut tre dfini autrement que par des cls danimation. De plus, il est possible danimer des types non numriques. Pour le mettre en vidence, vous pouvez modifier la couleur du champ texte (proprit Foreground) la seconde 2. Il vous faut au pralable accder

Chapitre 6

Animations

119

lanimation pour la modifier. Pour cela, cliquez sur licne listant les animations cres ( ). Une fentre apparat, slectionnez lanimation. Une fois la couleur du champ texte modifie, vous obtiendrez lquivalent du code XAML gnr ci-dessous:
<Storyboard x:Name="AnimationNumerique"> <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard. TargetName="textBlock" Storyboard.TargetProperty= "(TextBlock.Foreground).(SolidColorBrush.Color)" > <EasingColorKeyFrame KeyTime="00:00:00" Value="Black"/> <EasingColorKeyFrame KeyTime="00:00:02" Value="Red"/> </ColorAnimationUsingKeyFrames> </Storyboard>

Cette fois, Blend a gnr une sous-squence danimation de type ColorAnimation UsingKeyFrames au sein de lobjet Storyboard. Vous nanimez plus de valeurs numriques, mais des valeurs de type Color. La Figure 6.6 liste une partie des classes et types danimation permettant danimer des objets au sein de Silverlight.
Figure6.6
Les classes utilises pour animer des objets.

La classe Storyboard assure le contrle de tous les types danimation, leur lecture ou leur pause, par exemple. De ce fait, vous pouvez considrer lobjet Storyboard comme lunit dorganisation principale. Linterpolation des valeurs entre deux instants est gre par les autres classes. Quatre grands types de valeurs peuvent tre anims:

Double reprsente les valeurs de types numriques. Lopacit, par exemple, sera anime grce la classe DoubleAnimation, car celle-ci est type Double.

120

Partie II

Interactivit et cration graphique

Point correspond une structure constitue dune paire de valeurs nommes X et Y et de type Double. Pour rsumer, il reprsente les coordonnes dun point dans lespace. Lorsque vous animez les sommets dun trac vectoriel (de type Path), en interne le XAML gnr correspondra PointAnimation. Color fait rfrence toutes les classes utilisant la classe Color. Ainsi, animer les couleurs dun dgrad linaire (LinearGradientBrush) repose sur Color Animation. Object renvoie nimporte quel type. Silverlight vous permet danimer nimporte quel type de valeurs diffrentes des prcdentes. Toutefois interpoler la visibilit (Visi bility) ou une chane de caractres (string) ne produira pas une animation fluide.

Nous allons maintenant essayer de comprendre quels types dinterpolation sont fournis par Silverlight et comment les concevoir.

6.1.5 Les diffrents types dinterpolation


Comme vous pouvez le constater la Figure 6.6, mis part pour les animations ciblant les valeurs Object, deux grandes familles dinterpolations cohabitent pour chaque type. La premire famille utilise des cls danimation. La seconde possde une proprit pour la valeur de dpart et une autre pour la valeur darrive, cette dernire famille nutilise donc pas de cl danimation.

6.1.5.1 Interpolations par cl danimation


Une cl danimation est une classe constitue au minimum des proprits Value et KeyTime. La proprit Value indique la valeur de la proprit anime. KeyTime dfinit linstant auquel la proprit doit atteindre la valeur spcifie:
<EasingColorKeyFrame KeyTime="00:00:00" Value="Black"/> <EasingColorKeyFrame KeyTime="00:00:02" Value="Red"/>

Ainsi dans le code ci-dessus, la seconde 0, la proprit anime est affecte de Black (noir) alors qu la seconde 2 celle-ci doit atteindre la valeur Red (rouge). Parce quil existe quatre grands types danimation (voir section 6.1.4), il existe quatre grands types de cls danimation (voir Figure 6.7). Une classe abstraite reprsente chaque type de cl. Pour chaque type de cl (mis part les cls faisant rfrence lanimation ObjectAnimation), il existe quatre manires de jouer lanimation. Au sein de Blend, vous pouvez choisir le type dinterpolation en cliquant sur une image cl via le panneau des proprits (voir Figure 6.8). Par dfaut, les cls danimations sont de type Easing, cest--dire quelles utilisent des quations dacclration pour interpoler les valeurs entre elles. Par exemple, lors de la cration de notre premire animation, celle-ci utilisait une acclration linaire:
<EasingColorKeyFrame KeyTime=00:00:00 Value=Black/> <EasingColorKeyFrame KeyTime=00:00:02 Value=Red/>

Chapitre 6

Animations

121

Figure6.7
Les diffrents types dimages cls et dinterpolation.

Figure6.8
Choisir le type dinterpolations dans Blend.

Lorsquaucune acclration nest dfinie, celle-ci est linaire (Linear). Vous trouverez les diffrents types dinterpolation ci-dessous:

Discrete. Ninterpole pas les valeurs entre deux cls danimation. Lanimation est joue de manire brutale. La proprit cible par lanimation ne change de valeur (Value) qu linstant o la tte de lecture arrive au temps (KeyTime) dfini dans limage cl. Lanimation nest pas fluide mais saccade. Il faudra cliquer sur longlet Hold In pour utiliser ce type de cl. Easing. Les cls prfixes par ce mot possdent en plus une proprit (Easing Function) permettant de dfinir une quation dacclration. Cest exactement ce type que vous utiliserez pour faire rebondir une balle par exemple. Nous reviendrons sur ce type de cl la section6.3. Linear. Dans la vie relle, aucun objet ne possde de mouvement linaire. Plus vous utiliserez ce type de cl et moins votre animation sera intressante car prvisible. Vous aurez parfois besoin de ce type danimation pour les rotations par exemple. Toutefois, les animateurs traditionnels les vitent le plus possible. Il ny a pas de moyen simple dans Blend de spcifier ce type de cl. On utilise plutt une acclration linaire ce qui revient au mme rsultat.

122

Partie II

Interactivit et cration graphique

Spline. Vous pouvez dfinir vous-mme la courbe dacclration manuellement, ce qui peut tre plus prcis dans certains cas. Pour grer vous-mme lacclration, cliquez sur longlet KeySpline (voir section6.3).

6.1.5.2 Interpolations sans cl danimation


Silverlight apporte beaucoup de souplesse et de facilit dans la cration de transitions grce aux proprits From correspondant la valeur de dpart, To qui est la valeur de destination, et By une valeur de destination relative la valeur de dpart. Ces proprits sont utilisables par les animations qui nemploient pas de cls (indiques par le suffixe UsingKeyFrames), soit:

ColorAnimation DoubleAnimation PointAnimation

Voici une manire dcrire une telle animation. Remplacez le XAML dcrivant lanimation de positionnement X et Y par le code suivant:
<DoubleAnimation BeginTime="00:00:00" From="-25" To="75" Duration="00:00:02" Storyboard.TargetName="textBlock" Storyboard. TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children) [3].(TranslateTransform.X)" /> <DoubleAnimation BeginTime="00:00:00" From="-20" To="60" Duration="00:00:02" Storyboard.TargetName="textBlock" Storyboard. TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children) [3].(TranslateTransform.Y)" />

Comme aucune proprit KeyTime nest prcise, il vous faut dfinir la dure de lanimation via la proprit Duration. Ce type danimation ne permet de dfinir quune valeur de dpart et darrive. Dans ce cas, Blend naffiche pas de cls. Dpliez larborescence des objets anims pour visualiser les proprits animes (voir Figure 6.9).
Figure6.9
Affichage dune animation sans cl danimation.

Blend ne cre ce type danimation que dans le cas o vous utilisez le gestionnaire dtats visuels (voir section6.4).

Chapitre 6

Animations

123

6.1.6 La classe Storyboard


Une instance de la classe Storyboard reprsente lenveloppe de lanimation. Chaque occurrence de Storyboard peut avoir plusieurs sous-squences danimation distinctes possdant des comportements et des proprits qui leurs sont propres. Par exemple, lune de ces squences ciblera un rond et lautre un bouton. Lune pourra dbuter la seconde 2 du Storyboard, et lautre ciblera une proprit de type couleur. Toutes les combinaisons sont possibles. Les animations sont conues comme des objets indpendants compltement spars de laspect visuel des objets. Autrement dit, elles nappartiennent aucun lment graphique, mais peuvent cibler nimporte lequel dentre eux (voir Figure 6.10).
Figure6.10
Principe du Storyboard.

La classe Storyboard possde des proprits communes aux autres classes hritant de TimeLine. Toutefois, cest la seule classe possdant des mthodes de contrle de lanimation, dont voici une liste:

Begin. Cette mthode permet de lire lanimation depuis la seconde 0. chaque appel de la mthode, le Storyboard est jou depuis le dbut. GetCurrentState. Cette mthode renvoie ltat actuel du Storyboard, sil est en cours de lecture ou sil est stopp. GetCurrentTime. Retourne une valeur de type TimeSpan correspondant au temps coul depuis le dpart de lanimation, et cela linstant o la mthode est invoque. Pause. Met la lecture en pause. Resume. Redmarre une animation mise en pause. Seek. Cette mthode attend une instance de TimeSpan afin de positionner la tte de lecture un temps donn de lanimation. Stop. Arrte la lecture du Storyboard et repositionne la tte de lecture la seconde 0.

Les trois mthodes SetTarget, SetTargetName et SetTargetProperty sont statiques et dfinies dans la classe Storyboard. Elles sont donc invoques par celle-ci. Elles sont trs importantes car elles montrent quel point le modle danimation de Silverlight est souple. Une animation au sein de la plateforme Silverlight est un objet indpendant de lobjet anim ou de la propri-

124

Partie II

Interactivit et cration graphique

t cible. Ces trois mthodes prennent en premier paramtre une instance de type TimeLine, donc tout type danimation. Les animations de type ColorAnimation, Storyboard ou Double Animation UsingKeyFrame entre autres en font partie. En second paramtre, il vous faudra passer une valeur attendue par la mthode. La mthode SetTarget attend, par exemple, une instance de Dependency Object comme second argument.

SetTarget. Prcise la rfrence de lobjet graphique animer. SetTargetName. Dfinit le nom de la cible animer, elle est utiliser ct XAML. SetTargetProperty. Cible la proprit interpoler sur lobjet cibl, par exemple lopacit (Opacity) ou la largeur (Width).

Ces mthodes statiques sont trs utiles. Prenons le cas dun designer interactif. Il ralise une animation sous Blend pour un menu spcifique. Lun de ses collgue dveloppeur souhaite rutiliser son animation pour la raffecter dautres menus. Afin dviter un travail fastidieux de recopie et de raffectation au sein de Blend, le dveloppeur rcupre la rfrence du Storyboard du designer, puis il raffecte dynamiquement, comme cible, une autre instance de DependencyObject au Storyboard:
Storyboard.SetTarget( MonAnimationCool, MonNouveauMenu); MonAnimationCool.Begin();

Nous allons maintenant passer la pratique afin dassimiler tous les concepts et principes que nous avons appris. Cependant, noubliez pas que Blend est un outil de mise en forme XAML. La nature profonde du XAML, base sur les relations familiales, rend impossible la gestion de tous les cas dimbrication ou dcriture directement par linterface graphique de Blend. Parfois, crire ou copier-coller du XAML dans lditeur de code sera plus pratique et rapide, voire incontournable.

6.2 Animer avec Expression Blend 6.2.1 Les bonnes pratiques


Lorsque vous souhaitez animer un visuel, plusieurs bonnes pratiques importantes doivent tre prises en compte. Si vous avez dj de bonnes notions en animation traditionnelle, vous pouvez ignorer ce passage. Dans tous les cas, les rgles sont faites pour tre outrepasses, mais elles servent de cadre et voluent avec les murs. Voici certaines dentre elles:

vitez danimer trop dobjets en mme temps. Arrangez-vous pour que lil ne soit pas accroch trop dendroits en mme temps. Essayez toujours de dfinir un sens de lecture et une unit danimation. Les animations de menus ne doivent pas excder une seconde. Dans le cas contraire, les animations deviennent prvisibles et pesantes lors dune utilisation prolonge. vitez autant que possible les animations linaires. Rien nest linaire dans la nature, seules les mathmatiques dcrivent de tels mouvements. Cela donne un aspect plat, monotone et robotique aux animations. Parfois un simple ralenti fait des merveilles.

Chapitre 6

Animations

125

Simplifiez vos animations et concentrez-vous avant tout sur les sensations que vous souhaitez crer. Lanimation doit tre compltement intgre dans le site ou lapplication et en prolonger lunit graphique. Les transitions sont aussi importantes que les interfaces, elles reprsentent un lien logique et sensible entre chaque interface. Soignez-les particulirement, mais restez sobre. Silverlight cible avant tout les applications riches. Essayez dintroduire des lments inattendus au cours de vos animations. Cela ajoute de la profondeur vos applications et lutilisateur voudra les explorer un peu plus pour dcouvrir de nouveaux dtails. Rythmez vos animations.

6.2.2 Crer une animation dintroduction


Dans Blend, ouvrez le projet SiteAgencePortfolio cr dans les prcdents chapitres. Nous allons lutiliser pour affiner notre comprhension du modle danimation travers la cration dune animation dintroduction. Vous trouverez galement ce projet dans larchive pleinEcran_ maquette.zip du dossier chap6 des exemples du livre. Nous allons dcouper les tapes de notre animation afin de lenrichir. Cela permet de rflchir et dimaginer le tempo facilement sans pour autant nous plonger directement dans laspect technique de la ralisation. Voici chaque tape de notre animation dintroduction: 1. Rien nest prsent sur lcran au lancement. 2. Les menus du haut apparaissent les uns aprs les autres avec un lger effet de dplacement vertical (du haut vers le bas). La dure totale de cette partie de lanimation ne doit pas excder une seconde. 3. Le centre du site apparat au milieu de lcran. 4. Les liens en bas apparaissent comme sils mergeaient du cadre central en 4/10 de seconde environ. 5. Le bouton plein cran apparat pratiquement en mme temps. En totalit, lanimation ne doit pas excder trois secondes. Crez une nouvelle animation et nommez la ressource Storyboard AnimIntro. Vous ntes pas oblig de crer les squences danimation dans lordre chronologique. Vous allez commencer par crer lapparition du centre de la page. Slectionnez le composant Border et nommez-le Contenu Page.
NOTE INFO

Nous nommons lobjet car en XAML une animation ne peut cibler que des objets nomms. Si vous lanimez sans lui donner de nom, Blend le nommera votre place. Cela est gnant car le nom donn sera trop gnrique et peu explicite.

Une fois nomm, dfinissez son opacit 0%. Il sagit bien de pourcentage car la plage de valeurs acceptes en C# ou en XAML se situe entre 0 et 1. Positionnez maintenant la tte de lecture la seconde 1,6, puis cliquez sur licne carre droite de la proprit Opacity. Un nouveau menu apparat. Cliquez sur loption "Record Current Value" (voir Figure 6.11).

126

Partie II

Interactivit et cration graphique

Figure6.11
Cration dune nouvelle cl danimation avec la valeur courante dune proprit.

Vous venez de crer une nouvelle cl danimation la seconde 1,6. Cela signifie que durant la premire cl et la seconde, lopacit ne change pas et reste zro. Comme lanimation na pas besoin dtre fluide, vous pouvez galement slectionner la seconde cl, puis choisir loption Hold In pour en faire une cl danimation de type Discrete (voir Figure 6.12).
Figure6.12
Cl danimation sans interpolation.

Dplacez la tte de lecture la seconde 2 et modifiez lopacit avec une valeur de 100. Testez votre animation. Le centre du site reste transparent durant une seconde et demie, puis apparat. Votre ligne de temps doit correspondre la Figure 6.13.
Figure6.13
Animation du composant Border.

Chacun des objets anims du site va suivre cette logique danimation avec quelques diffrences de tempo. Pour vous simplifier la vie, vous pouvez dupliquer le code XAML cr et cibler un autre composant comme, par exemple, le premier de nos menus qui est contenu au sein du WrapPanel. Vrifiez tout dabord que tous les boutons sont nomms pour quils puissent tre cibls en XAML (voir Figure 6.14).

Chapitre 6

Animations

127

Figure6.14
Nommage des menus.

Vous pouvez maintenant passer en mode ddition XAML. Voici la partie du code gnr par Blend:
<Storyboard x:Name="AnimIntro"> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ContenuPage" Storyboard.TargetProperty="(UIElement.Opacity)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> <DiscreteDoubleKeyFrame KeyTime="00:00:01.6" Value="0"/> <EasingDoubleKeyFrame KeyTime="00:00:02" Value="1"/> </DoubleAnimationUsingKeyFrames> </Storyboard>

Animer dautres objets graphiques est trs simple partir de cette base. Dupliquez le nud XAML DoubleAnimationUsingKeyFrame et remplacez la cible, soit la valeur de Storyboard.Target Name, par NouveautesBtn. Ensuite, pour les deuxime et troisime cls danimation, dfinissez la valeur de la proprit KeyTime respectivement 0 seconde et 3/10 et 0 seconde et 6/10:
<Storyboard x:Name="AnimIntro"> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard. TargetName="ContenuPage" Storyboard.TargetProperty= "(UIElement.Opacity)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> <DiscreteDoubleKeyFrame KeyTime="00:00:01.60000" Value="0"/> <SplineDoubleKeyFrame KeyTime="00:00:02" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard. TargetName="NouveautesBtn" Storyboard.TargetProperty= "(UIElement.Opacity)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> <DiscreteDoubleKeyFrame KeyTime="00:00:00.3" Value="0"/> <EasingDoubleKeyFrame KeyTime="00:00:00.6" Value="1"/> </DoubleAnimationUsingKeyFrames> </Storyboard>

Rptez cette opration pour les autres menus en dcalant la seconde et la troisime cls d1/10me de seconde. Pour cela, copiez et collez le code XAML que vous venez dcrire, puis changez le nom de lobjet cibl chaque fois (voir Figure 6.15).

128

Partie II

Interactivit et cration graphique

Figure6.15
Ligne de temps avec menus anims.

Testez votre animation. Il semble quil scoule un peu trop de temps entre lapparition du dernier menu et lapparition du fond central. Cela ne pose pas de problme. Vous pouvez glisser-dplacer les cls danimation du fond central pour les rapprocher de celles des menus.
NOTE INFO

Comme vous lavez constat, concevoir une animation en XAML par de simple copier-coller ne prend que quelques secondes. Vous pourrez toujours raliser en mode cration vos propres animations. Passer par le code peut vous sembler loign de la cration pure, mais cela est trs rapide quand vous connaissez prcisment vos objectifs. Vous pouvez galement affiner les animations gnres en mode cration. Il suffira de les centraliser au sein dun projet ddi pour les rcuprer nimporte quel moment.

Nous allons maintenant finir lanimation en faisant apparatre le composant StackPanel contenant le pied de page, puis le bouton plein cran. Procdez exactement de la mme manire et faites en sorte que le pied et le bouton apparaissent en dernier. Lanimation dintroduction est presque termine. Celle-ci est encore un peu fade car nous ciblons uniquement lopacit des objets. De plus, nous navons dfini aucune acclration sur chaque animation.

6.2.3 Dclencher des animations


Pour tester votre animation vous pouvez ouvrir la bibliothque de composants, puis slectionner longlet des comportements (Behaviors). Ensuite, glissez le comportement ControlStoryboard Action sur le composant UserControl racine. Celui-ci est ajout au sein de larbre visuel, mais ce nest pas un composant graphique. Il va simplement nous aider jouer lanimation au chargement de lapplication. Pour la proprit EventName, dfinissez la valeur Loaded. Pour le champ Story board, slectionnez AnimIntro (voir Figure 6.16).

Chapitre 6

Animations

129

Figure6.16
Configuration du comportement.

Ce comportement permet de jouer lanimation lorsque le contrle UserControl racine est charg. Toutefois laction entreprendre peut tre diffrente. Par dfaut, laction est de lire le Storyboard. Appuyez sur la touche F5 de votre clavier pour tester votre animation dans des conditions relles. Pour revoir plusieurs fois lanimation se jouer, vous navez qu rafrachir la page au sein du navigateur. Nous apprendrons la section6.3 contrler des Story boards avec C#.

6.2.4 Les transformations relatives


Pour donner un peu de relief, nous allons animer dautres proprits que lopacit. Pour les menus, nous pourrions par exemple les faire apparatre tout en les dplaant de haut en bas. Slectionnez le premier menu, positionnez la tte de lecture la seconde 0. Tout en maintenant la touche Maj enfonce, appuyez deux fois sur la flche du haut. De cette manire, le menu est dplac de 20pixels vers le haut. Dplacez la tte de lecture de 3/10me, puis repositionnez le menu de 20pixels vers le bas. Celui-ci a repris sa position dorigine. ce stade, notre objet est anim alors quil nest toujours pas visible. Jusqu maintenant, pour dcaler nos animations, nous avions besoin de trois cls danimation. Toutefois, il existe une autre manire de procder. Toutes les classes hritant de la classe abstraite TimeLine possdent la proprit BeginTime. Dpliez larborescence du menu NouveautesBtn et slectionnez la ligne RenderTransform. Passez ensuite en mode ddition mixte pour faire apparatre le code XAML correspondant ce nud, modifiez la valeur de la proprit BeginTime 0 seconde et 4/10:
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00.3" Storyboard.TargetName="NouveautesBtn" Storyboard. TargetProperty="(UIElement.RenderTransform).(TransformGroup. Children) [3].(TranslateTransform.Y)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-20"/> <EasingDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/> </DoubleAnimationUsingKeyFrames>

Vous venez de dcaler lanimation de transparence de 3/10 de seconde. Cela vous permet danimer le dplacement du menu au mme instant o vous le faites apparatre. Au sein de Blend, la zone grise du dplacement est dcale vers la droite de 0/10me (voir Figure 6.17).

130

Partie II

Interactivit et cration graphique

Figure6.17
Dcaler une squence danimation au sein de Blend.

Regardez maintenant la proprit cible par notre squence danimation:


Storyboard.TargetProperty="(UIElement.RenderTransform). (TransformGroup.Children)[3].(TranslateTransform.Y)">

Laccs la proprit Y nest pas simple. En fait, ds que nous avons modifi la position de notre menu, Blend y a automatiquement gnr un nud de transformation relative. Pour rappel, les transformations relatives permettent de saffranchir des contraintes lies la mise en page du conteneur (voir section 5.5.3.2). Lorsque vous animez des objets, Blend privilgiera toujours lutilisation des transformations relatives. Pour des raisons pratiques, le nud RenderTransform est toujours gnr par Blend de la mme manire. Il existe toutefois de nombreuses faons dcrire ce type de nud. Ne vous formalisez pas si vous rencontrez une criture diffrente. Voici le nouveau code XAML dcrivant notre menu:
<Button x:Name="NouveautesBtn" Height="Auto" Width="Auto" Content="Nouveauts" Margin="0,0,20,0" FontSize="14" FontFamily="Trebuchet MS" Visibility="Visible" RenderTransformOrigin="0.5,0.5"> <Button.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Button.RenderTransform> </Button>

La consquence directe du ciblage dun nud RenderTransform par une animation est que si celui-ci nexiste pas rellement dans la balise du composant, Blend lve une erreur de ciblage. Pour le dmontrer, il suffit de copier-coller notre nouvelle animation tout en ciblant les autres boutons chaque fois et en dcalant de 1/10me de seconde la valeur de BeginTime (voir Figure 6.18).
Figure6.18
Erreur leve lorsque lon cible un nud RenderTransform inexistant.

Chapitre 6

Animations

131

Pour rsoudre ce problme, vous devez coller le nud RenderTransform suivant au sein de chaque menu :
<Button.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Button.RenderTransform> </Button>

Chaque menu est maintenant anim du haut vers le bas. Lanimation prend peu peu plus dampleur. Vous pouvez procder de la mme manire pour le composant StackPanel reprsentant le pied de page. Vous risquez cependant de rencontrer quelques difficults lors de la compilation. Le nud RenderTransform que nous copions dbute par Button.RenderTransform. Or, comme il est situ dans le nud lment StackPanel, le compilateur lvera une erreur. Pour viter tout problme, il suffit de remplacer Button par Framework Element de cette manire:
<FrameworkElement.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </FrameworkElement.RenderTransform> </StackPanel>

NOTE INFO

La classe FrameworkElement est hrite de tous les composants visuels et elle possde la proprit RenderTransform. Pour cette raison, quel que soit le composant visuel auquel vous souhaitez ajouter un nud RenderTransform, cette classe fera laffaire pour le dclarer. En programmation oriente objet, ce concept trs puissant est appel polymorphisme. Il est ralisable travers lhritage de classes ou limplmentation dinterfaces. Concrtement, vous lutiliserez lorsque vous ne connatrez pas lavance le type de lobjet ce qui est le cas ici. Comme les objets graphiques hritent tous de FrameworkElement, vous navez pas connatre le type prcis de chacun deux pour affecter le nud RenderTransform.

Voici le code XAML permettant danimer le pied de page:


<DoubleAnimationUsingKeyFrames BeginTime="00:00:01.3" Storyboard. TargetName="PiedDePage" Storyboard.TargetProperty= "(UIElement.RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.Y)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-20"/> <EasingDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/> </DoubleAnimationUsingKeyFrames>

Vous remarquez que le StackPanel est renomm en PiedDePage. Lanimation subit un dcalage de une seconde et 3/10 afin dtre lue en mme temps que celle concernant lopacit. Pour finir, nous allons faire apparatre le bouton plein cran. Positionnez la tte de lecture la seconde0,

132

Partie II

Interactivit et cration graphique

puis modifiez lchelle du bouton via longlet des transformations relatives. Dfinissez une chelle ScaleX et ScaleY 0,5. Cela signifie qu cette seconde, il ne possdera que la moiti de ses dimensions dorigine. Dplacez ensuite la tte de lecture la seconde 0 et 3/10 et dfinissez lchelle 1 pour ScaleX et ScaleY. Dcalez cette animation pour quelle corresponde exactement celle de lopacit. Nous nous approchons dun premier rsultat, il nous reste encore quelques rglages pour voir aboutir lanimation. Vous pouvez rcuprer cette tape de lanimation (pleinEcran_maquetteAnimee_1.zip) dans le dossier chap6 des exemples.

6.3 Grer lacclration


Comme nous lavons voqu dans les bonnes pratiques, il faut viter les animations linaires dans la majorit des cas. Silverlight vous permet dviter cet cueil grce trois types de mode danimation : Spline, Easing et Discrete. Le mode Discrete nest pas pertinent car aucune interpolation nest ralise par Blend. Dans ce cas, la transition est abrupte. Il nous reste les modes Spline et Easing qui font rfrence aux mme principes.

6.3.1 Les principes


Il nous faut dabord comprendre ce quest une acclration avant daborder sa gestion au sein de Blend. Pour rsumer, lacclration, quelle soit positive ou ngative, est une modification de la vitesse au cours du temps. La vitesse est le rythme du changement. Lorsque vous lchez une balle au-dessus du sol, elle subit lacclration de la pesanteur correspondant un G (G pour Gravit), soit 9,82 m/s-2. Cela signifie que lorsque la balle nest plus tenue, elle tombe de plus en plus rapidement vers le sol. Sil ny avait pas dacclration, elle tomberait de manire constante vers le sol (voir Figure 6.19).
Figure6.19
Mouvement sans acclration et avec acclration.

Dans le premier cas, le dplacement de la balle est constant, cela est visible car lespace entre deux instants gaux est toujours le mme. A contrario, dans le second cas, lespace entre chaque affichage de la balle grandit car la vitesse augmente au fur et mesure du temps. Il est galement possible de reprsenter lacclration grce un petit graphique. La Figure 6.20 illustre la reprsentation dun ralenti. On saperoit qu 20% du temps de lanimation, 50% de celle-ci est dj effectue. Cela signifie quil reste 50% de lanimation raliser en 80% de temps restant. La vitesse est donc en forte diminution.

Chapitre 6

Animations

133

Figure6.20
Reprsentation dune dclration sous forme de graphique.

Nous allons maintenant aborder ce sujet au sein de lenvironnement Silverlight et tudier les moyens mis en uvre par Blend pour grer lacclration. Dans Silverlight, lacclration est toujours dfinie sur la cl darrive. Lorsque vous souhaiterez en crer une spcifique entre deux cls danimation, il vous faudra donc slectionner la cl darrive, puis modifier ses proprits. Lavantage de grer lacclration sur limage cl darrive est quune cl initiale nest pas ncessaire pour crer une animation. Pour mieux lexpliquer et le dmontrer, nous allons animer le rebond dune balle avec une seule cl.

6.3.2 Une animation de rebond en une seule cl danimation


Une animation, dans Silverlight, peut-tre dfinie grce une unique cl darrive. Dans ce cas, lanimation est en fait une interpolation entre la valeur en cours de la proprit de lobjet et la valeur de destination dfinie par la cl. Cela signifie que lanimation sera calcule en fonction de la valeur de dpart de manire dynamique, ce qui facilite grandement le travail. Nous allons tudier et crer ce type danimation dans cette section. Nous aurons nouveau loccasion de le faire au Chapitre 7.

6.3.2.1 Crer la balle


Au sein de Blend, crez une nouvelle application Silverlight nomme AnimRebond. Nous allons commencer par crer une balle. Crez deux cercles parfaits lun sur lautre en instanciant le composant Ellipse. Slectionnez-les tous les deux, puis groupez-les au sein dune grille en utilisant le raccourci Ctrl+g. Nommez la grille MaBalle (voir Figure 6.21).
Figure6.21
Imbrication de la balle.

134

Partie II

Interactivit et cration graphique

Cachez linstance dEllipse qui est lavant-plan. Cela vous permet de travailler sur lautre de manire plus simple. Dfinissez-lui un dgrad radial partant de lorange clair vers lorange fonc. Pour crer un dgrad, au sein du panneau des proprits, slectionnez Fill puis le mode dgrad radial. Modifiez ensuite les picots pour grer la couleur du dbut de dgrad et celle de fin de dgrad. Ceux-ci sont situs sur la rglette des dgrads (voir Figures 6.22 et 6.23).
Figure6.22
Crer un dgrad radial.

Depuis la version 3 de Blend, il est possible de modifier les picots directement au sein de la vue de cration. Pour cela cliquez sur licne de gestion des dgrads (voir Figure6.23).
Figure6.23
Modifier un dgrad radial au sein de la fentre de cration.

Grce cet outil, vous pouvez directement, et de manire sensible, modifier et grer le remplissage dun dgrad. Faites apparatre le second cercle, puis au sein du panneau des transformations relatives, dfinissez une chelle en ScaleX 0,6 et laissez lchelle ScaleY sa valeur. Dfinissez galement un dgrad de couleur, mais dans les tons vert ou bleu. Le rsultat est reproduit la Figure 6.24.
Figure6.24
Une balle en plastique.

Chapitre 6

Animations

135

6.3.2.2 Les quations d'acclration


Maintenant que vous avez cr la balle, il ne reste plus qu raliser lanimation. Pour cela, nous allons utiliser les quations dacclration. Cliquez sur licne correspondante (. ) et nommez lanimation AnimRebond. Une fois en mode denregistrement, dplacez le composant Grid Ma Balle de 200 pixels vers le bas et de 100 pixels vers la droite. Vous venez de crer deux cls danimation la seconde 0, la premire pour le dplacement en X et la seconde pour le dplacement en Y. Dplacez la cl principale la seconde 2, puis dpliez compltement larbre visuel afin de slectionner la cl gnre par le dplacement vertical. Dans le panneau des proprits, cliquez sur la liste droulante contenant les quations dacclration et choisissez celle dcrivant un rebond larrive (voir Figure6.25). Vous pouvez rgler cette acclration grce deux paramtres : le facteur de rebond (Bounciness) et le nombre de rebonds (Bounces). Plus le facteur de rebond est faible, plus les rebonds gagneront en amplitude. Plus le facteur sera lev, moins les rebonds seront visibles. Pour chaque composant visuel, il est possible de dfinir, en une seule fois, une acclration diffrente pour chaque cl ou encore pour toutes les cls situes la mme seconde. Il suffit pour cela de configurer la cl danimation situe au mme niveau que lobjet. De cette manire, toutes les proprits sont interpoles de manire identique.
Figure6.25
Choisir une acclration de type rebond larrive.

6.3.2.3 Les courbes dacclration


Nous allons choisir un autre type dacclration pour laxe des X. Slectionnez la cl correspondante et dans le panneau des proprits choisissez longlet KeySpline. Configurez la courbe dacclration manuellement pour crer un lger effet de ralenti. Dplacez le point jaune situ en haut droite du graphique vers lintrieur du graphe (voir Figure6.26).

136

Partie II

Interactivit et cration graphique

Figure6.26
Personnaliser une courbe dacclration.

Lextrmit de la tangente est dtermine en sortie de courbe par les valeurs X2 et Y2. Voici le XAML gnr pour les deux types dacclration que nous venons de dfinir:
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard. TargetName="MaBalle" Storyboard.TargetProperty="(UIElement. RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.Y)"> <EasingDoubleKeyFrame KeyTime="00:00:01" Value="200"> <EasingDoubleKeyFrame.EasingFunction> <BounceEase Bounciness="2"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard. TargetName="MaBalle" Storyboard.TargetProperty="(UIElement. RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.X)"> <SplineDoubleKeyFrame KeyTime="00:00:01" Value="50" KeySpline="0,0,0.3,0.8"/> </DoubleAnimationUsingKeyFrames>

Vous pouvez remarquer en gras les deux types de cls correspondants aux modifications que nous avons apportes. La proprit KeySpline contient les coordonnes des points de tangence soit, dans lordre, X1, Y1, X2 et Y2. Testez votre animation au sein de Blend puis dans votre navigateur prfr. Vous pouvez utiliser un comportement de type Control StoryboardAction afin de dclencher la lecture de lanimation lexcution (voir la section6.2.3). Comme vous le constatez, une seule cl danimation est ncessaire. Le principal avantage de ce comportement est de permettre une mise jour plus facile de vos animations en vitant de figer par une cl leur point de dpart. Nous allons le dmontrer simplement. Fermez le Storyboard AnimRebond et dplacez votre balle nimporte o au sein du conteneur LayoutRoot. Puis recompilez votre application et testez-la. Comme lanimation utilise les transformations relatives, elle est indpendante des contraintes du conteneur. De plus, comme elle ne possde quune cl darrive, elle a exactement le mme effet quelle que soit la position par dfaut de lobjet. Autrement dit lanimation est totalement indpendante de la scne principale ou de lobjet cibl.

Chapitre 6

Animations

137

Pour vous en convaincre, crez un rectangle nimporte o dans LayoutRoot et nommez-le MonCarre. Crez-y un nud de transformations relatives, RenderTransform (voir section6.2.4), puis dupliquez lanimation en copiant-collant le code XAML.
NOTE INFO

Vous pouvez galement dupliquer lanimation au sein de linterface visuelle de Blend. Pour cela, ouvrez lanimation AnimRebond en cliquant sur licne de liste dactions (). Une fois lintrieur, cliquez sur licne droulante () situe juste droite de licne dajout et slectionnez loption Dupliquer. Vous tes dsormais dans lanimation AnimRebond_copy. Cliquez nouveau sur licne et choisissez Renommer.

Changez le nom par AnimRebondCarre. Passez en mode ddition mixte, puis modifiez la cible des deux sous-squences danimation de type DoubleAnimation par MonCarre. Vous venez de dupliquer lanimation et vous avez chang sa cible en quelques secondes. Vous pouvez tester lanimation directement dans Blend.
NOTE INFO

Grce licne de liste dactions, vous pouvez ajouter, supprimer, renommer et dupliquer une ressource Storyboard. Vous pouvez mme inverser lordre des cls danimation. Toutefois, cette dernire opration nest pas sans surprises car seul lordre des enfants de la proprit KeyFrames est invers. Autrement dit, le timing de lanimation ne lest pas rellement. Il vous faudra donc un peu plus de travail si vous avez plus de deux cls pour la mme proprit.

Lexercice finalis est dans larchive AnimRebond.zip du dossier chap6 des exemples.

6.3.3 Amliorer lanimation dintroduction


Nous allons maintenant amliorer notre animation principale en grant lacclration des cls danimation. Cela ne devrait pas poser beaucoup de problmes. Nous allons cependant limiter deux le nombre de types dacclration. Ouvrez la solution faisant rfrence au projet Site AgencePortFolio l o nous lavions laiss la section6.2. Vous trouverez aussi ce fichier dans larchive pleinEcran_maquetteAnimee_1.zip du dossier chap6 des exemples du livre. Slectionnez la dernire image cl de chaque animation de modification relative, Render Transform, et dfinissez une acclration de type Back Out (voir Figure 6.27). Cette quation dacclration est assez pratique car la valeur de la proprit dpasse un peu celle de destination avant de latteindre avec un effet de ralenti. Ce genre dacclration est utile car impossible raliser avec les courbes dacclration de type Spline. Il est en effet impossible de dfinir un point de tangence dont les coordonnes dpassent1enY, soit 100% de ralisation du mouvement. Si vous trouvez le tempo trop rapide, espacez lgrement chaque cl. De mme, si lil de lutilisateur nest pas assez attir en bas droite, pour lanimation du pied de page en fin dintroduction, il vous suffit de ralentir lanimation. Toutefois, dun point de vue design, de nombreux changements seront mis en uvre. Le gris clair des contrles par dfaut est neutre et nattire pas le regard.

138

Partie II

Interactivit et cration graphique

Dautres moyens sont encore notre disposition pour soutenir cette animation et lintgrer au sein dune charte graphique. Un autre facteur est galement trs important : les dimensions du site. Comme le site occupe 100% de la fentre du navigateur, si ce dernier accapare tout votre cran, les difficults de dcryptage pour lutilisateur en seront accrues. Le redimensionnement est trs pratique, mais peut influencer lanimation et son impact visuel au sein dune application ou dun site web. Pour finir, slectionnez la dernire image cl de chaque animation dopacit, puis dfinissez soit une courbe dacclration soit une quation dacclration avec ralenti.
Figure6.27
Personnalisez lacclration des nuds RenderTransform.

6.4 Animer avec C# 6.4.1 Lintrt danimer avec C#


Il nous faut tout dabord lever toute ambigut en prcisant que lanimation dun site incombe avant tout lanimateur, au designer interactif ou au directeur artistique. Celle-ci est directement lie la charte graphique, lexprience utilisateur et donc lergonomie. Toutefois, notre but dans cette section est dapprendre crer des animations dynamiquement. Les langages C# ou VB ne remplaceront bien sr jamais un logiciel comme Blend dun point de vue crativit, mais lutilisation dun langage logique ouvre de nombreuses possibilits et offre une grande souplesse de production. On le constate aisment avec des technologies du type Processing. Cette dernire prsente lavantage de gnrer des animations trs esthtiques en temps rel. Pour de plus amples informations sur cette technologie, rendez-vous sur le site: http://processing.org. Toutefois ces technologies sinscrivent souvent dans une dmarche artistique. Les outils et les bibliothques proposs sont par nature orients vers le visuel et linteractivit et non vers la fonctionnalit, au contraire de C#. La cration danimations via C# ou VB prsente tout de mme de nombreux intrts si celle-ci est encadre par des cratifs. Grce C#:

On vite le travail rbarbatif de recopie des animations sous Blend sans enlever la conception de celle-ci aux animateurs. Il est possible dajouter une couche dinteractivit utilisateur supplmentaire en mettant jour les animations dynamiquement.

Chapitre 6

Animations

139

On peut dclencher des animations alatoirement ou de manire rythme. Lanimation de particules est notre porte. Cela nous permet de simuler des fluides, de la fume, de la pluie ou un vol doiseau.

Tous ces avantages sont attrayants et justifient un investissement dans ce domaine. Nous allons aborder chacun deux dun point de vue pratique.

6.4.2 Instanciation dynamique de ressources Storyboard


Ouvrez le projet AnimRebond que vous avez ralis dans un prcdent exercice (AnimRebond.zip). Dans un premier temps, nous allons crer la mme animation que celle que nous avions ralise, mais uniquement avec C# pour apprendre les concepts.

6.4.2.1 Crer l'animation de rebond en C#


La premire tape consiste dupliquer la balle. Nommez la nouvelle balle MaBalle2. Slec tionnez la grille LayoutRoot, puis dans le panneau des vnements de lobjet entrez PlayAnimBalle pour lvnement MouseLeftButtonDown (voir Figure 6.28). Blend ouvre automatiquement le fichier de code logique C# correspondant notre fichier XAML et cre une mthode PlayAnimBalle. Elle se dclenchera chaque fois que lutilisateur cliquera sur la grille principale. Cette mthode nous permettra de dclencher la lecture du Storyboard, que nous allons crer par code.
Figure6.28
Dfinir une mthode dcoute pour lvnement MouseLeftButtonDown de lobjet LayoutRoot.

Le code ci-dessous expose la cration dune nouvelle ressource Storyboard:


public partial class MainPage : UserControl { Storyboard AnimRebondCode; public MainPage() { InitializeComponent();

140

Partie II

Interactivit et cration graphique

Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e) { //on commence par instancier une nouvelle ressource Storyboard AnimRebondCode = new Storyboard(); //on cre ensuite la sous-squence d'animation //en lui dfinissant une nouvelle destination DoubleAnimation DaY = new DoubleAnimation(); //on dfinit la valeur d'arrive de la proprit //qui sera cible, on a le choix entre To et By DaY.To = 200; //DaY.By = 200; //By permet d'ajouter une valeur de destination //relative la valeur actuelle //Puis une nouvelle quation d'acclration pour la //sous-squence d'animation DaY.EasingFunction = new BounceEase(); //La classe Storyboard nous permet de modifier l'objet //cibl par l'animation via la mthode statique SetTarget Storyboard.SetTarget(AnimRebondCode, MaBalle2); //La classe Storyboard nous fournit galement une mthode //pour cibler la proprit animer Storyboard.SetTargetProperty(DaY, new PropertyPath("(UIElement. RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.Y)")); //On ajoute la sous-squence d'animation comme enfant du Storyboard AnimRebondCode.Children.Add(DaY); //l'tape finale facultative consiste ajouter le Storyboard //aux ressources du UserControl racine, soit //this Resources.Add("AnimRebondCodeCl", AnimRebondCode); } private void PlayAnimBalle(object sender, MouseButtonEventArgs e) { AnimRebondCode.Begin(); } }

Deux ou trois concepts mritent dtre expliqus. Tout dabord, la cration, puis lutilisation dun Storyboard contiennent pratiquement les mmes tapes que lajout dun objet Framework Element larbre visuel dune application. On le dclare comme membre de classe pour y accder depuis nimporte quelle mthode. On linstancie ensuite au chargement de lapplication. Pour finir, on lajoute comme enfant de la proprit Resources. Cette dernire tape est ncessaire uniquement si vous souhaitez utiliser le Storyboard comme ressource, ce qui nest pas obligatoire depuis Silverlight 3. Il est conseill de ne pas lajouter par dfaut afin de faciliter la libration des ressources en cas de suppression du Storyboard. Cette proprit est propre tous les objets de type Framework Element. Nimporte quel objet au sein de larbre visuel peut donc possder des ressources. Nous pourrions donc trs bien avoir le code XAML suivant:

Chapitre 6

Animations

141

<Grid > <Button Width="100" Height="30"> <Button.Resources> <Storyboard x:Name="monAnimAccessibleDansButton" > </Storyboard> </Button.Resources > </Button> </Grid >

Comme nous lavons montr la section6.1.4, les objets de type Storyboard sont considrs comme des ressources car ils ne possdent pas de reprsentation visuelle concrte. La proprit Resources fait rfrence aux dictionnaires de ressources. Elle implmente linterface IDiction nary. Chaque ressource, lorsquelle est ajoute au dictionnaire, doit possder une cl daccs. Cest cela que sert la chane de caractres passe en premier paramtre:
Resources.Add("AnimRebondCodeCl", AnimRebondCode);

Le second argument reprsente la rfrence du Storyboard que nous souhaitons ajouter. Une autre difficult que vous pouvez rencontrer est le ciblage de la proprit animer. Dans la ligne de code ci-dessous, nous spcifions le chemin daccs pour la proprit Y de type Render Transform:
Storyboard.SetTargetProperty(DaY, new PropertyPath("(UIElement. RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.Y)"));

Cela peut paratre un peu barbare, mais vous pouvez copier-coller le chemin daccs grce au code XAML gnr automatiquement par Blend. De plus, ce type de chemin nest ncessaire que pour les transformations relatives. Pour dautres proprits propres aux objets eux-mmes, comme Opacity ou Width, vous pouvez utiliser des membres statiques de classe suffixs de Property:
PropertyPath pp = new PropertyPath( Canvas.WidthProperty ); Storyboard.SetTargetProperty(DaY, pp);

Pour finir, il ne faut pas oublier de cibler lobjet animer. cette fin, utilisez la mthode statique SetTarget de la classe Storyboard. Vous devez prciser linstance de type Time Line et la cible anime par cette dernire:
//La classe Storyboard nous permet de modifier l'objet //cibl par l'animation via la mthode statique SetTarget Storyboard.SetTarget(AnimRebondCode, MaBalle2);

Nous allons maintenant pousser ce concept un peu plus loin.

6.4.2.2 Mise jour dynamique de l'animation


Pour linstant, tout ce que nous faisons peut tre ralis dans Blend. Vous allez ajouter un peu de logique afin dillustrer lintrt de C#. Lorsque lutilisateur cliquera sur la grille principale, la balle se dplacera aux coordonnes o lvnement se sera produit. Tout dabord, vous allez afficher les informations concernant le clic du bouton de la souris sur LayoutRoot. Crez un nouveau membre de classe de type TextBlock, nomm InfoTxt, puis ajoutez-le comme enfant du conteneur LayoutRoot lors du chargement de lapplication:

142

Partie II

Interactivit et cration graphique

TextBlock InfoTxt = new TextBlock(); void MainPage_Loaded(object sender, RoutedEventArgs e) { LayoutRoot.Children.Add(InfoTxt); // le code vu prcdemment dans cette mthode }

Il faut galement modifier la mthode PlayAnimBalle pour rcuprer les coordonnes de la souris lors de lvnement OnMouseDown:
private void PlayAnimBalle(object sender,MouseButtonEventArgs e) { Point Position = e.GetPosition(null); InfoTxt.Text = Position.ToString(); AnimRebondCode.Begin(); }

La structure de type Position contient deux valeurs de type de double correspondant X et Y. Celle-ci est rcupre grce largument de type MouseButtonEventArgs. Nous reviendrons sur ce type dargument au Chapitre 8. Le champ texte indique dsormais les coordonnes de la souris linstant o vous cliquez sur le conteneur LayoutRoot. Pour se dplacer aux coordonnes X et Y, nous devons dfinir une deuxime animation ciblant cette fois laxe des X:
void MainPage_Loaded(object sender, RoutedEventArgs e) { LayoutRoot.Children.Add(InfoTxt); //on commence par instancier une nouvelle ressource Storyboard AnimRebondCode = new Storyboard(); //on cre ensuite la sous-squence d'animation //en lui dfinissant une nouvelle destination DoubleAnimation DaY = new DoubleAnimation(); DoubleAnimation DaX = new DoubleAnimation(); #region plus besoin de ce code //on dfinit la valeur d'arrive de la proprit qui sera cible //on a le choix entre To et By //DaY.To = 200; //Dax.By = 200; //By permet d'ajouter une valeur relative la valeur actuelle #endregion //Puis une nouvelle quation d'acclration pour la //sous-squence d'animation DaY.EasingFunction = new BounceEase(); DaX.EasingFunction = new BounceEase(); //La classe Storyboard nous permet de modifier l'objet //cibl par l'animation via la mthode statique SetTarget Storyboard.SetTarget(AnimRebondCode, MaBalle2); //La classe Storyboard nous fournit galement une mthode //pour cibler la proprit animer Storyboard.SetTargetProperty(DaY, new PropertyPath("(UIElement. RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.Y)")); Storyboard.SetTargetProperty(DaX, new PropertyPath("(UIElement. RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.X)"));

Chapitre 6

Animations

143

//On ajoute la sous-squence d'animation comme enfant du Storyboard AnimRebondCode.Children.Add(DaY); AnimRebondCode.Children.Add(DaX); }

Il suffit maintenant de modifier notre animation pour que les valeurs de destination soient mises jour. Toutefois, il faut faire la diffrence entre les coordonnes de la souris, que nous rcuprons sur le conteneur, et les transformations relatives X et Y que nous affectons. Le code suivant est un dbut mais nest pas suffisant:
private void PlayAnimBalle(object sender, MouseButtonEventArgs e) { Point Position = e.GetPosition(null); InfoTxt.Text = Position.ToString(); (AnimRebondCode.Children[0] as DoubleAnimation).To = Position.Y; (AnimRebondCode.Children[1] as DoubleAnimation).To = Position.X; AnimRebondCode.Begin(); }

Vous remarquez quil y a un dcalage entre le point de destination des animations X et Y et lendroit o vous avez cliqu. Ceci est d aux transformations relatives. Dans le code prcdent, chaque fois que vous cliquez, vous ajoutez les coordonnes de votre souris la position initiale de la balle au sein du conteneur LayoutRoot. Pour remdier ce problme, vous avez deux choix. Le plus simple consiste positionner MaBalle2 en haut gauche de LayoutRoot en supprimant les marges et en choisissant un alignement gauche et droite (voir Figure 6.29).
Figure6.29
Modification des marges et de lalignement de MaBalle2.

Recompilez votre application pour voir le rsultat. Elle fonctionne mieux, mais cette solution vous oblige positionner votre balle en haut gauche lors de la compilation. La seconde solution plus pratique consiste soustraire les marges existantes et spcifier un alignement en haut et gauche:
private void PlayAnimBalle(object sender, MouseButtonEventArgs e) { Point Position = e.GetPosition(null); InfoTxt.Text = Position.ToString(); double NewPosY = Position.Y - MaBalle2.Margin.Top-(MaBalle2.Height/2); double NewPosX = Position.X - MaBalle2.Margin.Left-(MaBalle2.Width/2); (AnimRebondCode.Children[0] as DoubleAnimation).To = NewPosY; (AnimRebondCode.Children[1] as DoubleAnimation).To = NewPosX; AnimRebondCode.Begin(); }

Dans le code prcdent, la moiti de la largeur et de la hauteur de la balle est galement soustraite. Ceci vous permet de positionner le centre de la balle exactement l o vous avez cliqu.

144

Partie II

Interactivit et cration graphique

6.4.3 Affectation dynamique de Storyboards


Vous allez affecter la mme animation diffrents objets contenus dans une grille. Crez un nouveau projet nomm AnimRebond_Dynamic. Commencez par la mise en place du projet sous Expression Blend. Au sein du conteneur LayoutRoot, crez trois copies de notre balle ayant pour nom MaBalle1, MaBalle2 et MaBalle3. En arrire-plan des balles, et toujours dans la grille LayoutRoot, instanciez un nouvel objet de type Grid et appelez-le ZoneClick. Cette grille doit possder une marge basse de 110 pixels. Vous pouvez lui affecter une couleur darrire-plan pour la visualiser plus facilement. La marge vous permet de positionner un composant StackPanel horizontal entre le bas de la zone de clic et le bord infrieur de notre application. Le composant contiendra les boutons qui modifieront la cible de lanimation, ainsi que les coordonnes lors du clic de souris. Autrement dit, nous changerons dynamiquement la rfrence correspondant lobjet cibl. Cela est ralisable grce la mthode statique SetTarget de la classe Storyboard. Nommez le StackPanel BoutonsInfos et crez les boutons. Pour chacun deux, la proprit Content doit tre affecte de la valeur Anim Balle 1, Anim Balle 2 ou Anim Balle 3 (voir Figure6.30).
Figure6.30
Interface pour animation dynamique.

Le code ressemble celui de notre projet prcdent, toutefois de subtiles modifications nous permettent damliorer son comportement. Commencez par recopier le code de la prcdente animation. Il vous faut ajouter le membre de classe BalleEnCours (de type FrameworkElement). Il correspond la rfrence de la balle actuellement cible par lanimation. Spcifiez ensuite une mthode pour lvnement MouseLeftButtonDown de chaque bouton. Vous pouvez utiliser le panneau des vnements cette fin. Nommez ces mthodes SetBalle1, SetBalle2 et Setballe3. Au sein de ces fonctions, vous allez redfinir la cible de lanimation. Ainsi, lorsque vous cliquerez sur le bouton 3, le Storyboard ciblera la balle 3. Voici la totalit du code mis jour:
public partial class MainPage : UserControl { Storyboard AnimRebondCode; FrameworkElement BalleEnCours; public MainPage() { InitializeComponent(); Loaded +=new System.Windows.RoutedEventHandler(MainPage_Loaded); } TextBlock InfoTxt = new TextBlock(); void MainPage_Loaded(object sender, RoutedEventArgs e)

Chapitre 6

Animations

145

{ //Par dfaut on anime la premire balle BalleEnCours = MaBalle1; BoutonsInfos.Children.Add(InfoTxt); AnimRebondCode = new Storyboard(); DoubleAnimation DaY = new DoubleAnimation(); DoubleAnimation DaX = new DoubleAnimation(); DaY.To = 200; DaY.EasingFunction = new BackEase(); DaX.EasingFunction = new ElasticEase(); //La classe Storyboard nous permet de modifier l'objet //cibl par l'animation via la mthode statique SetTarget Storyboard.SetTarget(AnimRebondCode, BalleEnCours); Storyboard.SetTargetProperty(DaY, new PropertyPath("(UIElement. RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.Y)")); Storyboard.SetTargetProperty(DaX, new PropertyPath("(UIElement. RenderTransform).(TransformGroup.Children)[3].( TranslateTransform.X)")); AnimRebondCode.Children.Add(DaY); AnimRebondCode.Children.Add(DaX); } private void PlayAnimBalle(object sender, MouseButtonEventArgs e) { Point Position = e.GetPosition(null); InfoTxt.Text = "X :: "+ Position.X + " - Y :: " + Position.Y; double NewPosY = Position.Y - BalleEnCours.Margin.Top (BalleEnCours.Height / 2); double NewPosX = Position.X - BalleEnCours.Margin.Left (BalleEnCours.Width / 2); (AnimRebondCode.Children[0] as DoubleAnimation).To = NewPosY; (AnimRebondCode.Children[1] as DoubleAnimation).To = NewPosX; AnimRebondCode.Begin(); } private void SetBalle1(object sender, RoutedEventArgs e) { AnimRebondCode.Stop(); BalleEnCours = MaBalle1; Storyboard.SetTarget((AnimRebondCode.Children[0]), BalleEnCours); Storyboard.SetTarget((AnimRebondCode.Children[1]), BalleEnCours); } private void SetBalle2(object sender, RoutedEventArgs e) { AnimRebondCode.Stop(); BalleEnCours = MaBalle2; Storyboard.SetTarget((AnimRebondCode.Children[0]), BalleEnCours);

146

Partie II

Interactivit et cration graphique

Storyboard.SetTarget((AnimRebondCode.Children[1]), BalleEnCours);

private void SetBalle3(object sender, RoutedEventArgs e) { AnimRebondCode.Stop(); BalleEnCours = MaBalle3; Storyboard.SetTarget((AnimRebondCode.Children[0]), BalleEnCours); Storyboard.SetTarget((AnimRebondCode.Children[1]), BalleEnCours); }

Revenons un peu sur ce code. Le moteur Silverlight ne permet pas un Storyboard dtre utilis plusieurs fois, tant que celui-ci est actif. Il nous faut donc librer la ressource Story board en invoquant la mthode Stop, avant de pouvoir lui affecter une nouvelle cible:
private void SetBalle3(object sender, RoutedEventArgs e) { AnimRebondCode.Stop(); BalleEnCours = MaBalle3; Storyboard.SetTarget((AnimRebondCode.Children[0]), BalleEnCours); Storyboard.SetTarget((AnimRebondCode.Children[1]), BalleEnCours); }

Lorsque vous relchez le bouton gauche de la souris nimporte o sur la zone de clic, la mthode PlayAnimBalle est excute. Il est assez pratique dans notre cas dappeler une mthode lorsque le bouton gauche de la souris est enfonc (MouseLeftButtonDown), puis den appeler une autre quand celui-ci est relch (MouseLeftButtonUp). Cela vous permet de contrler sereinement lenchanement des tapes. Nous pourrions par exemple dfinir la nouvelle balle animer lorsque lutilisateur appuie sur lune dentre elles, puis dclencher lanimation lorsquil relche le bouton. Les objets prsents au sein de larbre visuel sont tous interactifs, cela vous vite dinstancier des composants Button pour tout et nimporte quoi.

6.4.4 Dupliquer un Storyboard cr dans Blend via C#


Pour raliser cet exercice, il vous faudra dsarchiver MenuAnim_Dynamique.zip du dossier chap6 des exemples du livre. Vous pouvez ouvrir le projet dans Blend ou Visual Studio. Ce projet est trs simple, il contient plusieurs primitives Rectangle, mais seul le premier enfant de la grille est anim. Notre objectif va consister rcuprer lanimation gnre dans Blend par le designer interactif, puis la dupliquer dynamiquement afin de laffecter chaque Rectangle contenu dans la grille. Cloner dynamiquement un Storyboard nest malheureusement pas une opration simple raliser, ceci pour deux raisons. La premire est que la mthode MemberWise Clone hrite de Object est protge, donc inaccessible depuis lextrieur (de plus cette mthode nest pas satisfaisante car elle ne clone lobjet quen surface). La seconde raison est que la classe XamlWriter, utilise pour rcuprer la chane de caractres XAML de toute rfrence sous WPF, nest pas supporte par Silverlight et quelle est disponible uniquement au sein de WPF. Nous pourrions utiliser lAPI de rflexion qui permet de parcourir les types, mthodes, proprits, etc. Toutefois un tel code serait fastidieux et ne servirait pas notre propos. Nous allons donc commencer par rcuprer la chane de caractres correspondant au Storyboard. Il suffit de copier le code XAML gnr dans Blend, puis de le coller directement au sein du fichier C# dans le constructeur. Une fois cette tape ralise, supprimez toutes les proprits Sto

Chapitre 6

Animations

147

ryboard.TargetName="Rectangle1", les proprits BeginTime="00:00:00", ainsi que la proprit x:Name="Anim3D". Vous obtiendrez le rsultat ci-dessous:
<Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty= "(UIElement.Projection).(PlaneProjection.RotationY)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="650"/> <EasingDoubleKeyFrame KeyTime="00:00:01" Value="0"> <EasingDoubleKeyFrame.EasingFunction> <CubicEase/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty= "(UIElement.Opacity)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> <EasingDoubleKeyFrame KeyTime="00:00:01" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty= "(UIElement.Projection).(PlaneProjection.GlobalOffsetZ)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-700"/> <EasingDoubleKeyFrame KeyTime="00:00:01.5000000" Value="0"> <EasingDoubleKeyFrame.EasingFunction> <CubicEase/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty= "(FrameworkElement.Width)"> <EasingDoubleKeyFrame KeyTime="00:00:01" Value="51"/> <EasingDoubleKeyFrame KeyTime="00:00:01.5000000" Value="150"> <EasingDoubleKeyFrame.EasingFunction> <CubicEase/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> </Storyboard>

Visual Studio lve plusieurs erreurs, mais ce nest que temporaire. Il va nous falloir transformer le XAML en objet de type String. Cest la partie du code un peu rbarbative, mais cest une phase sensible car au moindre faux pas le compilateur lvera une erreur. Nous devons utiliser la classe StringBuilder pour concatner une chane de caractres. Concatner revient mettre plusieurs chanes de caractres la suite. Favoriser lutilisation de String Builder optimise grandement la mmoire alloue pour ce type dopration. Rfrencez lespace de noms System.Text via linstruction using. Nous allons parcourir tous les enfants de la grille LayoutRoot et crer un Storyboard pour chaque UIElement trouv:
//espace de noms ajouter using System.Windows.Markup; using System.Collections.Generic; using System.Text; //On cr un dictionnaire pour stocker chaque animation cre Dictionary<UIElement, Storyboard> DicoElementsSB = new Dictionary<UIElement, Storyboard>(); void MainPage_Loaded(object sender, RoutedEventArgs e) { CreateStoryboard();

148

Partie II

Interactivit et cration graphique

} private void CreateStoryboard() { foreach (UIElement Ui in LayoutRoot.Children) { //on rcupre l'index de chaque objet dans la liste d'enfants int i = LayoutRoot.Children.IndexOf(Ui); } }

Notre objectif est dinjecter dynamiquement la chane de caractres XAML. Vous allez maintenant placer le code XAML rcupr au sein de la boucle foreach, puis utiliser la classe String Builder. Toutefois, pour que cette opration soit possible, nous devons respecter certaines rgles:

Vous devez toujours ajouter les espaces de noms XAML llment le plus lev dans la hirarchie. Dans notre cas, il faudra donc ajouter les espaces de noms au nud lment Sto ryboard. La proprit Name doit toujours prendre une valeur diffrente si vous la dfinissez. Cependant, il nest pas utile de conserver et daffecter cette proprit. Pour transformer le XAML en chane de caractres, il faut remplacer les apostrophes doubles de chaque proprit par de simples apostrophes, puis encadrer la totalit de la ligne par deux apostrophes doubles. Cela vous vitera les erreurs. Par exemple, KeyTime="00:00:00" deviendra KeyTime='00:00:00'.

Voici le dbut de ce que doit tre votre code:


foreach (UIElement Ui in LayoutRoot.Children) { int i = LayoutRoot.Children.IndexOf(Ui); StringBuilder sb = new StringBuilder("<Storyboard x:Name='Anim3D"+ i +"' xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>"); sb.AppendLine("<DoubleAnimationUsingKeyFrames BeginTime='00:00:00." + i + "' Storyboard.TargetProperty = '(UIElement.Projection). (PlaneProjection.RotationY)'>"); sb.AppendLine("<EasingDoubleKeyFrame KeyTime='00:00:00' Value='650'/>"); }

La mthode AppendLine permet de concatner chaque nouvelle ligne XAML. Pour raliser cette opration rapidement, vous pouvez utiliser loutil de remplacement de texte de Visual Studio ou de Blend. Une fois fait, il faut encore transformer les chanes de caractres cres chaque itration de la boucle en instance de type Story board. Lespace de noms System.Windows.Markup que nous avons rfrenc contient la classe XamlReader qui permet de transformer la chane de caractres en instance:
foreach (UIElement Ui in LayoutRoot.Children) { int i = LayoutRoot.Children.IndexOf(Ui); StringBuilder sb = new StringBuilder("<Storyboard x:Name='Anim3D"+ i +"' xmlns='http://schemas.microsoft.com/winfx/2006/xaml/

Chapitre 6

Animations

149

presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/ xaml'>"); sb.AppendLine("<DoubleAnimationUsingKeyFrames BeginTime='00:00:00." + i + "' Storyboard.TargetProperty = '(UIElement.Projection). (PlaneProjection.RotationY)'>"); sb.AppendLine("<EasingDoubleKeyFrame KeyTime='00:00:00' Value='650'/>"); sb.AppendLine("</Storyboard>"); //on transforme la chane de caractres cre //en une instance de Storyboard Storyboard NewClonedStoryboard = (Storyboard) XamlReader.Load (sb.ToString()); //on dfinit un dcalage de temps permettant aux //objets Storyboard de se lancer les uns aprs les autres NewClonedStoryboard.BeginTime = TimeSpan.FromMilliseconds(i * 200); //on dfinit la nouvelle cible animer sur le Storyboard //lui-mme au lieu de chaque DoubleAnimation Storyboard.SetTarget(NewClonedStoryboard, Ui); //on ajoute le Storyboard cr au sein d'un dictionnaire, //avec comme cl la rfrence de l'instance anime DicoElementsSB.Add(Ui, NewClonedStoryboard); }

Compilez lapplication. Si ce stade vous navez aucune erreur leve par le compilateur, cest que tout sest bien pass. Dans le cas contraire, lerreur provient dans 80% des cas de la concatnation via la mthode AppendLine ou de loubli des espaces de noms comme attribut de la balise <Storyboard xmlns="" xmlns:x="">. Comme vous le constatez, il est utile de conserver un accs aux instances Storyboard cres. La meilleure manire dy avoir accs est dutiliser un dictionnaire. Vous pourriez galement utiliser la proprit Resource de votre application. Toutefois celle-ci peut contenir bien dautres ressources que des animations. Ce choix vous appartient. Dans tous les cas, nous avons besoin de stocker les occurrences de Storyboard pour les rutiliser plus tard. Nous allons maintenant dclencher les animations lors de chaque clic de la souris sur la grille principale. Au sein de Blend, dans le panneau des vnements entrez la chane DeclencheAnim pour lvnement MouseLeftButtonDown. Dans le code C#, il suffit de parcourir le dictionnaire et dappeler la mthode Begin pour chaque animation contenue:
private void DeclencheAnim(object sender, MouseButtonEventArgs e) { foreach (Storyboard sb in DicoElementsSB.Values) { sb.Begin(); } }

Cet exercice permet de comprendre comment les dveloppeurs et les designers interactifs peuvent travailler les avec les autres sans se gner et tout en conservant le travail de chacun. Vous trouverez lexercice finalis dans larchive MenuAnim_Dynamique_Final.zip du dossier chap6 des exemples de louvrage.

150

Partie II

Interactivit et cration graphique

6.5 Les transformations relatives


Dans cette section, nous allons aborder les transformations relatives de manire plus approfondie. Vous remarquez que lorsque vous modifiez la position dun objet au sein dune animation, Blend privilgie lutilisation des transformations relatives. Nous aurions tendance penser quau sein dun composant Canvas, les proprits Canvas.Left et Canvas.Top seraient employes pour animer la position, mais il nen est rien. L encore, Blend choisira danimer X et Y du nud Trans lateTransform plutt que dinterpoler les proprits attaches par le conteneur (Canvas.Left et Canvas.Top). Les transformations relatives nous permettent dchapper aux contraintes de mise en forme pose par le contexte conteneur. Pour cette raison, Blend les choisit en priorit. Il est donc pratique de savoir crer des instances de ce type dynamiquement via C#. Une autre raison plus terre terre nous invite gnrer ce type de nud. Lorsque vous avez dupliqu la balle dans lexercice prcdent, celle-ci possdait dj un nud RenderTransform.Transform Group, qui a donc t transmis aux copies de la balle. De ce fait, lanimation de rebond pouvait cibler les balles copies. Toutefois, si laffectation de cette proprit avait manqu, Blend aurait lev une erreur daccs la compilation. Dans certains cas, il vous faudra donc ajouter ce nud dynamiquement.

6.5.1 Principes
Il existe quatre types de transformations relatives (voir Figure 6.31).
Figure6.31
Les 4 types de transformations relatives.

Du point de vue dun dveloppeur, il est possible daffecter de diffrentes manires des transformations relatives aux instances. La premire consiste simplement affecter la proprit dune transformation de son choix:
TranslateTransform Tt = new TranslateTransform(); Tt.X = 200; MonFrameworkElement.RenderTransform = Tt; //dcale MonFrameworkElement de 200 pixels vers la droite ScaleTransform St = new ScaleTransform(); St.ScaleX = 2; MonFrameworkElement.RenderTransform = St; //crase l'ancienne affectation de translation //Multiplie par 2 la largeur de MonFrameworkElement

Chapitre 6

Animations

151

La deuxime est daffecter plusieurs transformations relatives au mme objet en les groupant dans une instance de type TransformGroup:
TranslateTransform Tt = new TranslateTransform(); Tt.X = 200; ScaleTransform St = new ScaleTransform(); St.ScaleX = 2; TransformGroup Tg = new TransformGroup(); Tg.Children.Add(Tt); Tg.Children.Add(St); MonFrameworkElement.RenderTransform = Tg; //Affecte les deux transformations sans que l'une crase l'autre

Pour un designer, cela est lgrement diffrent car Blend gnre par dfaut un nud XAML de type TransformGroup qui contient les quatre types de transformation:
<UIElement.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </UIElement.RenderTransform>

Ds lors, pour des raisons de communication et dhomognit, le dveloppeur doit, dans certains cas, cibler ou affecter les transformations contenues dans un nud XAML TransformGroup. Cela pour la bonne raison que le nud XAML est utilis par le designer interactif au sein de Blend.

6.5.2 Tester la prsence dune instance TransformGroup


Avant dajouter ou de cibler un nud de type TransformGroup, la premire chose faire est de tester la proprit RenderTransform. Quelle que soit linstance de UIElement, cette proprit nest pas nulle car sa valeur correspond la matrice de transformation de lobjet par dfaut (Ma trixTransform). Toutefois, vous pouvez tester si elle contient une instance de type Transfor mGroup. Si cest le cas, cela signifie que la proprit RenderTransform de linstance a t modifie sous Blend ou quelle a t affecte par code. Vous devrez si possible viter tout crasement des transformations modifies par le graphiste dans Blend. Crez un nouveau projet dans Blend et deux instances de Rectangle dans LayoutRoot. Nommez lun R et lautre Rt. Sur le Rectangle Rt, modifiez les transformations relatives via le panneau des proprits. Ouvrez le projet sous Visual Studio. Nous allons utiliser cet environnement pour tester les transformations relatives de chaque Rectangle:
public MainPage() { InitializeComponent(); bool Rb = R.RenderTransform is TransformGroup; bool Rtb = Rt.RenderTransform is TransformGroup; }

152

Partie II

Interactivit et cration graphique

Ce code ne suffit pas, le mieux serait de poser un point darrt pour vrifier quelles valeurs prennent Rb et Rtb. Cliquez gauche de la ligne contenant la dclaration de Rtb (voir Figure 6.32).
Figure6.32
Poser un point darrt dans Visual Studio.

Lancez la compilation. Elle est interrompue lorsque la mthode MainPage_Loaded est dclenche. Pour connatre la valeur de Rb et de Rtb, il vous suffit de survoler loprateur is qui value le type. La variable Rtb nest pas encore affecte cet instant, cest pourquoi le survol de la variable Rtb renvoie false. Visual Studio affiche la valeur sous chaque variable (Figure 6.33).
Figure6.33
Afficher les valeurs lexcution grce au dbogueur.

Non seulement Visual Studio affiche la valeur au survol, mais il renseigne la valeur des variables accessibles depuis la mthode MainPage_Loaded au sein du panneau Locals. Pour tester une rfrence ou une valeur, vous pouvez galement utiliser la fentre de sortie de Visual Studio. La classe statique Debug possde la mthode WriteLine permettant dcrire en fentre de sortie. Elle se trouve dans lespace de noms System.Diagnostics. Voici un exemple dutilisation:
public MainPage() { InitializeComponent(); bool Rb = R.RenderTransform is TransformGroup; bool Rtb = Rt.RenderTransform is TransformGroup; Debug.WriteLine(" TransformGroup de R :: {0} - TransformGroup de Rt :: {1}", Rb, Rtb); }

Le raccourci F5 sous Visual Studio lance automatiquement le dbogueur. Tant que celui- ci est excut, le code logique ou dclaratif sous Visual Studio nest pas modifiable. Dsactivez le dbogueur sous Visual Studio pour y accder de nouveau via le raccourci Maj+F5. Cet exercice est disponible dans TestRenderTransform.zip du dossier chap6.

Chapitre 6

Animations

153

6.5.3 Affecter la proprit RenderTransform


Maintenant que nous savons tester la prsence du nud lment TransformGroup, nous allons le crer de toute pice lorsquil est absent. Pour des raisons de standard dcriture XAML, nous allons le crer de la mme manire que le ferait Blend. Lexemple de code ci-dessous gre entirement lanimation, la cration des objets graphiques et des transformations relatives:
public partial class MainPage : UserControl { Storyboard Sb; DoubleAnimation DaX; DoubleAnimation DaY; public MainPage() { // Required to initialize variables InitializeComponent(); Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e) { Ellipse Balle = CreateBalle(); Balle = (Ellipse)CreateRenderTransformNode(Balle); CreateAnimationBalle(Balle); LayoutRoot.MouseLeftButtonUp += OnLayoutClick; } private Ellipse CreateBalle() { Ellipse MaBalle = new Ellipse(); MaBalle.Width = 100; MaBalle.Height = 100; MaBalle.HorizontalAlignment = HorizontalAlignment.Left; MaBalle.VerticalAlignment = VerticalAlignment.Top; MaBalle.Fill = new SolidColorBrush(Colors.Gray); LayoutRoot.Children.Add(MaBalle); return MaBalle; } private UIElement CreateRenderTransformNode(UIElement balle) { //l'objectif est de standardiser l'criture du nud //RenderTransform. Pour cette raison, nous le crons //de la mme manire que Blend if ( (balle.RenderTransform is TransformGroup)) { TransformGroup Tg = new TransformGroup(); Tg.Children.Add(new ScaleTransform()); Tg.Children.Add(new SkewTransform()); Tg.Children.Add(new RotateTransform()); Tg.Children.Add(new TranslateTransform()); balle.RenderTransform = Tg; } return balle; }

154

Partie II

Interactivit et cration graphique

private void CreateAnimationBalle(Ellipse balle) { Sb = new Storyboard(); DaX = new DoubleAnimation(); DaY = new DoubleAnimation(); DaX.Duration = TimeSpan.FromSeconds(0.6); DaY.Duration = TimeSpan.FromSeconds(0.6); DaX.EasingFunction = new ElasticEase(); DaY.EasingFunction = new ElasticEase(); Storyboard.SetTarget(DaX, balle); Storyboard.SetTarget(DaY, balle); Storyboard.SetTargetProperty(DaX, new PropertyPath("(UIElement. RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.X)") ); Storyboard.SetTargetProperty(DaY, new PropertyPath("(UIElement. RenderTransform).(TransformGroup.Children)[3]. (TranslateTransform.Y)") ); Sb.Children.Add(DaX); Sb.Children.Add(DaY); } void OnLayoutClick (object sender, MouseButtonEventArgs e) { // la balle se dplacera lorsque vous cliquerez //n'importe o au sein du conteneur LayoutRoot DaX.To = e.GetPosition(null).X - 50 ; DaY.To = e.GetPosition(null).Y - 50 ; Sb.Begin(); }

Compilez votre application. Lorsque vous cliquez nimporte o sur la scne, lanimation est mise Ecran_ jour et la balle se dplace lendroit cliqu. Vous trouverez cet exercice ici : chap6/plein maquetteAnimee_1.zip. Crer un nud lment RenderTransform peut se rvler assez fastidieux. De plus, son chemin daccs nest pas forcment simple renseigner. cette fin, vous pouvez soit vous aider de Blend, soit utiliser la bibliothque ProxyRenderTransform. Nous allons voir son utilisation dans la prochaine section.

6.5.4 La bibliothque ProxyRenderTransform


6.5.4.1 Principes et utilisation simple
Assurez-vous davoir tlcharg la bibliothque au pralable. Elle est votre disposition sur le portail CodePlex, ladresse : http://proxyrd.codeplex.com. Puis, rfrencez-la au sein dun nouveau projet nomm UsingProxyRD (voir Figure 6.34).

Chapitre 6

Animations

155

Figure6.34
Rfrencer la bibliothque ProxyRenderTransform.

Ensuite, importez lespace de noms au sein de votre code:


using ProxyRenderTransform;

Cette bibliothque fournit un certain nombre davantages. Elle peut ajouter dynamiquement un groupe de transformations relatives aux objets qui nen possdent pas. Elle permet galement de rcuprer ou daffecter la valeur de chaque transformation via lutilisation de mthodes dextension. Vous pourrez par exemple crire:
MonUIElement.SetScaleX(2); //ou encore MonUIElement.SetX(50);

Ces mthodes sont accessibles directement grce lIntelliSense que vous fournit Visual Studio (voir Figure 6.35).
Figure6.35
IntelliSense de la bibliothque ProxyRenderTransform dans Visual Studio.

Comme vous pouvez le voir, cette bibliothque donne galement accs aux projections3D (voir Chapitre 10). Si vous souhaitez rcuprer la rfrence dun nud de transformation contenu dans le groupe gnr par dfaut sous Blend, vous pouvez appelez les mthodes GetRotateNode, GetScaleNode, etc. Pour finir, la bibliothque vous permet de rcuprer les chemins daccs aux diffrents nuds en renvoyant des objets typs Property Path (voir Figure 6.36).

156

Partie II

Interactivit et cration graphique

Figure6.36
Rcupration des chemins daccs aux transformations.

Vous pouvez dsormais crire:


Storyboard.SetTargetProperty(DaX, ProxyRD._TRANSLATE_X_PATH );

Cette criture est non seulement simple, mais galement facile daccs via lIntelliSense de Visual Studio. LIntelliSense de Blend ne donne pas accs dynamiquement aux mthodes dextension.

6.5.4.2 Animer avec le mtronome DispatcherTimer


Nous allons faire une animation trs simple pour illustrer son utilisation. Dans un nouveau projet nomm AnimProg, ajoutez la bibliothque ProxyRenderTransform, puis crez un composant Rectangle au sein de la grille principale LayoutRoot. Placez-le en haut gauche de la grille et nommez-le Suiveur. Dans le panneau des vnements de la grille principale, entrez GetMouse Pos pour lvnement MouseMove. Vous allez utiliser la classe DispatcherTimer pour modifier la position du rectangle selon un intervalle de temps. Voici le code comment permettant au rectangle de suivre constamment la souris avec un lger effet de ralenti:
using ProxyRenderTransform; using System.Windows.Threading; public partial class MainPage : UserControl { //la destination du rectangle mis jour lors de l'vnement Tick //qui se dclenche selon lintervalle de temps spcifi double NewDestX=0; double NewDestY=0; //Stocke les coordonnes actuelles de la souris double MouseX; double MouseY; public MainPage() { // Required to initialize variables InitializeComponent(); DispatcherTimer dt = new DispatcherTimer(); dt.Interval = TimeSpan.FromMilliseconds(10); dt.Tick += new EventHandler(dt_Tick);

Chapitre 6

Animations

157

dt.Start(); } void dt_Tick(object sender, EventArgs e) { //ces expressions permettent de crer l'effet de dplacement ralenti //0.1 correspond au facteur de ralenti, plus ce facteur est faible //plus le ralentissement s'accentue NewDestX += ((MouseX - Suiveur.Width/2) - (double)Suiveur.GetX()) * 0.1; NewDestY += ((MouseY - Suiveur.Height/2)- (double)Suiveur.GetY()) * 0.1; Suiveur.SetX(NewDestX); Suiveur.SetY(NewDestY); } //lors du dplacement de la souris, on rcupre sa position private void GetMousePos(object sender, MouseEventArgs e) { MouseX = e.GetPosition(null).X; MouseY = e.GetPosition(null).Y; } }

Lanimation est trs fluide et ne repose pas sur la classe Storyboard. Vous pouvez pratiquement raliser nimporte quel type danimation grce la classe DispatcherTimer. Dans tous les cas, lanimation mme crite avec des nuds lments Storyboard est base en interne sur ce type de fonctionnement.
NOTE INFO

Il nest pas rellement possible de rcuprer les coordonnes de la souris en dehors dun gestionnaire dvnements pour la bonne raison que la classe "Mouse" nexiste pas. Dans le cas contraire, nous naurions pas besoin dcouter lvnement MouseMove et notre code serait plus optimis.

Vous trouverez le projet dans larchive AnimProg.zip du dossier chap6 des exemples. Nous allons maintenant animer avec la classe Math. Cette dernire centralise de nombreuses mthodes dont certaines sont lies la trigonomtrie. Cette discipline est assez intressante car elle permet de coder des animations complexes en quelques lignes seulement. Nous allons utiliser deux mthodes, Math.Sin et Math.Cos, pour gnrer un mouvement circulaire. Crez un nouveau projet et nommez-le AnimationCirculaire_Math. Rfrencez la bibliothque ProxyRender Transform. Crez ensuite deux instances de type Ellipse. La premire, nomme Axe, symbolise laxe de rotation. La deuxime, appele Satellite, va subir une rotation autour de laxe. Elles doivent toutes deux tre alignes horizontalement et verticalement au centre de la grille. Voici le code permettant de gnrer une rotation via DispatcherTimer :
//Vitesse angulaire exprime en radians //elle dpend directement de l'intervalle de l'objet DispatcherTimer double vitesseAngulaire = .1; //angle initial double angle = 0; //exprim en radian //Le rayon de rotation double rayon = 100; //l'axe de rotation Point CentreRotation; DispatcherTimer Dt = new DispatcherTimer();

158

Partie II

Interactivit et cration graphique

public MainPage() { InitializeComponent(); Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e) { //Lorsque l'application est charge, on rcupre les coordonnes //de l'objet servant d'axe de rotation CentreRotation = new Point((double)Axe.GetX(), (double)Axe.GetY()); Dt.Interval = TimeSpan.FromMilliseconds(30); Dt.Tick += new EventHandler(OnTick); Dt.Start(); } void OnTick(object sender, EventArgs e) { //On rcupre les nouvelles coordonnes du satellite //en fonction de l'angle, du rayon et du centre de la rotation Satellite.SetX(CentreRotation.X + Math.Sin(angle) * rayon); Satellite.SetY(CentreRotation.Y + Math.Cos(angle) * rayon); // chaque appel de la mthode, on redfinit l'angle //en lui ajoutant la vitesse angulaire angle += vitesseAngulaire; }

Cet exercice est disponible dans larchive AnimationCirculaire_Math.zip, du dossier chap6 des exemples de cet ouvrage.

6.5.5 Effets antagonistes et complmentaires


Ce type deffet est trs utile en matire de graphisme car il permet de crer des visuels la fois faciles mettre jour et impressionnants. Ces effets reposent essentiellement sur limbrication, lordre hirarchique des composants, ainsi que sur les transformations relatives. Nous allons simuler de la 3D sans utiliser la projection qui est disponible depuis la version 3 de Silverlight. La projection 3D est pratique, mais elle offre le dsavantage dun rendu parfois pixlis (voir Chapitre10). Nous naurons pas ce problme puisque nous utiliserons le mode vectoriel 2D uniquement. Crez un nouveau projet nomm DisqueAnim. Instanciez une ellipse de 200 pixels de largeur par 200 pixels de hauteur avec un fond blanc et une bordure de couleur noir. Faites-en une deuxime mais de 100 100 pixels. Slectionnez-les, puis via le menu dalignement centrez-les verticalement et horizontalement (voir Figure 6.37).
Figure6.37
Les deux instances de Ellipse alignes.

Chapitre 6

Animations

159

Vous allez soustraire la plus petite la plus grande afin de percer cette dernire. Pour cela, vous devez utiliser le menu Combiner accessible via un clic droit ou par le menu Objet. Slectionnez les deux instances dEllipse puis, dans le menu Combiner, choisissez lopration Soustraire. Lordre de slection compte. Vous devriez rcuprer un trac vectoriel de type Path ressemblant un tore (voir Figure 6.38).
Figure6.38
Opration de soustraction sur les Ellipses.

Crez un triangle droit grce loutil Plume, celui-ci doit partir du centre du tore vers la droite (voir Figure 6.39).
Figure6.39
Cration dun triangle droit via loutil Plume.

Slectionnez le triangle, puis le tore, et rptez lopration de soustraction. Nous allons maintenant animer le trac obtenu avec une rotation. Crez une nouvelle animation nomme Anim Rotation, puis ouvrez le panneau des transformations relatives. la seconde0, crez une cl danimation avec une rotation de 0 degr. Positionnez la tte de lecture la seconde 2, puis saisissez une rotation de 360 degrs. Slectionnez le Storyboard, pour cela cliquez sur son nom au-dessus de larbre visuel. Au sein du panneau des proprits, dans le champ RepeatBehavior, slectionnez la valeur Forever. Lanimation de rotation se rptera ainsi indfiniment (voir Figure 6.40).
Figure6.40
Lecture dun Storyboard en boucle via la proprit RepeatBehavior.

160

Partie II

Interactivit et cration graphique

Slectionnez la grille principale, dans le panneau des vnements, entrez OnLoaded pour Loaded. Au sein du code C#, dclenchez lanimation via la mthode Begin:
private void OnLoaded(object sender, RoutedEventArgs e) { AnimRotation.Begin(); }

Le disque est maintenant anim ds le chargement de lapplication. Vous allez crer un effet antagoniste. Pour cela, groupez le disque au sein dun Canvas. Slectionnez ce dernier, puis au sein de longlet des transformations relatives, entrez la valeur 0,25 pour lchelle ScaleY. Recompilez ; cette fois, le disque subit toujours la rotation, mais la totalit de cette dernire est aplatie, simulant un effet de perspective. Si vous aviez modifi lchelle directement au sein du disque, vous nauriez pas eu ce type de rsultat car vous auriez aplati le disque et non linterpolation elle-mme (voir Figures 6.41 et 6.42). Ce nest quun simple exemple et vous pouvez imaginer un grand nombre dutilisations diffrentes de ce concept. Vous trouverez le projet final, AnimProg.zip, dans le dossier chap6 des exemples du livre.
Figure6.41
Modification de lchelle directement sur le trac.

Figure6.42
Effet complmentaire suite la modification de lchelle sur le conteneur Canvas.

6.6 Animer des particules


Si un type danimation passe pour tre rbarbatif et difficile auprs des animateurs, il sagit bien de lanimation des particules. Aucun outil ddi nest prsent au sein de Blend cette fin. De plus, une particule possde des comportements soit alatoires soit dicts par des ensembles complexes. Par exemple, la poussire, la pluie, les oiseaux et mme les humains peuvent tre considrs comme des particules ds lors quon les examine de loin. Ainsi, un animateur traditionnel, dont le mtier est avant tout danimer un nombre restreint dobjets, est dpass par la somme colossale de travail raliser pour ce genre de visuel. Toutefois, cela nest pas inaccessible : les mouvements de foule du film Akira ont t raliss par des dizaines danimateurs et sans dveloppement informatique. Cela reste un cas particulier. Dans le film danimation du Bossu de Notre Dame, la foule regroupe autour de Notre Dame est

Chapitre 6

Animations

161

quant elle gnre par ordinateur. Lide est dassocier diffrents mouvements, comportements, couleurs et formes chaque individu prsent sur la place. Cela confre au dessin anim beaucoup de ralisme, mais ne requiert pas pour autant une arme danimateurs. Par la suite, un algorithme informatique associe alatoirement chaque composant constituant un individu, afin de lui donner un caractre unique au sein de la foule. Cest exactement ce que nous allons faire dans cette section pour donner lillusion de la diversit.

6.6.1 Exemples dun fond sous-marin


Tlchargez le projet chap6/BubbleParticule.zip. Dcompressez le fichier, puis chargez le projet dans Expression Blend. Vous avez un aperu du visuel final de cet exercice la Figure 6.43.
Figure6.43
Visuel du projet finalis.

6.6.1.1 Mise en place


Au sein du panneau des projets, vous constatez la prsence dun composant personnalis nomm Bulle. Vous navez pas besoin de savoir pour linstant comment celui-ci a t ralis (vous pourrez vous en faire une ide au Chapitre 12). Un composant personnalis peut tre instanci de la mme manire que nimporte quel autre via le code C# ou la bibliothque de composants accessible dans Blend. La grille principale du projet contient deux composants dont seul le premier nous intresse: le composant Canvas nomm Emetteur. Cest ce composant qui va contenir nos particules. Celles-ci seront en fait des bulles qui remonteront vers la surface en zigzagant. Pour dplacer les bulles, nous nutiliserons pas les Render Transform car cela engendrerait la cration dune transformation relative de type Translate Transform et ajouterait une charge processeur supplmentaire.
NOTE INFO

Il est parfois utile dviter lutilisation des nuds RenderTransform. Vous pourrez vous en passer dans deux cas prcis : lorsque vous souhaiterez dplacer dans lespace un objet vectoriel ou le redimensionner. Les oprations de rotation (RotateTransform) ou dinclinaison (Skew Transform) ne sont en revanche pas ralisables sans lutilisation des transformations relatives ou dune matrice de transformation. Pour dplacer simplement un contrle, il vous suffit dutiliser le composant Canvas. Ce composant permet un placement des objets sans contrainte de repositionnement. Cela est trs pratique si vous souhaitez vous carter au maximum dune mise en forme traditionnelle.

162

Partie II

Interactivit et cration graphique

Pour redimensionner un composant sans sa proprit RenderTransform, il vous faut utiliser le composant ViewBox. Vous trouverez ce contrle dans la bibliothque Silverlight Toolkit ladresse : http://www.codeplex.com/Silverlight. Lorsque vous changez la largeur (Width) et la hauteur (Height) de ce conteneur enfant unique, il redimensionne son contenu comme si celuici avait eu sa proprit RenderTransform affecte dune instance ScaleTransform modifie.

Vous constatez galement la prsence dune animation si vous ouvrez la liste des objets de type Storyboard dans Blend. Vous pouvez modifier cette liste loisir pour donner plus de ralisme la scne. Ouvrez le fichier MainPage.xaml.cs. Vous constatez que lon commence par dmarrer lanimation des rais de lumire. Vous remarquez galement que celle-ci est cinq fois moins rapide que laperu dans Blend car sa proprit SpeedRatio est affecte 0.2:
void MainPage_Loaded(object sender, RoutedEventArgs e) { //initialisation de l'animation des rais de lumire RaiesLumieres.SpeedRatio = 0.2; RaiesLumieres.Begin(); }

Nous allons maintenant crer des instances du composant personnalis Bulle selon un laps de temps.

6.6.1.2 Crer les particules


Il faudra limiter le nombre de particules. Pour cela, il nous suffit de dfinir une constante reprsentant le nombre maximum de bulles gnres:
public partial class MainPage : UserControl { //On dfinit un nombre de bulles maximum private const int NOMBRE_BULLE = 50; }

Chaque bulle de notre visuel est conue un instant diffrent. Pour gnrer les bulles, le mieux est dutiliser la classe DispatcherTimer contenue dans lespace de noms System.Windows. Threading. Nous pouvons ajouter une instance de cette classe comme membre de la classe principale, puis la configurer dans notre mthode Loaded:
public partial class MainPage : UserControl { //On dfinit un nombre de bulles maximum private const int NOMBRE_BULLE = 50; //on cre une instance de l'objet DispactherTimer //qui va nous servir crer des bulles selon un intervalle de temps DispatcherTimer monTimer = new DispatcherTimer(); public MainPage() { InitializeComponent(); Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e)

Chapitre 6

Animations

163

{ //initialisation de l'animation des rais de lumire RaiesLumieres.SpeedRatio = 0.2; RaiesLumieres.Begin(); //Intervalle de temps entre la cration de chaque bulle monTimer.Interval = TimeSpan.FromMilliseconds(200); //Souscription de l'couteur monTimer_Tick l'vnement Tick monTimer.Tick += new EventHandler(monTimer_Tick); //Dmarrage du mtronome monTimer.Start();

Il nous faut un objet de type Random. Celui-ci possde plusieurs mthodes capables de calculer un nombre alatoire. Cest donc grce lui que nous positionnerons les bulles alatoirement. Sous la dclaration de linstance DispatcherTimer, crez une instance de lobjet Random. En le dclarant comme membre de classe, nous le rendons accessible depuis nimporte quelle mthode de la classe MainPage:
public partial class MainPage : UserControl { //On dfinit un nombre de bulles maximum private const int NOMBRE_BULLE = 50; //on cre une instance de l'objet DispactherTimer //Il va nous servir crer des bulles selon un intervalle de temps DispatcherTimer monTimer = new DispatcherTimer(); //On initialise une instance Random dont on va se servir //pour grer les mouvements alatoires private Random rnd = new Random();

Il ne nous reste plus qu instancier puis positionner alatoirement les bulles au sein de la mthode monTimer_Tick. Chacune des bulles sera un enfant du Canvas Emetteur.
void monTimer_Tick(object sender, EventArgs e) { //On commence par vrifier que l'on na pas atteint le nombre maximum //de bulles gnres. if (Emetteur.Children.Count==NOMBRE_BULLE) { //Si c'est le cas, on arrte le mtronome monTimer.Stop(); //et on sort de la mthode return; } //dans le cas contraire, on cre une nouvelle bulle Bulle MaBulle = new Bulle(); //Pour donner l'impression de la diversit //on affecte la largeur et la hauteur de la bulle avec //une valeur alatoire entre 10 et 20 MaBulle.Width = MaBulle.Height = rnd.Next(10, 20); //on modifie l'opacit par dfaut alatoirement entre 0.2 et 0.7

164

Partie II

Interactivit et cration graphique

//soit entre 20 % et 70 % MaBulle.Opacity = (rnd.NextDouble()*0.5) + 0.2D; //on cre deux valeurs alatoires double PosX = rnd.NextDouble() * Emetteur.ActualWidth; double PosY = rnd.NextDouble() * Emetteur.ActualHeight; //La premire est affecte la proprit Canvas.Left Canvas.SetLeft(MaBulle, PosX); //la seconde la proprit Canvas.Top de chaque bulle Canvas.SetTop(MaBulle, PosY); //On ajoute la bulle cre comme enfant du Canvas Emetteur Emetteur.Children.Add(MaBulle); //Pour finir, on appelle la mthode qui va crer une animation //propre la bulle cre CreerAnimationAleatoire(MaBulle); }

Nous allons voir en dtail certaines parties de ce code. La premire concerne laffectation de la hauteur et de la largeur de chaque objet Bulle. La mthode Next de lobjet Random renvoie des entiers. Lorsque vous passez deux arguments, vous demandez en fait un entier alatoire dans une plage de valeurs. Les proprits Width et Height tant type Double, nous procdons ainsi un transtypage implicite. La valeur entire rcupre est convertie en type Double. Sur cette ligne de code, nous effectuons galement une triple galit. Cela nous permet davoir des dimensions dont le rapport initial est conserv. Concernant lopacit, elle est obtenue grce la mthode Next Double de lobjet Random. Cette mthode renvoie un nombre de type Double alatoire situ entre 0 et1. Multiplier le retour de cette mthode par 0.5 revient demander un nombre entre 0 et0.5. Ajouter 0.2D signifie que vous ajoutez la valeur 0.2 de type Double. Nous obtenons donc une opacit situe entre 0.2 et 0.7. Cela donne un effet de profondeur la scne. De la mme manire, pour positionner la bulle alatoirement, nous utilisons la mthode NextDouble. Les proprits ActualWidth et ActualHeight renvoient en fait la largeur et la hauteur mises jour selon les contraintes de redimensionnement du site. Ces valeurs sont rellement utiles lorsque votre conteneur possde des proprits Width et Height en mode Auto. Cest notre cas, la largeur (Width) du Canvas Emetteur est constamment mise jour selon le redimensionnement de la fentre de navigation. Les proprits Canvas.Left et Canvas.Top sont des proprits attaches aux objets contenus dans un conteneur de type Canvas. Cest le cas des instances de Bulle que nous crons. Il existe deux manires daffecter des proprits attaches, les voici dans le cas de Left et Top:
//1 - on utilise les mthodes statiques de la classe Canvas Canvas.SetTop(MonInstance, 100); //positionne mon instance 100 pixels du bord haut Canvas.SetLeft(MonInstance, 100); //positionne mon instance 100 pixels du bord gauche //2 - on utilise la mthode SetValue propre aux instances de // DependencyObject MonInstance.SetValue(Canvas.TopProperty, 100); //on obtient le mme rsultat MonInstance.SetValue(Canvas.LeftProperty, 100);

Chapitre 6

Animations

165

Compilez votre projet pour voir le rsultat. Les bulles sont cres alatoirement au sein du conteneur Canvas (Figure 6.44).
Figure6.44
Cration des bulles alatoirement dans le composant Emetteur.

6.6.2 Crer lanimation des bulles


Nous allons maintenant nous concentrer sur lanimation de chaque bulle. Le code sera centralis dans la mthode CreerAnimationAleatoire:
private void CreerAnimationAleatoire(Bulle maBulle) { //on commence par instancier une nouvelle ressource Storyboard Storyboard AnimBulle = new Storyboard(); }

Cette mthode reoit en paramtre la nouvelle bulle cre, puis lui affecte deux animations uniques. La premire animation cible laxe verticale Y reprsent par la proprit Canvas.Top de chaque Bulle. La seconde interpole la position des particules sur laxe X, dfini par la proprit Canvas.Left.

6.6.1.1 Animation verticale


Pour laxe vertical, cela est assez simple car lanimation gnre avec C# est semblable celle cre la section6.4.2.1. Pourtant elle diffre en plusieurs points. Tout dabord lanimation dbute partir de lendroit o la bulle a t cre alatoirement. Pour rcuprer la position dun objet au sein dun Canvas, il vous suffit dutiliser ses mthodes statiques:
Canvas.GetTop(MonObjetContenu); //renvoie la position de l'objet sur l'axe vertical si celui-ci //est contenu dans un Canvas Canvas.GetLeft(MonObjetContenu); //renvoie la position de l'objet sur l'axe horizontal si celui-ci est //contenu dans un Canvas //Dans les deux cas, il est inutile de prciser //la rfrence du conteneur car celui-ci est implicitement //le parent de l'instance MonObjetContenu

Une fois rcupre, nous pouvons affecter cette valeur la proprit From de notre animation. Nous dfinissons loppos de la hauteur de la page comme valeur de destination. La deuxime particularit de cette animation est quelle est joue en boucle. Ceci se fait en affectant la valeur Forever la proprit RepeatBehavior. Cette proprit est hrite de la classe abstraite Time

166

Partie II

Interactivit et cration graphique

Line. Concrtement, lorsquune bulle a termin son parcours, elle revient son point de dpart et rejoue son dplacement. Cela vite de gnrer constamment de nouvelles bulles et allge la charge processeur en rutilisant celles qui sont dj instancies:
//Cette animation se joue en boucle indfiniment sur l'axe vertical //Une fois arrive sa destination, la bulle recommence son trajet DaY.RepeatBehavior = RepeatBehavior.Forever;

La dernire particularit est de dfinir une dure alatoire pour chaque animation verticale via lobjet Random:
//L'animation durera entre 8 et 14 secondes maximum //grce l'utilisation d'une valeur alatoire DaY.Duration = TimeSpan.FromSeconds((rnd.NextDouble() * 6) + 8);

Voici le code complet gnrant cette animation:


//on cre une sous-squence d'animation DoubleAnimation DaY = new DoubleAnimation(); //Celle-ci cible l'axe Y grce la proprit Canvas.Top de chaque Bulle Storyboard.SetTargetProperty(DaY, new PropertyPath(Canvas.TopProperty)); //Cette seconde sous-squence cible galement l'instance maBulle Storyboard.SetTarget(DaY, maBulle); DaY.RepeatBehavior = RepeatBehavior.Forever; DaY.From = Canvas.GetTop(maBulle); DaY.To = -LayoutRoot.ActualHeight - 50; DaY.Duration = TimeSpan.FromSeconds((rnd.NextDouble() * 6) + 8);

Cette animation est assez simple, ce nest pas vraiment elle qui donnera son caractre lanimation car lobjet Random est trs peu utilis. Nous allons maintenant voir comment dplacer alatoirement chaque bulle sur laxe X.

6.6.1.2 Animation horizontale


Cette animation est un peu plus complique. Nous allons tout dabord essayer de comprendre linterpolation dont nous avons besoin. La bulle doit remonter lentement tout en zigzagant gauche et droite. Si elle possde une amplitude constante gauche et droite, nous aurons un mouvement trop mcanique et donc pas assez alatoire et chaotique. Il faut donc que celle-ci possde une amplitude diffrente lorsquelle va de droite gauche. Si lon additionne lanimation verticale une animation horizontale de gauche droite, on obtient aisment leffet recherch (voir Figure 6.45).

Chapitre 6

Animations

167

Figure6.45
Conjugaison de lanimation verticale et horizontale.

Notre objectif consiste crer des cls danimation qui prendront une valeur alatoire autour de la position dorigine (Canvas.Left) de la bulle. Nous avons besoin de crer une animation un peu plus complexe quune DoubleAnimation puisque celle-ci doit contenir des cls danimation. Comme vu la section6.1, il nous faut instancier une animation de type DoubleAnimationUsing KeyFrames. De plus, celle-ci doit tre un mouvement en boucle sans -coup. Il suffit de prciser quelle joue lenvers une fois arrive son terme, puis quelle joue en boucle. Voici le code permettant de la gnrer:
//On va crer une animation contenant des cls d'animation, lavantage //est de pouvoir gnrer une animation plus complexe et chaotique DoubleAnimationUsingKeyFrames DaX = new DoubleAnimationUsingKeyFrames(); //Cette seconde sous-squence cible la proprit Canvas.Left //pour dplacer les bulles sur l'axe X Storyboard.SetTargetProperty(DaX, new PropertyPath(Canvas.LeftProperty)); //Cette seconde sous-squence cible l'instance maBulle Storyboard.SetTarget(DaX, maBulle); //l'animation sur cet axe doit tre lue en boucle DaX.RepeatBehavior = RepeatBehavior.Forever; //Elle doit galement se jouer dans les deux sens DaX.AutoReverse = true; //on cre 5 cls d'animation avec une boucle for (int i = 0 ; i< 5; i++) { //Pour lisser le mouvement, on utilise une cl d'animation //de type acclration EasingDoubleKeyFrame dkx = new EasingDoubleKeyFrame(); //on dfinit donc un type de easing ExponentialEase Ee = new ExponentialEase(); //afin de lisser l'animation de droite gauche //l'acclration doit tre la mme au dpart comme // l'arrive de l'interpolation Ee.EasingMode = EasingMode.EaseInOut;

168

Partie II

Interactivit et cration graphique

//on affecte cette quation la proprit EasingFunction //de chaque cl dkx.EasingFunction = Ee; //Chaque cl doit possder une valeur qui affectera //la proprit Canvas.Left de la bulle dkx.Value = (double)Canvas.GetLeft(maBulle)+(rnd.NextDouble()*120) - 60; dkx.KeyTime = TimeSpan.FromMilliseconds((rnd.NextDouble()*1500) + ( (i+1) * 1500)); DaX.KeyFrames.Add(dkx); }

Comme vous le constatez, les animations utilisant des cls danimation possdent la proprit KeyFrames, qui est en fait une collection de DoubleKeyFrame. Chaque cl danimation fait donc partie dun type prcis dacclration. Vous aurez le choix entre Easing, reprsentant les quations dacclration, Spline pour les courbes dacclration (voir section 6.3.2.3), Linear permettant les interpolations linaires et Discrete pour des cls danimation sans interpolation. Lun des aspects importants consiste viter des mouvements trop saccads sur laxe horizontal. Pour cela, il faudra viter de positionner trop de cls dans lanimation horizontale. Il nous reste maintenant ajouter les deux animations linstance de Storyboard et la lire:
//On ajoute la sous-squence d'animation comme enfant du Storyboard AnimBulle.Children.Add(DaY); AnimBulle.Children.Add(DaX); //Puis on demande l'animation de se jouer AnimBulle.Begin();

Finalement, on pourrait encore crer deux animations de fondu pour lapparition progressive dune bulle et pour sa disparition. Il suffit pour cela de stocker la dure alatoire de lanimation verticale et de jouer une animation dopacit 2 secondes avant sa fin. Vous trouverez ce projet finalis dans larchive BubbleParticule_final.zip du dossier chap6 des exemples. Au Chapitre 7, nous reviendrons sur des notions danimation dans un contexte compltement diffrent puisquelles seront conues via le gestionnaire dtats visuels. Nous aborderons la cration de boutons personnaliss travers la conception dun lecteur vido simple.

7
Boutons personnaliss
Tout au long de ce chapitre, vous concevrez le design dun lecteur vido simple. travers cet exemple, vous allez crer des composants de type ButtonBase entirement personnaliss. Cest une premire tape facilitant lapprentissage des notions propres la personnalisation de tous types de contrles. Ainsi, vous connatrez la diffrence entre style et modle de composant, au sein de la plateforme Silverlight. Vous tudierez la liaison de modles qui assouplit et facilite la maintenance des styles et des modles tout en vitant leur multiplication. Dans un second temps, vous dcouvrirez le gestionnaire dtats visuels qui permet aux designers de grer les transitions aussi bien au sein des contrles quau niveau de lapplication elle-mme. Pour finir, vous apprendrez crer un bouton interrupteur deux tats et utiliserez le systme dagencement fluide pour faciliter les transitions entre tats.

7.1 Crer un lecteur vido


Nous allons concevoir le lecteur vido correspondant la Figure 7.1. Dans un premier temps lide est de mettre en forme ce projet d'un point de vue design.
Figure7.1
Lecteur vido finalis.

170

Partie II

Interactivit et cration graphique

7.1.1 Mettre en place le projet


Afin de simplifier les oprations, vous pouvez tlcharger le projet du dossier : chap7/Player Video.zip. Lapplication se redimensionne automatiquement en fonction du navigateur. Vous trouverez plusieurs objets, dans des grilles nommes, rpartis dans larbre visuel. Il s'agit en ralit d'une base visuelle pour les futurs contrles du lecteur (voir Figure7.2).
Figure7.2
Arbre visuel du projet PlayerVideo.

Comme vous le constatez, le lecteur vido est centralis dans un Canvas. Le contrle Media Element contenant le fichier vido n'est pas encore prsent (nous ltudierons au Chapitre13). Cela est assez logique car il ne sera pas redimensionn par lutilisateur. De plus, lagencement de ses composants est facilit par le placement libre que propose ce type de conteneur. Le premier de ses enfants, nomm TimeLineProgress, permettra lutilisateur de dplacer la tte de lecture un instant prcis. Le second, Download Progress, est un trac qui affichera ltat de tlchargement des vidos en cours de lecture. Les troisime et quatrime enfants, correspondants LargeColorRing et SmallColorRing, sont des indicateurs de couleur recouvrant pour linstant compltement les prcdents. Lorsquun des boutons sera survol, ces deux disques changeront de couleur. Au centre du lecteur, un interrupteur nomm PlayPause permettra de lire la vido ou de la mettre en pause et sera de type ToggleButton. Il affichera alternativement licne de lecture ou licne de pause. Nous aborderons son aspect visuel plus tard au sein de ce chapitre. Juste en dessous de linterrupteur, un trac nomm Background ainsi quune grille (Grid), IconeForward, constitueront notre bouton davance rapide. Les trois derniers enfants du Canvas sont en fait les icnes que nous utiliserons pour les prochains boutons.

7.1.2 Insrer une image darrire-plan


Avant de crer les boutons, nous allons afficher une image larrire-plan du contrleur vido. Slectionnez la grille principale LayoutRoot comme conteneur contexte. Au sein du panneau Project, ouvrez le rpertoire bitmaps et double-cliquez sur limage nomme back.jpg. Celle-ci prend place au sein dun conteneur spcialis de type Image.
NOTE INFO

Vous pouvez cliquer droit sur limage au sein du projet et choisir loption Insert pour raliser cette opration. Il est galement possible de rechercher le composant Image dans la bibliothque de composants Silverlight pour linstancier directement sur la scne. Ensuite, vous devrez lui dfinir

Chapitre 7

Boutons personnaliss

171

un chemin daccs pointant vers limage que vous souhaitez afficher via sa proprit Source. Une image bitmap ne peut tre affiche que de deux manires. La premire consiste utiliser un conteneur Image. La seconde est dutiliser un pinceau de type ImageBrush (voir Chapitre9).

Slectionnez le composant Image nouvellement cr. Placez-le lindex 0 de la liste daffichage de LayoutRoot. Dfinissez une opacit de 20 % pour le composant Image. Centrez-le horizontalement et alignez-le en haut. Lidal serait dempcher la dformation de limage bitmap. Pour cela, dans les options propres au composant Image, choisissez un tirement de type UniformToFill. Ce mode de remplissage permet dviter la dformation de limage lorsque le composant est tir tout en vitant les zones de remplissage vides (voir Figure7.3).
Figure7.3
Mode dtirement UniformToFill.
Cas d'un contrle Image centr horizontalement et align vers le haut. Fentre du navigateur Fentre du navigateur

Conteneur Image avec un tirement en mode UniformToFill au sein d'un navigateur plus large que haut.

Conteneur Image avec un tirement en mode UniformToFill au sein d'un navigateur plus haut que large.

Pour configurer ce type de remplissage en C#, il suffit de cibler la proprit Stretch du composant Image comme suit:
//Instanciation dun composant Image Image myImage = new Image(); //On dfinit son mode de redimensionnement myImage.Stretch = Stretch.UniformToFill; Uri adresseImage = new Uri("fond.png",UriKind.Relative); BitmapImage bi = new BitmapImage( adresseImage ); myImage.Source = bi;

Nous ne nous attarderons pas sur ce code car nous aborderons le chargement dynamique de mdias au Chapitre10.

7.1.3 Le rle du composant Grid


La grille est le conteneur enfants multiples sur lequel repose larchitecture de la majorit des composants Silverlight. Lorsque vous souhaiterez crer un composant personnalis, vous devrez souvent centraliser les objets graphiques au sein dune grille avant de crer le composant. Celle-ci est trs performante et offre de nombreux avantages exploits par lquipe de dveloppeurs charge de crer la bibliothque de composants. Cest pour cette raison que le contrle Grid, nomm PlayPause dans larbre visuel de notre application, contient tous les lments qui composeront le

172

Partie II

Interactivit et cration graphique

futur composant ToggleButton. Vous allez commencer par crer le bouton davance rapide. Pour cela, slectionnez le trac nomm Background ainsi que le conteneur IconeForward, puis utilisez le raccourci Ctrl+G pour les imbriquer au sein dune nouvelle grille (voir Figure7.4).
Figure7.4
Arbre visuel de la maquette finalise.

Vous trouverez la maquette finalise dans larchive PlayerVideo_Maquette.zip du dossier chap7 des exemples du livre. Maintenant que vous avez centralis tous les lments graphiques, il est temps de crer un bouton personnalis.

7.2 Style visuel


Personnaliser laffichage dun composant visuel consiste souvent dfinir un nouveau style ce type dobjet. On peut donc se demander ce que reprsente un style. Cest assez simple, un style est un ensemble de proprits prdfinies propres un type de composant. Concrtement, vous pourriez vouloir que tous vos boutons contiennent un texte par dfaut et quils aient une largeur de150 pixels. Ce paramtrage prdfini de proprits dobjet est appel Style. Le principe des feuilles de style pour le contenu HTML repose sur cette dfinition. La dfinition dun style peut galement tre aborde dun point de vue purement technique. Tous les composants hritant de Control possdent la proprit Style. Cest le cas de nombreux composants tels que Button, RadioButton ou Slider. Ils ont la mme architecture que notre application. Ils sont constitus dun fichier XAML dclaratif ainsi que dun fichier C# contenant le code logique du composant. Toutefois, ils ne sont ouverts au changement que du point de vue visuel. Autrement dit, leur code logique est ferm la modification, loppos de leur code dclaratif qui est accessible et facilement modifiable. La raison en est simple : la fonctionnalit (donc le code logique dune barre de dfilement ou dun bouton) ne changera jamais alors que son apparence dpendra grandement de la charte graphique. Pour affecter ou atteindre le code XAML permettant de personnaliser un composant de type Control, on utilisera sa proprit Style.

7.2.1 Crer un style personnalis


Slectionnez la grille contenant les objets graphiques davance rapide et dans le menu Tools, cliquez sur le menu Make Into Control... Une bote de dialogue correspondant la Figure 7.5 saffiche. Elle vous permet de crer un nouveau composant personnalis partir du conteneur slectionn et de ses enfants. Comme vous pouvez le constater, la liste de composants possibles est

Chapitre 7

Boutons personnaliss

173

longue. Dans certains cas, cette tche demande un minimum dexprience, nous verrons comment aborder cet apprentissage au Chapitre9.
Figure7.5
Cration dun style.

Nommez le style ArcButtonStyle. En dessous de Define in, laissez loption This document coche. Cette option place le style au sein de la balise UserControl correspondant notre composant racine. Ainsi, tous les composants de type Button qui sont dans le composant UserControl auront la possibilit de recevoir ce style. Ceux qui seront situs lextrieur du UserControl nauront pas accs au style que nous avons cr. Cette srie doptions dfinit la porte daccs au style gnr (voir Chapitre11). Cliquez sur OK. Blend vous place par dfaut et immdiatement au sein du modle Button gnr, et non au niveau du style lui-mme. Seul larbre visuel du composant Button apparat (voir Figure7.6).
Figure7.6
Arbre visuel du bouton personnalis.

Comme vous le constatez, la liste daffichage se diffrencie de larbre visuel de MainPage.xaml par de nombreux points. Tout dabord, llment le plus haut nest plus User Control, mais llment Template qui signifie modle. Le modle dun composant constitue son arbre visuel et logique. Cest lune des proprits prdfinies quun style peut possder. En second lieu, nous savons que nous sommes dans un modle propre aux composants de type bouton car vous pouvez lire Button Template droite du nom du style ArcButtonStyle. Il peut arriver de se perdre un

174

Partie II

Interactivit et cration graphique

peu dans linterface lorsque lon dbute avec Blend car elle est entirement contextuelle. Veillez bien conserver des repres visuels tels que le nom de l'objet le plus haut dans la hirarchie. Vous remarquez, gauche de Arc ButtonStyle, licne ( ) qui est devenue active. Elle ne ltait pas au sein de larbre visuel principal de lapplication. Si vous la cliquez, vous pourrez revenir sur larbre visuel principal. Cest lune des manires de naviguer entre diffrents niveaux de composants. Pour finir, vous trouverez en bas de larbre visuel un composant de type Content Presenter gnr lors de la cration du style. Lexplication en est simple : la classe Button hrite elle-mme de ContentControl. Cette dernire ajoute un comportement dimbrication par dfaut toutes ses classes hrites. Grce la proprit Content, vous pouvez afficher nimporte quel type de contenu au sein du bouton en le glissant directement sur le bouton dans larbre visuel principal de l'application. Le composant ContentPresenter assure cette fonction. Slectionnez-le et passez sa proprit Visibility Collapsed pour dsactiver momentanment cette fonctionnalit. La chane de caractres Button affiche par dfaut disparat.

7.2.2 Naviguer entre style, modle et application principale


La navigation entre chaque niveau dimbrication reprsente lune des difficults rencontres lors de la prise en main de Blend. Vous aurez souvent besoin de corriger ou de mettre jour un style personnalis. Mais nous allons commencer par analyser le code XAML gnr afin de mieux comprendre le fonctionnement de la navigation dans Blend. Ouvrez le mode ddition XAML et placez-vous au niveau de la balise <UserControl.Resources>. Vous devriez visualiser lquivalent non abrg du code XAML montr ci-dessous:
<UserControl.Resources> <Style x:Key="ArcButtonStyle" TargetType="Button"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid> <VisualStateManager.VisualStateGroups> </VisualStateManager.VisualStateGroups> <Path x:Name="Background" </ControlTemplate> </Setter.Value> </Setter> </Style> <UserControl.Resources>

Lorsque le style est gnr dans un UserControl, il fait partie de sa proprit Resources. Cette dernire reprsente un ensemble de ressources de nimporte quel type. Lattribut x:Key de la balise Style dsigne le nom du style. Un style est une ressource en tant que telle, on utilise une cl de ressource plutt quun nom de rfrence (voir Chapitre9). La proprit TargetType spcifie le type dobjet cibl par ce style. La balise Setter dfinit une proprit spcifique au sein du style. Dans notre cas, lorsque le Style sera appliqu un bouton, la proprit Template de ce bouton sera affecte indirectement par notre Style nomm ArcButtonStyle. Le modle nest donc quune proprit parmi dautres que lon peut trouver au sein dun style. Cette importante notion conditionne la navigation au sein de linterface dExpression Blend. Passez en mode cration, puis cliquez sur licne , situe gauche du nom Arc Button Style. Blend affiche nouveau larbre visuel principal. La grille qui contenait les lments visuels du

Chapitre 7

Boutons personnaliss

175

bouton a t remplace par un composant Button. Nous avons, jusqu prsent, accd au modle mais pas au style. Il existe trois mthodes diffrentes pour accder un style:

La premire mthode est la plus simple. En haut de la fentre de design, vous apercevez trois icnes vous permettant daccder, soit linstance du bouton, soit au style, soit directement au modle du bouton slectionn (voir Figure7.7). Attention toutefois au fait que ces icnes sont visibles uniquement si le Style ou le Template ont dj t modifis ou du moins atteints dans Blend.

Figure7.7
Icnes daccs au style, au modle et nouvel arbre visuel du lecteur vido.

Licne contenant [Button] reprsente linstance du bouton actuellement slectionn au sein du Canvas. Si vous nommez votre bouton, cest le nom qui apparatra. Le pictogramme en forme de palette de peintre ( ) reprsente, quant lui, un raccourci vers le style. Il suffit donc de cliquer dessus pour y accder. La dernire icne, [ContentPresenter], correspond au dernier lment slectionn dans le modle et donne accs celui-ci.
NOTE INFO

Lorsque vous venez douvrir un projet, seule la premire des trois icnes est prsente en haut de la fentre de design. Ce nest pas un problme. Il suffit de cliquer sur cette icne, puis de slectionner le menu Edit Template> Edit Current (voir Figure7.8). Toutefois, vous accdez alors directement au modle et non au style. Vous devrez donc remonter dun niveau pour afficher le style.

Figure7.8
Accder au modle dun composant.

La seconde possibilit est dutiliser le menu Object > Edit Style, puis de cliquer sur Edit Current (voir Chapitre11 pour les options de cration de style).

176

Partie II

Interactivit et cration graphique

La dernire mthode consiste utiliser le panneau Resources situ droite, dplier larborescence du UserControl et cliquer sur licne du style auquel vous souhaitez accder (voir Figure7.9). Vous pouvez galement utiliser le panneau des proprits, cliquer sur le bouton des options avances situ au niveau de la proprit Style et cliquer sur Edit Resource.

Figure7.9
Icnes daccs au style, au modle et nouvel arbre visuel du lecteur vido.

Une fois au sein du style, vous constatez quaucun arbre visuel nest reprsent. Cest tout fait normal car nous ne sommes pas encore au sein du modle de notre bouton, mais simplement au niveau des proprits propres la classe Button. Modifiez la proprit Cursor en slectionnant la valeur Hand. De cette manire, lorsque le bouton sera survol, le curseur de la souris sera remplac par une main. Compilez le projet si ncessaire pour le vrifier. tudiez maintenant le code XAML gnr:
<UserControl.Resources> <Style x:Key="ArcButtonStyle" TargetType="Button"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid> <VisualStateManager.VisualStateGroups> </VisualStateManager.VisualStateGroups> <Path x:Name="Background" </ControlTemplate> </Setter.Value> </Setter> <Setter Property="Cursor" Value="Hand"/> </Style> <UserControl.Resources>

Une nouvelle balise Setter est contenue dans la balise Style. Elle indique que la proprit Cur sor doit prendre Hand pour valeur par dfaut lorsque le style est appliqu. Cela montre quel point le modle, reprsent par la proprit Template des objets de type Control, nest quune proprit parmi dautres. Vous allez maintenant modifier le modle en crant un lger reflet. Dfinissez un dgrad transparent pour le remplissage du trac nomm Background. Supprimez galement le contour du trac (voir Figure7.10).

Chapitre 7

Boutons personnaliss

177

Figure7.10
Bouton avec reflet.

Vous avez finalis la premire tape de cration du bouton. Il serait possible de crer autant de styles que ncessaire pour chaque bouton prsent dans le lecteur. Vous allez toutefois utiliser le style actuel pour crer dautres boutons ce qui est bien plus optimis en termes de production.

7.3 Bouton gnrique


Les quatre boutons principaux prsents sur le disque du lecteur partagent de nombreuses similitudes. Par exemple, afin de respecter la charte graphique, ils doivent avoir le mme comportement au survol de la souris. De plus, leur structure interne est identique et seul le pictogramme diffre. Crer autant de styles que de boutons serait inutile en plus dtre fastidieux. Il existe trois mthodes diffrentes pour rsoudre ce type de problmatique et minimiser le nombre de styles crs.

La premire est dutiliser du code logique, cest un peu ennuyeux dans notre situation. Bien que cette solution soit envisageable, cela serait un peu prmatur dutiliser du code logique pour rsoudre cette problmatique. Lorsque le nombre d'oprations de ce type est limit, il est prfrable que le graphiste garde cette tche pour lui et ne dpende pas du planning d'un dveloppeur. Toutefois, cela est salutaire et invitable dans certains cas lorsque le nombre de boutons grer est trop important. De manire gnrale, plus une tche est rbarbative, plus il est souhaitable qu'elle soit automatise via le code logique. La seconde manire de procder consiste utiliser la proprit Content propre aux classes hritant de ContentControl. La troisime possibilit est dutiliser la liaison de modles que nous aborderons en dtail au Chapitre11. Nous choisirons donc la deuxime solution.

7.3.1 La proprit Content


Finalement la seule diffrence entre chacun de nos boutons est licne elle-mme. La proprit Content, hrite de la classe ContentContent, permet dafficher nimporte quelle instance dobjet. Si nous externalisons licne prsente dans le modle de bouton, en laffectant la proprit Content des instances, chaque exemplaire de Button possdera sa propre icne tout en ayant un visuel homogne car affect du mme style. Une fois au sein du modle, slectionnez la grille nomme IconeForward, puis faites un coupercoller via le raccourci Ctrl+X. Ensuite, slectionnez le composant Content Presenter et passez sa proprit Visibility Visible. Revenez au niveau de lapplication et slectionnez le bouton comme contexte conteneur si ce nest pas le cas. Ensuite, utilisez le raccourci Ctrl+V pour im-

178

Partie II

Interactivit et cration graphique

briquer licne lintrieur du bouton. Cela revient affecter la grille la proprit Content du bouton. Vous pouvez recentrer licne lintrieur du bouton facilement en utilisant la proprit Margin de la grille IconeForward. Crez les trois autres boutons partir de celui existant. Aprs lavoir dupliqu trois fois, il vous reste positionner ses copies avec une simple rotation via longlet Render Transform du panneau des proprits. Vous pouvez vous faciliter la tche en dplaant le centre de transformation du bouton au centre du cercle. Ainsi, chaque copie du bouton sera place correctement via une rotation adquate (voir Figure7.11).
Figure7.11
Copie du bouton gnr avec centre de transformation dplac.

Vous pouvez supprimer la grille nomme IconeBackward dans ce cas prcis. La rotation du bouton davance rapide correspond en effet au visuel du bouton de retour rapide. Ensuite, il reste renommer la grille contenue dans le nouveau bouton par IconeBackward. Pour les deux autres copies, glissez les icnes correspondant la gestion du volume en utilisant larbre visuel et logique.
NOTE INFO

Utiliser une rotation fonctionne car tous nos boutons sont symtriques sur leur axe horizontal. Cette manipulation nest donc pas valable dans tous les cas de figure. La proprit Content, bien que trs utile, ne rpond pas toutes les problmatiques. Toutefois, son utilisation repose sur un concept plus large que nous allons maintenant tudier. Il est galement possible d'oprer une symtrie horizontale.

7.3.2 Liaison de modles


La liaison de modles est un concept provenant de WPF et peut sappliquer diverses proprits. Linstance ContentPresenter au sein de tout modle dobjet de type ContentControl repose sur ce principe. Ainsi, sans nous en rendre compte, la liaison de modles nous a permis de crer quatre boutons diffrents en apparence, mais ayant pourtant le mme style.

7.3.2.1 Principes
Pour mieux le constater, il vous suffit daller dans le code XAML du modle:
<ControlTemplate > <Grid> <ContentPresenter HorizontalAlignment=" {TemplateBinding HorizontalContentAlignment}"

Chapitre 7

Boutons personnaliss

179

VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> </Grid> </ControlTemplate>

Comme vous le remarquez, les deux proprits dalignement sont affectes dune valeur entre accolades. Cela signifie que ces proprits ne sont pas affectes dune valeur dfinie en dur, mais dune expression dont le rsultat peut voluer. Dans notre cas, cest mme un peu plus compliqu car lexpression entre accolades commence par le mot-cl TemplateBinding. Il signifie que les valeurs dalignement de linstance Content Presenter ne sont pas dfinies directement au sein du modle, mais au niveau de lexemplaire du bouton. Cest exactement ce qui permet dutiliser la proprit Content de chaque exemplaire afin de spcifier une icne diffrente afficher. Par dfaut, une instance Content Presenter possde une proprit Content lie la valeur affecte sur la proprit Content de lexemplaire. Celle-ci nest donc pas prcise dans le code XAML du ContentPresenter. Vous pourriez donc crire le code XAML suivant, le rsultat serait exactement le mme:
<ControlTemplate > <Grid> <ContentPresenter HorizontalAlignment= "{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}"/> </Grid> </ControlTemplate>

Vous pouvez consulter la Figure7.12 qui dcrit le schma de deux liaisons de modles. La premire correspond la liaison de modles propre la proprit Content. Elle est cre par dfaut. La seconde expose une liaison de modles entre la proprit Fill, du trac prsent lintrieur du modle, et la proprit Background de chaque exemplaire de Button.
Figure7.12
Le principe de la liaison de modles.

180

Partie II

Interactivit et cration graphique

En tant que designer interactif, vous pouvez dfinir une liaison de modles directement via linterface dExpression Blend. Nous allons permettre chaque exemplaire de bouton, au sein de notre lecteur vido, dafficher une couleur de remplissage diffrente.

7.3.2.2 Crer une liaison de modles


Afin de mieux comprendre lintrt de ce type de liaison, slectionnez nimporte lequel des boutons crs. Modifiez sa proprit Background en choisissant nimporte quelle couleur via le nuancier. Comme vous le constatez, modifier la couleur darrire-plan des boutons ne change en rien leur affichage. Cest tout fait normal car les proprits de couleurs ne sont relies aucun objet prsent dans le modle de nos boutons. Cest cette problmatique que nous allons maintenant traiter. Slectionnez le bouton davance rapide, puis affichez larbre visuel de son modle. Slectionnez le trac nomm Background. Il possde un remplissage que nous avons dfini en dur. Cela signifie que si vous modifiez ce trac directement lintrieur du modle, tous les exemplaires du bouton seront affects de ces modifications. Cliquez maintenant sur licne carre, situe droite de la proprit Fill du trac. Ensuite, slectionnez le menu Template Binding, puis la proprit Background (voir Figure7.13).
Figure7.13
Dfinir une liaison de modles au sein dExpression Blend.

Tous les boutons du lecteur possdant ce modle affichent dsormais la couleur dfinie sur leur proprit Background. Revenez au niveau de lapplication principale, puis dfinissez une couleur darrire-plan diffrente pour chaque exemplaire. Cela peut-tre un dgrad, une couleur pleine ou nimporte quelle instance de type Brush. Choisissez des couleurs vives afin de donner un peu plus de vie notre lecteur. Des couleurs bonbon fluo correctement doses seraient les bienvenues (voir Figure7.14). Voici le code XAML gnr dans Blend:
<ControlTemplate x:Key="ArcButtonStyle" TargetType="Button"> <Grid> <Path Fill="{TemplateBinding Background}" Data="" /> </Grid> </ControlTemplate>

Chapitre 7

Boutons personnaliss

181

En quelques oprations assez simples, nous avons cr une impression de richesse visuelle alors quun seul style est utilis.
Figure7.14
Chaque exemplaire de bouton possde dsormais sa propre couleur.

Dcliner plusieurs visuels partir dun unique modle est une technique de marketing utilise depuis bien longtemps et toujours dactualit (voir Figure7.15). Il est donc normal que le langage XAML fournisse les moyens aux designers de raliser simplement cette tche.
Figure7.15
Dclinaisons partir dun unique objet.

Jaune

Rose

Gris

Vert

Bleu

Vous pouvez tlcharger le projet finalis, PlayerVideo_ButtonsGenerique.zip, dans le dossier chap7 des exemples.

7.3.2.3 Contraintes
La liaison de modles est une fonctionnalit accessible pour la grande majorit des proprits dobjets prsents au sein des modles. Comme nous ltudierons aux Chapitres11 et12, toute proprit de type DependencyProperty peut tre la cible dune liaison de modles. La seule condition de fonctionnement est que la proprit de lobjet prsent dans le modle ne peut dfinir de liaison que vers une proprit de mme type. Ainsi, lorsque vous avez affich la liste des proprits acceptant une liaison pour Fill, seules quatre proprits de Button ont t disponibles: Background, BorderBrush, Fore ground et OpacityMask. Elles sont disponibles car elles acceptent des valeurs de type Brush au mme titre que Fill ou Stroke (qui sont propres aux objets hritant de Shape). Lorsquun transtypage implicite est possible, la liaison de modles est galement accessible. Par exemple, si vous essayez de dfinir une liaison de modles sur la proprit Content dun ContentPresenter, toutes les proprits de linstance seront accessibles. Ceci est normal

182

Partie II

Interactivit et cration graphique

puisque par dfinition la proprit Content est type Object et que toutes les classes hritent de Object. Content peut donc tre lie nimporte quelle proprit (voir Figure7.16).
Figure7.16
Liste des proprits disponibles pour une liaison de modles la proprit Content.

Dun point de vue logique, on pourrait considrer cette fonctionnalit comme une bquille permettant de rsoudre certaines problmatiques de conception. En effet, nous avons li la proprit Fill Background car elles ont des rles trs proches. Toutefois, rien ne nous empcherait de lier Fill OpacityMask. Cela nest pas trs logique, mais la liaison de modles nous lautorise. Il faudra parfois passer par des contorsions de ce type pour concevoir un composant gnrique et facile maintenir. Le dsavantage de ces contorsions est quil faut se souvenir dune liaison de modles qui nest pas forcment naturelle lorsque vous ouvrez nouveau le projet aprs un long moment.
NOTE INFO

Dans certains cas, vous ne souhaiterez pas rcuprer directement la valeur en provenance de la proprit dinstance mais la convertir la vole pour en avoir une reprsentation lgrement diffrente au sein du modle. Dans ce cas, vous utiliserez une classe implmentant linterface IVa lueConverter. Cela peut-tre trs pratique et se rvle simple coder. Nous en tudierons un exemple concret lorsque nous aborderons la cration de modles personnaliss plus complexes (ListBox, Slider, ProgressBar).

La dernire contrainte concerne en particulier les designers. Les proprits lies ne sont plus modifiables au sein du modle car elles rcuprent leur valeur dynamiquement. Il est donc tout fait logique de ne plus accder la modification de ces proprits au sein du modle. Lorsquune proprit est lie dans un modle dobjet, elle est entoure dun liser interdisant toute manipulation (voir Figure7.17). Dans la grande majorit des situations, vous pouvez toutefois rinitialiser la valeur de la proprit en cliquant sur licne carre situe sa droite et en slectionnant loption Reset (voir Figure7.18).

Chapitre 7

Boutons personnaliss

183

Figure7.17
Affichage dune proprit lie au sein dExpression Blend.

Figure7.18
Supprimer une liaison de modles.

Cette dernire contrainte parat vidente, mais il faut compter avec, surtout lorsque vous souhaiterez animer la proprit en question. Pour linstant notre bouton est fonctionnel, mais il ne ragit pas aux interactions utilisateur les plus simples. Vous allez y remdier en utilisant le gestionnaire dtats visuels abord dans la prochaine section.

7.4 Le gestionnaire dtats visuels


Le gestionnaire dtats visuels est un module introduit depuis Silverlight2. Il est reprsent par une API dont la classe principale est VisualStateManager. Celle-ci a pour objectif de grer les transitions entre chaque interface utilisateur au sein dune application. Cette dmarche et le concept de gestion dtats visuels reprsentent lun des axes majeurs de rflexion pour les ergonomes et les designers interactifs. Si lesthtique et lergonomie des interfaces visuelles composants une application furent considres comme importantes au milieu des annes90, les transitions qui les mettent en scne ne furent quant elles prises en compte que bien plus tard. Aujourdhui encore, les transitions restent ngliges au sein de nombreux dveloppements applicatifs. Pour les dveloppements de type Windows, celles-ci ne furent considres dun point de vue technique qu partir de .Net3, cest--dire lors de lapparition de Windows Presentation Foundation dbut2007.

184

Partie II

Interactivit et cration graphique

7.4.1 volution de lexprience utilisateur


Pour mieux comprendre limportance des transitions, nous allons faire un rapide retour sur lvolution des interfaces utilisateurs. Ainsi, nous comprendrons mieux le positionnement du lecteur Silverlight dans cette volution.

7.4.1.1 Les diffrentes gnrations dinterfaces


Trois grandes familles dinterfaces cohabitent aujourdhui. Elles furent successivement dcouvertes depuis la premire interface informatique homme-machine (voir Figure7.19).
Figure7.19
Les trois grands types dinterfaces utilisateur.
CLI GUI NUI

Texte Ncessite de la Mmoire, des connaissances spcifiques pralables et le respect de procdures linaires et complexes.

Graphique Demande une reconnaissance visuelle, une exploration systmatique de l'interface, de l'exprience spcifique au systme.

Objet Repose sur l'intuition dja acquise dans la vie relle par la manipulation d'objets concrets au sein d'interfaces contextuelles.

Le type CLI (Command Line Interface) fut la premire famille dinterface rellement disponible. Encore aujourdhui, Unix, Linux, FreeBsd, MS-DOS, le terminal sous MacOSX et de nombreux autres environnements reposent sur cette conception de laccs aux fonctionnalits. Concrtement, lutilisateur doit connatre le langage propre au systme dexploitation pour lutiliser. Ainsi, lister un rpertoire sous MS-DOS ou Linux Debian est ralis en excutant une commande prdfinie, immuable et propre au systme dexploitation. La grammaire et le vocabulaire de ce langage tant tous deux propres chaque systme, cela force lutilisateur se spcialiser ou ingurgiter un nombre de connaissances important et anecdotique tant leur utilisation peut savrer ponctuelle. Lutilisation du clavier comme mdium permettant la communication homme-machine est obligatoire. La souris na simplement aucun intrt car naviguer dans linterface est impossible. GUI est lacronyme de Graphic User Interface. Une quipe de Xerox PARC, compose entre autres de Alan Kay et Douglas Engelbar, a cr, la toute fin des annes70, la premire interface utilisateur graphique. Par la suite, Steve Jobs a poursuivi ce travail Apple, aid de nombreux anciens de Xerox. Paralllement Apple et PARC, X Window est dvelopp au MIT sous le nom de Projet Athena et devient accessible ds1983. Windows1 reprsentant linterface graphique de MS-DOS devient disponible partir de1985. Au sein dune interface GUI, on privilgie lexploration de lutilisateur ainsi quun apprentissage empirique (la pdagogie par lerreur ou lexprience, au choix). Cela est ralis travers un mode fentr grce auquel lutilisateur peut excuter des programmes, trouver ses fichiers et cliquer sur des icnes. Windows, Mac OS X, X-Window sont tous bass sur ce principe. Celui-ci na pas rellement volu depuis 1983 et Vista, Windows7, Snow Leopard ainsi que la grande majorit des systmes dexploitations sont bass sur ce principe. La souris devient ds ce moment un instrument incontournable pour utiliser ce type dinterfaces. Comme pour les interfaces de type CLI de nombreuses diffrences existent encore

Chapitre 7

Boutons personnaliss

185

entre chaque systme dexploitation. Cela repose constamment la problmatique de formation pour la prise en main et ladministration du systme. Le type NUI (Natural User Interface) est aujourdhui visible sur de trs rares priphriques tels que les tables de type Surface, liPhone plus proche du grand public ou encore le projet NATAL de Microsoft. Lobjectif est simple: viter lutilisateur lapprentissage dune interface en se reposant sur lexprience dj acquise dans son environnement naturel. Ainsi, pour un jeu de voiture sur liPhone, tourner le volant sera accompli en inclinant liPhone. Lutilisateur par sa propre nature possde tous les outils et instincts ncessaires pour interagir avec linterface. La voix, le toucher, la reconnaissance visuelle des objets, la go-localisation, la dtection du mouvement ainsi que sa direction, tous ces lments sont directement considrs comme des stimuli au mme titre que le clic de la souris dans un environnement de type GUI. Linterface NUI y ragit directement. Lutilisateur nest donc que trs peu limit par son environnement social, son ge ou son investissement dans lapprentissage de telle ou telle technologie. La table Surface est ce jour le priphrique supportant le mieux ce type dinterfaces. De plus, dvelopper pour Surface est assez simple car son framework repose sur la technologie WPF. Tous les priphriques supportant les interfaces NUI possdent un point commun : ils saccordent et se marie lenvironnement physique. Poser un objet physique sur une table Surface, se retrouver entre amis autour, collaborer, jouer plusieurs est non seulement possible mais souhaitable. Surface est un environnement massivement multi-touch 360 degrs. De nombreuses autres technologies de ce type existent dont certaines ont t dveloppes par des universitaires et sont compltement libre daccs moyennant un peu de bricolage fait maison. Dans ce type dinterfaces, les transitions sont extrmement importantes car aucune fentre dexploration nest prsente. En effet, les interfaces utilisateur NUI tant entirement contextuelles, cest--dire lies au contexte dutilisation, il devient crucial que lutilisateur connaisse sa position au sein du processus dutilisation. Il doit galement savoir son point de dpart et ses destinations possibles. Si vous souhaitez plus dinformations sur les interfaces de type NUI, vous pouvez consulter le blog de Dr Neil, trs investi dans la technologie Surface de Microsoft, cette adresse: http:// blogs.msdn.com/surface/archive/2009/03/13/friday-afternoon-chat-with-dr-neil-on-education.aspx, ou encore le site de Douglas Edric Stanley concernant lhypertable et ses exprimentations: http://www.abstractmachine.net/blog/. Nous allons maintenant essayer de comprendre comment se positionne Silverlight dans cette volution.

7.4.1.2 Lapport des moteurs vectoriels


Bien que les moteurs vectoriels, comme Flash ou Silverlight, soient contenus par dfaut au sein dun navigateur web (donc dune interface GUI), ils proposent des interfaces utilisateur novatrices chappant compltement aux contraintes GUI. Le fichier compil peut en effet proposer nimporte quel type dinterfaces utilisateur puisquil est compltement indpendant du systme dexploitation. Cela est possible car les designers dinterfaces sont partie prenante dans la conception de lapplication, mais galement parce que chaque dveloppement est unique et industrialisable au prix de nombreux efforts. Contrairement une application Windows Forms, limitant grandement la manire de prsenter les informations mais facile dvelopper, une application WPF est entirement personnalisable mais plus difficile concevoir (car intgrant de nouveaux profils mtier). Flash est sans doute, jusqu prsent, le moteur vectoriel qui a le plus bnfici de la communaut

186

Partie II

Interactivit et cration graphique

des designers. Cela a permis de saffranchir des modes de rflexion et des standards dergonomie lis au systme dexploitation. Lexemple de lapplication de rservation en ligne du clbre htel Broadmoor au Colorado est la preuve de lefficacit dune bonne ergonomie (voir Figure7.20). Bien que linterface (voir Figure 7.20) ft dveloppe il y a maintenant sept ans, elle na t modifie que trs rcemment. Nous pourrions procder un lifting complet dun point de vue esthtique, mais la manire dont elle est envisage rpond compltement aux attentes du client. Lors de sa mise en ligne, les rservations de lhtel ont simplement tripl.
Figure7.20
Linterface de rservation du Broadmoor avec ses 3tapes de rservation.

Ainsi les applications vectorielles Cross Platform bnficient dun statut intermdiaire puisquelles sont conues indpendamment du systme ou du navigateur qui les affiche. Lapplication de rservation en est un exemple criant et les transitions quelle propose lutilisateur entre chaque tape du processus sont pertinentes encore aujourdhui. Celles-ci bnficient, en outre, de nombreux comportements asynchrones tels que la connexion socket XML ou binaire, le peer to peer, lappel de services distants, le streaming vido live ou enregistr, laffichage dynamique de mdias. Ces fonctionnalits favorisent grandement lessor dapplications caractre social et la diffusion de contenus riches, deux thmes majeurs du NUI. La grande limite reste donc la souris et le clavier comme medium incontournable de lexprience utilisateur pour ce type denvironnement.

7.4.1.3 Limportance des transitions


Les transitions sont considres comme aussi importantes que les interfaces applicatives. Chaque interface visuelle au sein dune application peut tre considre comme une fonctionnalit de cette dernire, une brique applicative. Les transitions jouent le rle de mortier entre chaque brique fonctionnelle. Autrement dit, elles font le lien entre deux interfaces visuelles. Elles possdent de ce fait trois rles importants :

Esthtisme et ludique. Elles doivent tre esthtiques et amusantes, car ce qui est ludique est directement connect laffect de lutilisateur. Le plaisir ressenti lutilisation est aujourdhui un domaine qui nest plus exclusivement reli aux jeux vido. Lexprience utilisateur lorsquelle est agrable peut faire la diffrence commercialement.

Chapitre 7

Boutons personnaliss

187

Sens. Bien que ludiques, les transitions ne sont pas pour autant gratuites. Elles ont donc pour mission de renforcer le sens donn chaque interface visuelle. Nous pourrions par exemple utiliser des transitions3D sur la profondeur des objets pour permettre lutilisateur de ressentir leur importance un instant donn du processus tout en vitant une navigation trop linaire. Localisation. Elles ont galement pour objectif de faciliter limmersion de lutilisateur en amliorant lergonomie. Afin datteindre ces objectifs, elles doivent fournir une indication supplmentaire sur lemplacement, la position ou ltape du processus dans lequel est situ lutilisateur. Il ne suffit pas de savoir ce que lon fait, il faut galement savoir do lon vient et o lon va. Cela permet lutilisateur de se reprer et davoir une ide claire des tches restant accomplir ou les fonctionnalits accessibles. Cette notion est trs importante pour les interfaces de type naturelle non fentre pour des priphriques comme Surface, liPhone, etc. Pour ces interfaces de nouvelle gnration, il faut viter autant que possible lutilisateur davoir dcouvrir lapplication par une exploration systmatique ou par lexprimentation empirique. L'exprience des interactions dans la vie relle est dj accomplie, le designer dexprience utilisateur doit rcuprer ce savoir acquis pour accompagner la dmarche d'utilisation.

Pour finir sur ce sujet, il est important de concevoir les transitions le plus tt possible dans le processus de conception, mais galement dquilibrer les trois composantes dcrites plus haut car privilgier trop lune au dpend des autres engendre des comportements non souhaits. Une application trop agrable, mais dans laquelle lutilisateur ne sait pas se situer, est intressante dans une dmarche artistique, mais nest pas satisfaisante dun point de vue commercial. linverse, savoir se situer, mais navoir aucune surprise ou plaisir dans la navigation, peut provoquer une dsaffection et de lennui. Sur Internet, lennui est le grand ennemi des Webmasters. Nous allons maintenant aborder la conception des transitions.

7.4.2 Au sein dun control


Grer les transitions est ralisable deux niveaux diffrents. Vous pouvez grer celles appartenant lapplication elle-mme, ou celles prdfinies dans les composants personnalisables tels que Button. Dun point de vue dveloppeur, il ny a pas rellement de diffrences entre ces deux niveaux. Lapplication peut, en effet, tre considre comme un composant gant trs spcifique car son architecture est similaire aux composants standard dj fournis. Toutefois dun point de vue organisationnel et utilisateur final, la diffrence est flagrante. Nous allons commencer par grer les tats dun des boutons personnaliss pour mieux comprendre lutilisation des transitions au sein de Silverlight.

7.4.2.1 Principes
Slectionnez le bouton davance rapide, cliquez-le droit et slectionnez successivement les menus Edit> Template> Edit Current. Vous atteignez une nouvelle fois le modle du bouton. Cest ce niveau que les transitions sont gres pour tous les composants et non au niveau du style. Ouvrez le panneau contenant les tats visuels States. Les objets de type Button possdent tous les mmes tats (voir Figure7.21).

188

Partie II

Interactivit et cration graphique

Figure7.21
Les tats visuels au sein dun composant Button.

Tout dabord, les tats visuels sont contenus au sein de groupes dtats visuels reprsents par la classe VisualStateGroup. Le code XAML, formalisant nos tats visuels, est situ dans la balise VisualStateManager.VisualStateGroup:
<VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="FocusStates"> <VisualState x:Name="Focused"/> <VisualState x:Name="Unfocused"/> </VisualStateGroup> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"/> <VisualState x:Name="Pressed"/> <VisualState x:Name="Disabled"/> </VisualStateGroup> </VisualStateManager.VisualStateGroups>

Les groupes dtats visuels sont rpartis par fonctionnalits. Dans le code XAML ci-dessus, le premier groupe gre le visuel selon le focus utilisateur, le deuxime en fonction de ses tats dinteractions utilisateur. Ainsi, un bouton peut ne pas possder lintrt utilisateur tout en tant survol. Il peut donc afficher deux tats visuels la fois, mais un seul par groupe dtats. Il peut avoir une opacit diffrente pour le survol de la souris et possder une petite ombre pour indiquer le fait quil possde le focus utilisateur. Deux tats centraliss dans des groupes diffrents seront indpendants.
NOTE INFO

Un bouton possdant le focus utilisateur est cliquable par dfaut via la barre despace ou la touche Entre. Cest assez pratique dans certains cas dutilisation, notamment pour les formulaires dinscription ou pour les fentres de connexion. Vous devrez toutefois grer lordre de tabulation pour viter au focus utilisateur de se placer sur nimporte quel composant interactif.

Avant daller plus loin, sachez que Base fait rfrence au visuel du bouton lorsque celui-ci ne possde aucun tat visuel actif. Lorsque vous slectionnez Base, puis que vous modifiez une proprit dobjet, tous les tats visuels seront, par dfaut, affects de cette modification. Voici la description des tats interactifs du groupe CommonStates:

Chapitre 7

Boutons personnaliss

189

Normal. Ltat normal est toujours actif par dfaut, il reprsente ltat dinteraction normal du bouton. Cest lui qui est, en ralit, affich lorsque vous tes lextrieur du modle. MouseOver. Reprsente le visuel du bouton lorsque celui-ci est survol par la souris. Pressed. Affiche ltat du bouton lorsque lutilisateur clique dessus en appuyant sur le bouton gauche de la souris. Disabled. Dfinit le visuel affich lorsque le bouton nest pas actif. Vous pourriez dsactiver un bouton de souscription tant quun formulaire nest pas rempli de manire conforme par exemple. Vous pouvez directement lactiver en modifiant la proprit Enabled dun exemplaire de composant.

Considrez ces tats comme une liste de choix. Vous ne pourrez en afficher quun seul la fois par groupe dtats. Nous abordons cette contrainte la section7.4.3.2. Chaque type de composant possde sa propre liste dtats visuels. Vous trouverez pourtant certains points communs entre ceux-ci. Les principes que nous exposons ici sont, pour leur part, communs tous composants

7.4.2.2 Modifier les tats visuels


Modifier un tat est assez simple. Cliquez sur ltat MouseOver, vous passez en mode enregistrement dtat et un contour rouge vous le signale. Vous pourriez tre tent de modifier la couleur ce stade. Ainsi, le bouton changerait de couleur lors du survol. Toutefois cela est impossible car la proprit Fill est lie la proprit Background de linstance. Celle-ci est donc ferme la modification au sein du modle. Ce nest pas grave, nous allons passer outre cette contrainte en utilisant ltat Normal. Slectionnez-le, puis cliquez sur lobjet reprsentant le fond de couleur. Affectez la proprit Opacity du trac de la valeur0. Comme vous le constatez, tous les boutons perdent leur couleur darrire-plan ce stade. Cest tout fait logique puisque ltat Normal est affich par dfaut. Les autres tats visuels utilisent les proprits dfinies par Base, la couleur est donc visible au survol (MouseOver), sur le clic de lutilisateur (Pressed) et lorsque le bouton est inactif (Disabled). Vous allez maintenant agrandir de 20 % les dimensions de licne lors du survol de la souris. Comme licne nest pas contenue au sein du modle, mais affecte la proprit Content des boutons, il suffit daugmenter pour cela les dimensions du composant ContentPresenter. Cest ce composant qui affiche la valeur de la proprit Content de chaque exemplaire. Il est ncessaire dutiliser les transformations relatives afin de saffranchir des contraintes de positionnement lies au conteneur Grid. Slectionnez ltat MouseOver, puis ContentPresenter. Ouvrez longlet des transformations relatives et modifiez lchelle en x (ScaleX) et en y (ScaleY) en affectant chacune delles la valeur1.2. Licne est dornavant agrandie lorsque vous passez de ltat Normal ltat MouseOver (voir Figure7.22).
Figure7.22
Modification de ltat MouseOver.

190

Partie II

Interactivit et cration graphique

Lorsque vous testez votre application aprs lavoir compile, vous remarquez que tout correspond nos actions. Toutefois lorsque vous cliquez sur les boutons, licne retrouve une taille normale car vous passez implicitement ltat Pressed. Cela serait plus lgant si nous navions pas de diffrences marques entre Pressed et MouseOver. Revenez dans Blend et cliquez-droit sur ltat MouseOver, puis cliquez sur loption Copy to Pressed State. Toutes les modifications ralises sur ltat MouseOver viennent dtre directement affectes aux objets sur Pressed. Ce menu cach vous vitera des manipulations rbarbatives dans de nombreux cas. Tous les tats sont maintenant configurs, il ne nous reste plus qu les animer.
NOTE INFO

Vous pouvez visualiser un tat visuel sans pour autant le slectionner. Pour cela, cliquez sur Base, puis sur le cercle noir prsent gauche de ltat dont vous souhaitez avoir un aperu (voir Figure7.23). Une fois activ, licne dun il apparat ( ). Cela ne fonctionnera toutefois pas forcment lorsque vous utiliserez des animations personnalises.

Figure7.23
Affichage dtats visuels sans slection.

7.4.2.3 Animer les tats visuels


Pour linstant, chaque transition est brutale donc peu lgante. Pour y remdier, il faut dfinir des interpolations pour chacune. Il existe trois possibilits via linterface de Blend pour crer des transitions animes. Le code XAML est assez proche pour chacune delles, mais elles apportent une finesse de personnalisation diffrente. La premire mthodologie consiste dfinir une dure danimation gnrique qui sera propre lensemble des tats visuels contenus dans un groupe. C'est trs pratique en terme de productivit. Toujours au sein du modle dans le panneau States, dans le groupe dtats visuels CommonStates, vous trouverez loption Default transition. Dans le champ de saisie situ droite et indiquant0s, dfinissez une dure de0.4s (voir Figure7.24).

Chapitre 7

Boutons personnaliss

191

Figure7.24
Cration dune transition gnrique de groupe.

Vous venez en une seule manipulation de dfinirtrois transitions diffrentes. Quel que soit ltat interactif actuel du bouton, une transition de4/10 de seconde sera par dfaut joue afin datteindre nimporte quel autre tat du groupe CommonStates. Voici le code XAML gnr:
<VisualStateGroup x:Name="CommonStates"> <VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="00:00:00.4"/> </VisualStateGroup.Transitions> <VisualState x:Name="Normal"> </VisualStateGroup>

Nous allons maintenant outrepasser lanimation de base. Utiliser une seule interpolation gnrique par groupe dtats est trs bien pour un prototype rapide, mais cela est parfois un peu trop sobre ou standard pour une version finale de lapplication. Vous aurez besoin de marquer la diffrence dimportance ou de dfinir une acclration propre chaque transition. Lesthtique entre galement en ligne de compte. Normaliser ou industrialiser trop les transitions, bien quefficace en terme de temps, nest pas une bonne pratique. Il faut travailler chaque transition indpendamment les unes des autres. Cela ne signifie pas pour autant que vous devez trop en faire, bien au contraire. Les transitions les moins importantes prendront moins de temps. Les plus importantes sont situes au niveau de lapplication et permettent de valider les diffrentes tapes dutilisation. Celles-ci doivent tre plus travailles. La deuxime mthodologie permet de dfinir une dure et une quation dacclration propre chaque tat. Cliquez sur licne reprsentant une flche et un signe plus ( ) situe droite de ltat MouseOver. Une autre srie dicnes vous permet de dfinir une transition spcifique. Choisissez celle dfinie par une toile suivie de MouseOver. Celle-ci dfinie une transition unique depuis nimporte quel tat dorigine destination de Mouse Over. Comme vous le constatez, la valeur par dfaut correspond celle que vous avez dfinie pour la transition par dfaut, soit0.4. Spcifiez un dlai de0.6s, ainsi quune quation dacclration de type CubicOut (voir Figure7.25).

192

Partie II

Interactivit et cration graphique

Figure7.25
Cration dune transition dtat.

Les spcificits de chaque transition sont contenues dans la balise VisualState Group.Transitions. Vous le constatez dans le code XAML ci-dessous:
<VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="00:00:00.4"/> <VisualTransition GeneratedDuration="00:00:00.6" To="MouseOver"> <VisualTransition.GeneratedEasingFunction> <CubicEase EasingMode="EaseOut"/> </VisualTransition.GeneratedEasingFunction> </VisualTransition> </VisualStateGroup.Transitions>

Lorsque les tats de dpart ou de destination, au sein de la balise VisualTransition, ne sont pas prciss, cette balise concerne toutes les transitions dtat tat quel que soit leur nombre. Les transitions dont vous souhaitez diffrencier le comportement passeront outre le rglage de base.
NOTE INFO

Vous pouvez ds prsent tester ces transitions en utilisant le mode de prvisualisation. Cliquez sur licne contenant une flche et licne de lecture pour activer ce mode ( ). Celle-ci est situe tout en haut du panneau des tats. Slectionnez ltat Normal, puis MouseOver, la transition est automatiquement joue de manire optimise. Cette fonctionnalit est vraiment trs utile et vite de compiler systmatiquement l'application pour tester les transitions.

La dernire manire de grer les transitions consiste crer une animation personnalise laide dun objet Storyboard personnalis. Cette manire de procder offre bien plus de possibilits mais il est moins facile de la maintenir sur le temps. Toutefois cest galement celle qui vous permettra de crer des transitions plus rythmes et plus originales. Slectionnez ltat MouseOver et cliquez sur licne permettant dafficher le scnario: . Vous remarquez quune cl danimation est prsente pour lobjet ContentPresenter la seconde0. Cest le comportement par dfaut adopt par le mode denregistrement dtat. Passez ensuite en mode ddition XAML, Le code ci-dessous montre clairement lintgration de lobjet Storyboard:
<VisualStateGroup x:Name="CommonStates"> <VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="00:00:00.4"/> <VisualTransition GeneratedDuration="00:00:00.6" To="MouseOver">

Chapitre 7

Boutons personnaliss

193

<VisualTransition.GeneratedEasingFunction> <CubicEase EasingMode="EaseOut"/> </VisualTransition.GeneratedEasingFunction> </VisualTransition> </VisualStateGroup.Transitions> <VisualState x:Name="MouseOver"> <Storyboard> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard. TargetName="contentPresenter" Storyboard.TargetProperty="(UIElement.RenderTransform). (TransformGroup.Children)[0].(ScaleTransform.ScaleX)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1.4"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard. TargetName="contentPresenter" Storyboard. TargetProperty="(UIElement.RenderTransform). (TransformGroup.Children)[0].(ScaleTransform.ScaleY)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1.4"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup>

La structure de chaque tat est simple, les transitions sont par dfaut centralises dans la balise Visual StateGroup.Transitions. La dfinition de chaque tat contenant les proprits modifies est stocke, quant elle, dans une balise VisualState. Cette balise contient au moins lattribut x:Name correspondant au nom de la transition. Chaque objet de type VisualState contient un Storyboard. Cette animation est dclenche chaque fois que ltat doit tre affich, mais par dfaut les cls danimation se situent toutes la seconde0. Autrement dit, la dure du Storyboard lui-mme est par dfaut de0 seconde. La dure de la transition, qui est diffrente, est gre au niveau des transitions, via la proprit GeneratedDuration, qui est configurable via le panneau States au sein de Blend. Supprimez la transition que nous avions dfinie pour ltat MouseOver en passant, soit par le code XAML, soit par linterface de Blend. Pour le faire au sein de Blend, il vous suffit de cliquer sur licne moins ( ). Dplacez ensuite la cl danimation la seconde0.6. Pour finir, dfinissez une quation dacclration de type CubicEase sur celle-ci. Vous obtenez le code XAML ci-dessous:
<VisualStateGroup x:Name="CommonStates"> <VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="00:00:00.4"/> </VisualStateGroup.Transitions> <VisualState x:Name="MouseOver"> <Storyboard> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="contentPresenter" Storyboard. TargetProperty="(UIElement.RenderTransform). (TransformGroup.Children)[0].(ScaleTransform.ScaleX)"> <EasingDoubleKeyFrame KeyTime="00:00:00.6" Value="1.4"> <EasingDoubleKeyFrame.EasingFunction> <CubicEase EasingMode="EaseOut"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames>

194

Partie II

Interactivit et cration graphique

<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard. TargetName="contentPresenter" Storyboard. TargetProperty="(UIElement.RenderTransform). (TransformGroup.Children)[0].(ScaleTransform.ScaleY)"> <EasingDoubleKeyFrame KeyTime="00:00:00.6" Value="1.4"> <EasingDoubleKeyFrame.EasingFunction> <CubicEase EasingMode="EaseOut"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup>

Maintenant que vous connaissez toutes les manires de crer des transitions, finalisez le design de chaque tat interactif au sein du groupe CommonStates. Vous avez le choix: soit diffrencier ltat Pressed de ltat MouseOver, soit les cloner. Dupliquer ltat, par copier-coller du code XAML dj gnr, reste le plus simple.
NOTE INFO

Si vous crez un Storyboard personnalis comme ralis pour ltat MouseOver, vous ne pourrez pas avoir daperu de cet tat en utilisant licne de lil. Cest tout fait normal puisque cet il ne montre que la seconde0 du Storyboard ( ). L'idal serait videmment d'afficher la cl d'animation finale.

Pour ltat Disabled, vous pouvez passer lopacit de larrire-plan de couleur 0 et passer sa proprit Visibility Collapsed. Cela ne suffit pas pour le diffrencier de ltat Normal. Affectez lopacit et la visibilit du ContentPresenter de la mme manire. Ainsi lorsque le bouton est dsactiv, il est compltement cach. Dpliez la ligne du temps ou scnario de cet tat. Dcalez ensuite toutes les cls danimation de6/10 de seconde. La proprit Visibility est anime grce une cl de type Discrete. Cela signifie quelle ne prendra la valeur Collapsed que lorsque la tte de lecture atteindra la cl. Lopacit sera, quant elle, interpole car la plage de valeurs admises est de type Double (voir Figure7.26).
Figure7.26
Scnario de ltat Disabled.

Chapitre 7

Boutons personnaliss

195

7.4.2.4 Contraintes logiques


Vous pouvez dcider de personnaliser les tats Focused et Unfocused. Si tel est le cas, sachez que vous ne pourrez pas rutiliser des proprits dj modifies dans le groupe dtats CommonStates. Pour vous en rendre compte, slectionnez ltat Unfocused et modifiez lopacit du trac vectoriel assurant le fond de couleur. Au sein du panneau des tats, une nouvelle icne apparat. Elle vous indique une utilisation illogique des tats (voir Figure7.27).
Figure7.27
Erreur logique denregistrement dtat.

Le dilemme est simple, les groupes dtats sont indpendants les uns des autres du point de vue de leur affichage. Le bouton peut possder le focus ou non, et tre survol par la souris en mme temps. Ds lors, les deux tats vont tre tous deux affichs. Toutefois, comme la proprit Opacity du trac Background a t affecte dans chaque tat, le gestionnaire dtats visuels ne saura pas laquelle des deux affectations choisir. Laffectation est due au fait que le bouton na pas le focus ou elle est gnre par le survol de la souris. Cest un choix impossible rsoudre de manire lgante et cela est tout fait logique dun point de vue conception. Il ny a aucune manire simple de rsoudre ce type de conflit car cest le raisonnement la source qui est faux. Avoir le focus utilisateur nest pas la mme chose que survoler le bouton. Le visuel doit donc tre diffrent. Supprimez les modifications apportes ltat Unfocused. Le mieux serait de rajouter une forme de type Ellipse sous le ContentPresenter avec un lger dgrad du blanc vers le blanc transparent pour simuler une lueur. Lorsque le bouton na pas lintrt utilisateur, cette lueur est dsactive en passant son opacit 0. Compilez et testez votre application en utilisant la touche Tabulation (voir Figure7.28).
Figure7.28
Gestion visuelle du focus utilisateur.

196

Partie II

Interactivit et cration graphique

NOTE INFO

Pour voir laffichage du focus sans larrire-plan de couleur, vous pouvez slectionner ltat Fo cused, puis cliquez sur licne daperu gauche de ltat Normal (voir Figure 7.28). De cette manire, vous pouvez tester le visuel de ltat Focused avec nimporte quel autre tat interactif si celui-ci nappartient pas au groupe FocusStates.

Vous trouverez cet exercice corrig dans: chap7/PlayerVideo_ButtonsAnime.zip.

7.4.3 Au niveau de lapplication


Nous allons maintenant crer des tats au niveau de lapplication elle-mme. Les tats que nous avons configurs jusqu prsent taient propres la classe Button. Une application Silverlight ne possde pas dtats visuels par dfaut, il vous faudra donc les crer manuellement. Avant de commencer, il importe de faire un rapide tour des diffrents affichages que nous pourrions envisager.

7.4.3.1 Dcouper lapplication


Nous partons du principe que le lecteur vido soccultera de lui-mme aprs un certain temps dinactivit de la souris. Il sera donc parfois visible et parfois invisible. Cette fonctionnalit peut faire lobjet dun groupe dtats nomm VisibleStates. Pour linstant le lecteur vido ne semble prsenter que des fonctionnalits sommaires, toutefois on pourrait imaginer plusieurs affichages diffrents. Par exemple, chaque fois que la souris survolerait lun des boutons de contrle, le disque se teinterait partiellement pour illustrer laction en cours. Pour crer ce type dinteraction, il nous faudra crer un groupe dtats nomm ColorStates. Nous pourrions galement proposer deux modes daffichage. Lutilisateur pourrait soit utiliser les contrles de base que nous avons dj raliss, soit consulter ltat de tlchargement et naviguer grce une tte de lecture directement sur une ligne de temps reprsente par le disque. Au final, cette fonctionnalit constituerait galement un groupe dtats visuels nomm ControlStates. Nous aurons donctrois groupes dtats indpendants qui greront chacun laffichage de lune de ces fonctionnalits (voir Figure7.29).

Chapitre 7

Boutons personnaliss

197

Figure7.29
Schma des groupes dtats visuels propres notre application.

Base VisibleStates VisiblePlayer HiddenPlayer ColorStates Normal (When there's no interaction) Purple (Volume plus) Orange (Arrire rapide) Cyan (Volume moins) Green (Avance rapide) Black (Lecture/Pause) ControlStates
(Contrles Volume Up, Volume Down, Avance Rapide, Arrire Rapide etc...) (permet de voir l'tat du tlchargement en cours ou la progression de la tte de lecture vido)

Le lecteur est visible ou invisible selon les besoins de l'utilisateur. Au bout de deux secondes d'inactivit de la souris, le lecteur est occult.

Ces tats sont activs lorsque l'utilisateur survole l'un des boutons. Chaque bouton possde son propre thme de couleur.

BasicView

ProgressView

Activs selon le type de contrle que l'utilisateur souhaite exercer.

7.4.3.2 Crer des tats visuels


Positionnez-vous au niveau de lapplication et affichez le panneau States. Celui-ci est pour linstant vide. Crez trois groupes via licne dajout de groupe ( ). Nommez-les respectivement VisibleStates, ColorStates et ControlStates. Vous allez crer tous les tats dcrits la Figure7.29. droite du groupe VisibleStates, cliquez sur licne dajout dtat ( ). Nommez le nouvel tat cr VisiblePlayer et rptez lopration autant de fois que ncessaire pour tous les groupes. Vous allez commencer par grer les transitions du groupe ColorStates. Pour celuici, dfinissez une transition gnrique de4/10 de seconde ainsi quune quation dacclration de votre choix. Vous navez pas rellement besoin danimations personnalises pour linterpolation de couleur. Utiliser une animation gnrique est dans ce cas le meilleur moyen de gagner du temps (voir Figure7.30).

198

Partie II

Interactivit et cration graphique

Figure7.30
Groupes dtats visuels du lecteur vido.

Il ne vous reste plus qu slectionner chaque tat au sein de ce groupe pour modifier la couleur du dgrad du disque situ sous les contrles utilisateur. Pour rcuprer les bonnes nuances de couleur, vous pouvez temporairement modifier ltat Normal du bouton gnrique. En passant la valeur dopacit du bouton 100 %, vous faites apparatre les couleurs de chacun des contrles. Ensuite, slectionnez ltat Purple, puis dans larbre visuel de lapplication, lobjet Large ColorRing. Cest en fait lun des disques que vous allez colorer. Modifiez son remplissage pour un dgrad du rose vers le blanc. Vous pouvez vous baser sur la couleur du bouton de volume VolumeUpBtn. Slectionnez ensuite le trac SmallColorRing et recommencez le processus. Procdez de mme pour chaque tat de couleur en utilisant les couleurs de base de chaque bouton. Retournez dans le modle de bouton gnrique, au sein de ltat Normal, et redfinissez un arrireplan 100% dopacit. Avant de piloter le gestionnaire dtats visuels, vous pouvez crer une ou deux animations personnalises pour les tats du groupe VisibleStates. Ne vous occupez pas pour linstant du groupe ControlStates.

7.4.3.3 Grer les transitions grce aux comportements interactifs


Les comportements ou Behaviors au sein de Blend et de lAPI XAML permettent aux designers interactifs de grer par eux-mmes les interactions simples. Ouvrez le panneau Assets et le menu Behaviors, la liste des comportements accessibles par dfaut apparat (voir Figure7.31).
Figure7.31
Liste des comportements disponibles.

Chapitre 7

Boutons personnaliss

199

Vous les utiliserez tous tt ou tard dans vos dveloppements, ainsi que dans ce livre. Nous les aborderons plus en dtail au Chapitre8. Glissez-dposez le comportement nomm GoToStateAction sur chacun des quatre contrles utilisateur dj raliss. Ils permettent daccder un tat visuel lors de linteraction utilisateur de votre choix. Dans le panneau des proprits, configurez-les pour quils ragissent au survol de la souris (MouseEnter) et ciblent ltat de couleur correspondant au sein du groupe ColorStates (voir Figure7.32).
Figure7.32
Configuration du comportement GoToStateAction.

Compilez et testez le projet. Vous remarquez que ds que vous survolez un bouton, lapplication change dtat visuel. La couleur des deux disques se met jour dynamiquement. Toutefois, lapplication ne raffiche pas ltat Normal. Il faudrait pour cela dfinir un nouveau comportement ciblant cet tat lorsque la souris quitte le survol des boutons. Cest assez simple raliser. Afin de vous viter un travail fastidieux, groupez tous les contrles au sein dun conteneur de type Canvas. Dposez le comportement GoToStateAction sur ce dernier. Ensuite, configurez-le afin quil se dclenche lorsque la souris quitte son survol et quil cible ltat Normal. Cette manire de procder vous vite de recrer le mme comportement quatre fois (une fois par contrle). Larbre visuel de notre application sest lgrement toff, vous pouvez voir la portion correspondant aux comportements ajouts sur la Figure7.33.
Figure7.33
Partie de larbre visuel avec comportements.

Testez et compilez votre application: celle-ci ragit de manire fluide lors du survol de chaque contrle.

200

Partie II

Interactivit et cration graphique

7.4.3.4 Piloter le gestionnaire dtats visuels avec C#


Piloter et grer le dclenchement des transitions en C# est assez simple. Nous devrons pour cela utiliser la classe VisualStateManager. Nous allons faire en sorte que tant que la souris bouge, ltat VisiblePlayer soit ltat de destination. Au bout de deux secondes dinactivit, ltat cibl sera HiddenPlayer. Le code ci-dessous constitue la premire tape:
public partial class MainPage: UserControl { public MainPage() { InitializeComponent(); //Par dfaut le lecteur est cach VisualStateManager.GoToState(this, "HiddenPlayer", true); //on coute lvnement MouseMove LayoutRoot.MouseMove += LayoutRoot_MouseMove; } //Chaque fois que celui-ci est diffus //donc lorsque la souris bouge void LayoutRoot_MouseMove(object sender, MouseEventArgs e) { //on utilise le gestionnaire dtats visuels //afin dafficher ltat VisiblePlayer VisualStateManager.GoToState(this, "VisiblePlayer", true); } }

Dans le code ci-dessus, les deux lignes importantes concernent la classe VisualState Manager. Elle possde la mthode statique GoToState qui permet dafficher ltat visuel de nimporte quel contrle. Le premier argument est le contrle dont vous souhaitez afficher ltat. Dans notre cas, nous souhaitons atteindre ltat du UserControl racine, soit this, linstance de la classe MainPage. Le second paramtre est la chane de caractres correspondant au nom de ltat. Le dernier argument permet de spcifier si nous souhaitons utiliser ou non une transition anime. Toutefois, cette option ne concerne pas les transitions reposant sur un objet Storyboard spcifique. Une transition personnalise sera joue quelle que soit la valeur du dernier argument car ce nest pas lobjet State qui dfinit la dure danimation (via la proprit GeneratedDuration) mais, dans ce cas, le Storyboard. Pour finaliser linteraction utilisateur, il va falloir crer un compte rebours. Ce dernier sera gr par une instance dobjet de type DispatcherTimer. Lide consiste rinitialiser le compte rebours chaque fois que la souris bouge. Lorsque la souris ne bouge plus, le compte rebours grne les secondes. Au bout de deux secondes dinactivit, on dclenche lanimation vers ltat HiddenPlayer. On occulte donc celui-ci.
//Ajouter lespace de noms Threading //pour instancier DispatcherTimer using System.Windows.Threading; namespace PlayerVideo

public partial class MainPage: UserControl { //on cre un mtronome DispatcherTimer Dt = new DispatcherTimer();

Chapitre 7

Boutons personnaliss

201

//on lui dfinit un intervalle de temps de deux secondes Dt.Interval=TimeSpan.FromSeconds(2); public MainPage() { InitializeComponent(); //Par dfaut le lecteur est cach VisualStateManager.GoToState(this, "HiddenPlayer", true); //on coute lvnement MouseMove LayoutRoot.MouseMove += LayoutRoot_MouseMove; //on coute le mtronome (DispatcherTimer) Dt.Tick += Dt_Tick;

//Chaque fois que celui-ci est diffus //donc lorsque la souris bouge void LayoutRoot_MouseMove(object sender, MouseEventArgs e) { //on utilise le gestionnaire dtats visuels //afin dafficher ltat VisiblePlayer VisualStateManager.GoToState(this, "VisiblePlayer", true); //puis on rinitialise le compte rebours deux secondes Dt.Start();

//lorsque les deux secondes sont atteintes //cest--dire lorsque la souris //ne bouge plus depuis deux secondes void Dt_Tick(object sender, EventArgs e) { //on cache le lecteur vido grce la classe //VisualStateManager VisualStateManager.GoToState(this, "HiddenPlayer", true); //on stoppe le mtronome pour optimiser les performances Dt.Stop();

Testez et compilez lapplication, les transitions sont fluides et agrables. Les contrles du lecteur vido ne sont accessibles que lorsque lutilisateur en a rellement besoin. Le lecteur est donc contextuel, ce qui est encore la meilleure manire de concevoir lexprience utilisateur. Vous trouverez cet exercice dans: chap7/PlayerVideo_AppAnime.zip.

7.5 Le bouton interrupteur ou ToggleButton


Nous allons maintenant personnaliser un bouton de type interrupteur (ToggleButton). Vous pouvez considrer ce type de bouton comme une case cocher (CheckBox) car seule leur forme diffre. Ces deux composants possdent trois tats visuels supplmentaires par rapport un bouton traditionnel : Checked, Unchecked et Indeterminate. Habituellement, on trouve ces boutons dans les formulaires. Grce au XAML et la personnalisation de contrle utilisateur, nous utiliserons le comportement on/off de ce type de bouton pour alterner entre la lecture de la vido et sa mise en pause.

202

Partie II

Interactivit et cration graphique

7.5.1 Crer le bouton


Dans larbre visuel et logique de lapplication, slectionnez la grille nomme PlayPause, cliquezdroit dessus et choisissez loption Make Into Control Dans la liste affiche, slectionnez Tog gleButton, nommez le style PlayPauseStyle. Vous pouvez vous aider du champ de recherche pour afficher le bouton de type ToggleButton (voir Figure7.34). Confirmez ensuite la cration du style en cliquant sur OK.
Figure7.34
Cration du style PlayPause.

Commencez par cacher le composant ContentPresenter en passant sa proprit Visibility sur Collapsed. Vous utiliserez ce composant ultrieurement pour indiquer une information lutilisateur. Vous allez faire apparatre le reflet lors du survol de la souris uniquement. Pour cela, slectionnez ltat Normal et crez une animation de votre choix pour faire disparatre le reflet de manire lgante. Vous pouvez, par exemple, concevoir une animation personnalise sur les dgrads simulant limpact lumineux et le reflet. Ceux-ci correspondent respectivement aux valeurs de la proprit Fill pour les composants Ellipse RefletHaut et RefletBase. Crer une animation personnalise pour ltat Normal vous simplifiera grandement la tche. Il suffit de faire disparatre les reflets dj prsents. Pour les autres tats, vous pouvez utiliser des transitions gnriques afin dallger au maximum votre travail (voir Figure7.35). Testez et compilez le projet.
Figure7.35
Exemple danimation de disparition pour ltat Normal.

Chapitre 7

Boutons personnaliss

203

7.5.2 Le systme dagencement fluide


Les trois tats supplmentaires, propres au ToggleButton et dj voqus, sont prsents au sein dun groupe dtats nomm CheckStates. Nous navons pas besoin dutiliser ltat Indetermi nate car nous avons besoin dun interrupteur deux tats. Lorsque le bouton sera coch, nous ferons apparatre la grille nomme IconePause, indiquant ainsi lutilisateur que la vido est en cours de lecture et quil doit appuyer sur le bouton pour la mettre en pause. loppos, lorsque le bouton sera dcoch, la vido sera sur pause et la grille IconePlay sera visible, indiquant lutilisateur quil peut la remettre en lecture tout instant. Slectionnez ltat Checked et affectez la proprit Visibility de IconePause Visible, ensuite passez la proprit Visibility de la grille IconePlay Collapsed. Compilez et testez votre projet, les icnes apparaissent alternativement lune et lautre lors de chaque clic gauche de la souris. Toutefois, il ny a pas de transitions fluides entre les tats coch et non coch. Cela est trs simple rsoudre grce une fonctionnalit prsente depuis Silverlight3, nomme systme dagencement fluide ou Fluid Layout System. Les proprits qui ne sont pas de type Point, Double ou Color ne sont pas interpoles et subissent des animations de type Discreet. Le systme dagencement fluide rsout en partie cette limitation en gnrant une animation de ce que pourrait tre linterpolation, la plus logique, de telles proprits. Par exemple, vous pourriez dcider quun des enfants dune grille soit align gauche dans un tat visuel, puis droite dans un autre tat visuel. Habituellement, une transition fluide serait impossible car lalignement est gr par la proprit Horizontal Alignment qui est une numration. Toutefois, le systme dagencement fluide permet de simuler ce que serait lanimation la plus logique entre les deux positions dalignement. Commencez par dfinir une transition gnrique dune dure de6/10 de seconde pour le groupe dtat CheckStates. Cliquez sur licne reprsentant des vaguelettes ( ) situe droite de ltat CheckStates afin dactiver le systme dagencement fluide. Compilez et testez nouveau le bouton de lecture/pause. Cette fois une animation est joue; elle ntait pas vraiment facile prvoir, on a limpression dun redimensionnement des icnes permettant de les faire apparatre ou disparatre. En un seul clic, nous avons permis de simuler lanimation de la proprit Visibility qui nest pourtant pas interpolable. Du ct XAML, le code est assez simple:
<VisualStateGroup x:Name="CheckStates" ic:ExtendedVisualStateManager.UseFluidLayout="True"> <VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="00:00:00.6"/> </VisualStateGroup.Transitions> <VisualState x:Name="Unchecked"/> <VisualState x:Name="Indeterminate"/> <VisualState x:Name="Checked"> <Storyboard> <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="IconePause" Storyboard.TargetProperty="(UIElement.Visibility)"> <DiscreteObjectKeyFrame KeyTime="00:00:00"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="IconePlay"

204

Partie II

Interactivit et cration graphique

Storyboard.TargetProperty="(UIElement.Visibility)"> <DiscreteObjectKeyFrame KeyTime="00:00:00"> <DiscreteObjectKeyFrame.Value> <Visibility>Collapsed</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup>

La proprit UseFluidLayout possde la valeur true, cest celle-ci qui permet dactiver le gestionnaire dtats visuels. Vous remarquez cependant que la proprit Visibility nest pas interpole car elle subit des cls danimation de type DiscreteObjectKeyFrame. Lanimation relle ressemblant un redimensionnement (RenderTransform) nous est compltement occulte. Cest le gestionnaire dtats qui gre cette animation en arrire-plan. Il ne vous reste plus qu crer un nouveau comportement pour le bouton de lecture, qui indiquera lapplication de naviguer vers ltat Black lors de son survol (voir section7.4.3.3). Dun point de vue design, le lecteur vido est termin, vous finaliserez son dveloppement au Chapitre12, ddi aux composants personnaliss. Vous trouverez le lecteur vido dans: chap7/ PlayerVideo_ToggleButton.zip. Nous ne finalisons pas le lecteur vido dans ce chapitre pour diverses raisons. Lune delles est que la cration du code logique pour ce type dapplication repose grandement sur la notion de programmation vnementielle. Depuis le dbut du livre, nous avons voqu de nombreuses reprises ce concept sans vraiment ltudier. Cette notion est trs importante au sein des langages de haut niveau tels que C#. Nous allons donc laborder au Chapitre8 et voir comment une utilisation adquate de ses concepts peut nous faciliter grandement la vie.

8
Interactivit et modle vnementiel
Le concept dinteractivit repose sur la notion de stimulus, et dune ou plusieurs actions invoques en rponse celui-ci. Ce principe, pour les applications, est essentiellement li lutilisateur, il fait appel la logique vnementielle. Dans ce chapitre, vous tudierez en profondeur les mcanismes du modle vnementiel dans Silverlight, pour le langage C#. Ainsi, vous apprendrez la diffusion, la souscription et le dsabonnement dvnements. Puis, vous verrez comment optimiser votre code grce au couplage faible et la propagation des vnements. Pour finir, vous aborderez la cration de comportements interactifs personnaliss afin de faciliter et damliorer le flux de production entre designers et dveloppeurs.

8.1 Les fondements du modle vnementiel


Le modle vnementiel, la base de tout dveloppement orient utilisateur, est souvent reli aux langages de haut niveau, tels que C#. Il occupe galement une place important au sein des technologies asynchrones comme Silverlight ou Ajax. Il correspond pleinement la notion de connexion distante sur laquelle repose Internet; sur le Web, rien nest synchrone. La dure coule entre linstant o vous cliquez sur un lien et le moment o la nouvelle page saffiche varie de manire impossible prvoir. Cette variation sexplique assez bien : les donnes sont distantes et doivent donc tre tlcharges avant dtre affiches. Le dbit des lignes Internet, la frquentation dun site ou loccupation mmoire comme processeur dun serveur un instant t ne sont jamais identiques. La logique vnementielle prend tout son sens sur ce type de rseau. Il en va de mme pour les interactions utilisateur. Le dveloppeur ne peut jamais prvoir quand un utilisateur va cliquer sur un bouton ou quand il va bouger la souris. Il peut, en revanche, dcider dun comportement adopter lorsque cela arrivera. Pour cela, il utilise les outils fournis par le modle vnementiel, propres chaque langage. Nous allons maintenant essayer de comprendre lorigine et les mcanismes du modle vnementiel.

206

Partie II

Interactivit et cration graphique

8.1.1 Le pattern Observateur


Les modles de conception (ou design patterns) sont ns la fin des annes80 avec lavnement de la programmation oriente objet (POO). cette poque, la majeure partie, soit99,99%, des problmes de conception avait dj t rsolue par les dveloppeurs en matire de POO et navait plus rien doriginale. Les patterns sont ns du besoin de formaliser des solutions gnriques rpondant aux diffrentes problmatiques rencontres. Ds1991, quatre dveloppeurs, connus sous le nom de "Gang of Four", crivent le premier ouvrage de rfrence sur ce sujet: Design Patterns: Elements of Reusable Object Oriented Software. Il sagit dErich Gamma, Richard Helm, Ralph Johnson et John Vlissides. Ces concepteurs formalisent ainsi les bonnes pratiques de conception oriente objet rpondant la majorit des problmatiques. Le modle Observateur, ou Observer en anglais est lun dentre eux, il fait partie des patterns lis la gestion du comportement des objets. Il dfinit une relation de un plusieurs objets, et permet lorsquun objet change dtat, de le notifier plusieurs autres qui en dpendent. Ceux-ci peuvent ainsi ragir ou tre mis jour automatiquement. Pour que les objets soient notifis ou informs des changements, ils doivent souscrire auprs de lobjet qui diffuse les notifications. Ce modle de conception repose donc sur deux notions essentielles: la souscription et la diffusion de notifications. Cest exactement le principe de la programmation vnementielle. Dans ce contexte, une notification est appele vnement. Prenons un exemple de la vie courante: 1. Vous dsirez acheter ou louer un bien immobilier. Vous souhaitez tre inform lorsquun nouvel appartement ou quune nouvelle maison est disponible lachat ou la location pour ne pas vous dplacer pour rien. 2. Vous souscrivez aux lettres dinformations de plusieurs agences immobilires. Vous vous abonnez en fait aux vnements "nouvel appartement louer" et "nouvel appartement acheter" diffuss par les agences immobilires. 3. Lorsquune agence reoit une nouvelle offre de location ou dachat, elle vous en fait part. Pourquoi? Simplement parce que vous tes abonn. Les non abonns ne sont pas notifis de lvnement. 4. Vous pouvez ragir diffremment en fonction des caractristiques du bien immobilier. Le descriptif de celui-ci est contenu le plus souvent dans un objet vnementiel, par exemple, la lettre dinformation. 5. Lorsque vous avez trouv le bien adquat et que vous lavez acquis, vous vous dsabonnez car il nest plus ncessaire de chercher. Nous venons de dcrire exactement le principe du modle vnementiel. Chaque agence immobilire possde plusieurs abonns et diffuse des vnements de type "nouveau bien disponible" chacun deux. Le diffuseur est galement appel sujet, les abonns sont appels couteurs (voir Figure8.1). Nous allons maintenant dmontrer en quoi ces principes sont souples et faciles maintenir travers une introduction au couplage faible.

Chapitre 8

Interactivit et modle vnementiel

207

Figure8.1
Principes du pattern Observateur travers lexemple dannonces immobilires.

8.1.2 Introduction au couplage faible


Lorsque deux objets nont pas besoin de se connatre pour collaborer ensemble, on dit quils sont faiblement coupls, cest--dire quils nentretiennent pas de relations spcifiques fortes. Une relation forte signifie quun objet fait explicitement rfrence un autre objet pour tre fonctionnel. Le couplage faible reprsente exactement la nature des relations entretenues par les couteurs et les diffuseurs dvnements:

Le sujet (ou diffuseur) na pas besoin de connatre les objets qui coutent ses vnements diffuss. Ainsi, il est possible de supprimer des couteurs sans que le diffuseur ne soit drang dans son fonctionnement. De mme, il est possible dajouter des couteurs tout instant en cours dexcution nimporte quel diffuseur. Les couteurs ou les diffuseurs peuvent avoir dautres activits que la souscription ou la diffusion dvnements de manire totalement indpendante. Modifier un objet abonn ou diffuseur ne change pas les relations ou le fonctionnement de chacun des acteurs du processus.

Lavantage principal du couplage faible est de permettre des conceptions souples et faciles maintenir. Il est possible de concevoir des combinaisons dcouteurs-diffuseurs plus complexes, sans

208

Partie II

Interactivit et cration graphique

mettre en danger le fonctionnement ou la cohrence des liaisons. Par exemple, vous pouvez vous abonner aux lettres dinformations de plusieurs agences immobilires (voir Figure8.2). De plus, la suppression dun couteur ou dun sujet naffecte en rien le fonctionnement de lun ou de lautre. Nous verrons la section8.2 comment dsabonner un couteur lexcution.
Figure8.2
Un schma plus complexe.

8.1.3 Souscrire un vnement en C#


Dans la majorit des conceptions, lcouteur est une mthode. Ainsi, dfinir un couteur dvnements consiste dfinir une mthode sexcutant chaque diffusion de lvnement. Toutefois, nous allons voir que ces mthodes sont particulires. Si vous dveloppez pour le Web en Java Script ou ActionScript, vous avez pu rencontrer lcriture suivante:
uneInstance.addEventListener("vnement", couteur );

Lcriture en C# est assez comparable. Le code gnrique ci-dessous permet dcouter un vnement en langage C#:
UneInstance.Evenement += Ecouteur; //lcouteur est une mthode void Ecouteur ( Diffuseur, ObjetEvenementiel) { //Fait quelque chose }

Chapitre 8

Interactivit et modle vnementiel

209

Loprateur daffectation += permet dajouter la mthode la liste des couteurs. En pratique, dclencher la mthode ClickButton chaque fois que lutilisateur clique sur un bouton nomm MonBouton est ralis comme ci-dessous:
MonBouton.Click += new RoutedEventHandler(ClickButton); void ClickButton ( object sender, RoutedEventArgs e) { //Fait quelque chose }

Voici la traduction en "bon franais" de ce qui est ralis: lcouteur, reprsent par la mthode ClickButton, souscrit lvnement Click de MonBouton. Lorsque lutilisateur clique sur le bouton durant lexcution, ce dernier diffuse lvnement Click. La mthode ClickButton est alors invoque car elle fait partie des abonns lvnement Click de MonBouton. Nous allons maintenant mettre en pratique cet exemple.

8.1.4 Cas pratique


Ouvrez le projet nomm PlayerVideo_ToggleButton ralis au Chapitre7. Vous pouvez galement le trouver dans larchive PlayerVideo_ToggleButton.zip du dossier du chap8. Sauvegardez-en une copie nomme PlayerVideo_Evenement via le menu File dExpression Blend, puis ouvrez cette copie; cela vous vite de modifier le projet original. Nous allons remplacer les comportements (ou Behaviors) dfinis dans Expression Blend, pour naviguer dun tat visuel de lapplication un autre, par du code C#. Commencez par supprimer tous les comportements que vous trouverez sur les boutons (dont le ToggleButton). Nommez le ToggleButton de lecture/pause PlayPauseBtn et le conteneur Canvas des contrles ControlsRingArea. Ensuite, dans le code C#, ajoutons lquivalent de linteractivit utilisateur produite par les comportements. Pour cela, il faut couter chaque bouton de contrle du lecteur vido sparment comme montr dans le code ci-dessous:
public MainPage() { InitializeComponent(); //Par dfaut le lecteur est cach VisualStateManager.GoToState(this, "HiddenPlayer", true); //on coute lvnement MouseMove LayoutRoot.MouseMove += new MouseEventHandler(LayoutRoot_MouseMove); Dt.Tick += new EventHandler(Dt_Tick); #region gestion des transitions vers les tats de #couleurs ColorStates Group ForwardBtn.MouseEnter += new MouseEventHandler(ForwardBtn_MouseEnter); BackwardBtn.MouseEnter += new MouseEventHandler(BackwardBtn_MouseEnter); VolumeDownBtn.MouseEnter += new MouseEventHandler (VolumeDownBtn_MouseEnter); VolumeUpBtn.MouseEnter += new MouseEventHandler(VolumeUpBtn_MouseEnter);

210

Partie II

Interactivit et cration graphique

PlayPauseBtn.MouseEnter += new MouseEventHandler (PlayPauseBtn_MouseEnter); ControlsRingArea.MouseLeave += new MouseEventHandler (ControlsRingArea_MouseLeave); #endregion } ... void ControlsRingArea_MouseLeave(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Normal", true); } void VolumeUpBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Purple", true); } void VolumeDownBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Cyan", true); } void BackwardBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Orange", true); } void ForwardBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Green", true); } void PlayPauseBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Black", true); }

NOTE INFO

Le code gnr est un peu verbeux, vous pourriez lviter en dfinissant lcoute de lvnement en langage dclaratif XAML via le panneau Properties. Toutefois, cela peut se rvler plus problmatique quautre chose. Le dveloppeur nira pas naturellement vers cette solution propre aux designers interactifs. Si lcoute est dfinie dans le XAML, elle est partiellement cache au dveloppeur car un fichier dclaratif peut tre fastidieux explorer. Cela pourrait engendrer des pertes de performance ou des conflits si le dveloppeur na pas pris connaissance de lcoute dun vnement.

Testez et compilez le lecteur vido, vous obtenez exactement la mme interactivit quavec les comportements. Vous trouverez plusieurs pistes la section8.5 afin de choisir entre comportements interactifs et programmation vnementielle C#. Ce choix sera fonction de la situation et du contexte de production que vous rencontrerez. Il est tout de mme utile de prciser que lavantage de la programmation vnementielle reste le contrle total des performances par le dveloppeur. En effet, ce dernier peut, tout moment, ajouter ou supprimer lcoute dun vnement lexcu-

Chapitre 8

Interactivit et modle vnementiel

211

tion. Ainsi, lapplication ne consomme que la mmoire et la ressource processeur qui lui est utile un instant donn. Nous allons maintenant tudier plusieurs techniques doptimisation.

8.2 Supprimer lcoute dun vnement


La premire technique consiste tout simplement arrter lcoute dun vnement lorsquil nest plus utile dy ragir.

8.2.1 Principe
Dans la vie relle, cest une tche courante et saine. Dans lexemple de lagence immobilire, lorsque lun des abonns aux lettres dinformations a trouv un appartement ou une maison, il ne souhaite plus tre inform des nouvelles offres. Traduire cette notion en langage C# est simple: loppos de loprateur daffectation += qui signifie ajouter, supprimer se traduit par loprateur -=. Le code ci-dessous montre lcriture complte:
UneInstance.Evenement -= Ecouteur;

Ainsi, pour supprimer lcoute dun bouton, vous pouvez crire:


MonBouton.Click -= ClickButton;

Pour viter toute confusion, vous pouvez traduire ce code en franais par : lcouteur Click Button se dsabonne de lvnement Click diffus par MonBouton. Il ne faut pas vous imaginer que vous supprimez la mthode ClickButton de cette manire. Dans les faits, vous supprimez juste la rfrence ClickButton dans la liste des couteurs de lvnement Click (voir Figure8.3). Vous pourrez donc souscrire nouveau ClickButton cet vnement plus tard si besoin. Si la souscription auprs dvnements diffuss est importante, le dsabonnement lest tout autant pour diverses raisons. La premire est de contrler linteractivit. La seconde raison est lie la gestion des ressources. couter un vnement consomme de la mmoire, parfois inutilement. Par exemple, couter le dplacement de la souris occupe beaucoup de ressources processeur. Ainsi, il est fortement conseill de supprimer lcoute de lvnement MouseMove quand vous nen avez plus besoin. Le langage C# est dit gr car lallocation des ressources mmoire nest pas directement gre par le dveloppeur, mais par le ramasse-miettes ou Garbage Collector. Toutefois, pour que ce dernier libre les ressources le plus tt possible, il est important de lui prsenter des objets qui ne sont plus rfrencs par dautres, lorsque vous nen avez plus besoin. Arrter la souscription dun vnement entre dans ce cadre.

212

Partie II

Interactivit et cration graphique

Figure8.3
Suppression dun vnement.

8.2.2 Un cas concret dutilisation


Dans cet exemple, nous allons utiliser le projet nomm PlayerVideo_Optimisations. Il se trouve dans larchive PlayerVideo_Optimisations.zip du dossier chap8 des exemples. Lide de ce projet est simple : deux nouveaux tats permettent de positionner le lecteur vido soit au centre de la fentre soit en bas. Pour changer de position dynamiquement, il suffit de cliquer alternativement sur le bouton interrupteur, nomm FixedPositionBtn. Lorsque les contrles utilisateur ne sont pas placs au centre, il ny a pas deffet de disparition au bout de deux secondes. Pour raliser cette tche, le dveloppeur a cout les vnements Checked et Unchecked du bouton Fixed PositionBtn. Ainsi, il peut la fois arrter le compte rebours de disparition et dplacer les contrles utilisateurs vers le bas ou le centre de lapplication. De mme, il teste lors du dplacement de la souris (vnement MouseMove) si le bouton est coch ou dcoch. Ainsi, il peut galement arrter ou lancer le compte rebours en fonction du ToggleButton nomm Fixe PositionBtn. Voici le code logique correspondant ce dveloppement:
public MainPage() { LayoutRoot.MouseMove += new MouseEventHandler(LayoutRoot_MouseMove); FixePositionBtn.Checked += new RoutedEventHandler (FixePositionBtn_Checked); FixePositionBtn.Unchecked += new RoutedEventHandler (FixePositionBtn_Unchecked);

Chapitre 8

Interactivit et modle vnementiel

213

} void FixePositionBtn_Unchecked(object sender, RoutedEventArgs e) { VisualStateManager.GoToState(this, "Center", true); //la position est centre car le bouton est dcoch, //on cache donc automatiquement les contrles utilisateur //au bout de deux secondes Dt.Start(); } void FixePositionBtn_Checked(object sender, RoutedEventArgs e) { VisualStateManager.GoToState(this, "Bottom", true); //le bouton fixe position est coch, //on ne fait donc pas disparatre le lecteur //en stoppant le compte rebours de disparition Dt.Stop(); } //lorsque la souris bouge void LayoutRoot_MouseMove(object sender, MouseEventArgs e) { //on teste la position centre ou basse des contrles //utilisateur, si la position est basse on arrte //le compte rebours sinon on le relance if ((bool)FixePositionBtn.IsChecked) Dt.Stop(); else Dt.Start(); //on utilise le gestionnaire dtat visuel //afin dafficher ltat VisiblePlayer VisualStateManager.GoToState(this, "VisiblePlayer", true); }

Ce code prsente plusieurs problmatiques. Tout dabord, la logique concernant larrt du compte rebours de disparition est rpartie dans trois couteurs diffrents. La logique de la mthode Position Btn en dur. Aprs LayoutRoot_MouseMove ne devrait pas tester ltat du bouton Fixe tout, les instructions ont toutes le mme rle: relancer le compte rebours de disparition chaque fois que la souris bouge, et effectuer une transition vers ltat VisiblePlayer si besoin. Cela empche le fondu des contrles lorsque lutilisateur a une quelconque activit. La seconde problmatique concerne les performances. Le fait que lvnement MouseMove de LayoutRoot continue dtre cout lorsque nous positionnons le lecteur en bas de la fentre consomme inutilement des ressources processeur et mmoire. Comme nous ne souhaitons pas deffet de disparition dans ltat Bottom, lcoute de MouseMove qui gre cet effet devient superflue sur cet tat. Autant supprimer cette coute lorsque le bouton FixePositionBtn est coch, puis se rabonner lvnement uniquement lorsque le bouton est dcoch (indiquant ltat centr). La dsinscription et la souscription de lvnement MouseMove au bon moment gnrent un code plus propre et moins gourmand en ressources:
public MainPage() { LayoutRoot.MouseMove += new MouseEventHandler(LayoutRoot_MouseMove); FixePositionBtn.Checked += new RoutedEventHandler( FixePositionBtn_Checked);

214

Partie II

Interactivit et cration graphique

FixePositionBtn.Unchecked += new RoutedEventHandler (FixePositionBtn_Unchecked); } void FixePositionBtn_Unchecked(object sender, RoutedEventArgs e) { VisualStateManager.GoToState(this, "Center", true); //la position est centre car le bouton est dcoch, //on cache donc automatiquement les contrles utilisateur //au bout de deux secondes Dt.Start(); //On coute lvnement MouseMove que lorsque cest ncessaire LayoutRoot.MouseMove += LayoutRoot_MouseMove; } void FixePositionBtn_Checked(object sender, RoutedEventArgs e) { VisualStateManager.GoToState(this, "Bottom", true); //le bouton fixe position est coch, //on ne fait donc pas disparatre le lecteur //en stoppant le compte rebours de disparition Dt.Stop(); //On supprime la souscription de lcouteur lorsquil nest pas //ncessaire de faire disparatre les contrles LayoutRoot.MouseMove -= LayoutRoot_MouseMove; } //lorsque la souris bouge void LayoutRoot_MouseMove(object sender, MouseEventArgs e) { //Il ny a plus besoin de tester ltat du bouton FixePositionBtn //ici car lcoute de lvnement MouseMove est dsactive avant //on utilise le gestionnaire dtats visuels //afin dafficher ltat VisiblePlayer VisualStateManager.GoToState(this, "VisiblePlayer", true); Dt.Start(); }

Testez en compilant votre projet. Pour mettre en valeur loptimisation apporte par ce code, vous pouvez utiliser le mode "debug" de Visual Studio. Vous pourrez ainsi crire un message en fentre de sortie chaque fois que la souris se dplace:
Using System.Diagnostics; Int nMessage =0; //lorsque la souris bouge void LayoutRoot_MouseMove(object sender, MouseEventArgs e) { //Il ny a plus besoin de tester ltat du bouton FixePositionBtn ici //car lcoute de lvnement MouseMove est dsactive avant //On crit un message lorsque la souris bouge Debug.WriteLine("la souris bouge pour la {0}me fois",++nMessage); //on utilise le gestionnaire dtat visuel //afin dafficher ltat VisiblePlayer

Chapitre 8

Interactivit et modle vnementiel

215

VisualStateManager.GoToState(this, "VisiblePlayer", true); Dt.Start(); }

Vous constaterez quen position basse, le lecteur ne consomme plus du tout de ressources. Lvnement MouseMove nest plus capt par lcouteur LayoutRoot_MouseMove. Les messages en fentre de sortie ne sont donc plus incrments. Nous pouvons encore amliorer notre code et optimiser notre application grce au couplage faible.

8.3 Le couplage faible en pratique


Comme nous lavons vu prcdemment, le couplage faible est avant tout le rsultat dune bonne pratique du dveloppement orient objet. Cest une manire de crer des liens faibles entre les objets: la modification et la suppression dobjets collaborent de concert et nimpactent pas les objectifs de fonctionnement propres chacun.

8.3.1 Principe
Pour le modle vnementiel, le couplage faible est ralis grce aux deux paramtres rcuprs par les mthodes dcoute. Le premier argument reprsente une rfrence au diffuseur de lvnement, il est de type object car on ne peut savoir lavance quel est le type de lobjet diffuseur. Ceci pour la bonne raison que des objets de types diffrents peuvent diffuser le mme vnement. Par exemple, lvnement Click peut tre diffus par les composants hritant de la classe ButtonBase, soit RadioButton, CheckBox, ToggleButton ou Button. Lvnement Loaded est diffusable, quant lui, par toutes les classes hritant de UIElement. Le fait de typer object nous permet donc de nous affranchir du type diffuseur puisque tous les types ont pour origine object. Le deuxime argument est nomm objet vnementiel. Il donne des informations complmentaires sur lvnement diffus comme la position linstant prcis du clic de la souris. Grce ces deux paramtres, il nest nul besoin de rfrencer lobjet diffuseur en dur. Dans le code ci-dessous, vous trouverez deux manires de raliser la mme tche. Voici la mauvaise manire de rcuprer la valeur dun Slider dont la valeur vient de changer:
//On diffuse lvnement ValueChanged chaque fois que lutilisateur //modifie la position du curseur MonSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double> (MonSlider_ValueChanged); //la mthode dcoute se dclenche chaque fois que lutilisateur //modifie la position du curseur void MonSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs <double> e) { //lorsque cest le cas on trace en fentre //de sortie la nouvelle valeur Debug.WriteLine("nouvelle valeur de MonCurseur: "+MonSlider.Value); }

Ce nest pas la bonne manire de procder car MonSlider est rfrenc fortement dans la mthode dcoute. Voici une autre manire de procder qui prsente lavantage de ne pas faire directement rfrence au Slider:

216

Partie II

Interactivit et cration graphique

void MonSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs <double> e) { if ( (sender as Slider)!=null) Debug.WriteLine("nouvelle valeur de MonCurseur: "+ (sender as Slider).Value); }

Avec cette mthode, le dveloppeur utilise largument nomm sender faisant rfrence lobjet diffuseur. Comme sender est de type object, il nous faut transformer son type grce au mot-cl as. Ce mot-cl permet de renvoyer null si la conversion nest pas possible. Avec une conversion de type explicite note (Slider)sender, nous serions susceptible davoir une erreur leve lexcution et nous serions obligs dutiliser une instruction try/catch consommant plus de ressources en cas d'exception leve. Une seconde manire de procder consiste utiliser lobjet vnementiel pour rcuprer la nouvelle valeur ainsi que lancienne:
void MonSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs <double> e) { Debug.WriteLine("ancienne valeur de MonCurseur: "+e.OldValue); Debug.WriteLine("nouvelle valeur de MonCurseur: "+e.NewValue); }

Ces deux mthodes ne font pas rfrence au Slider directement. Ainsi, la mthode couteur MonSlider_ValueChanged pourrait souscrire lvnement ValueChanged diffus par plusieurs objets Slider:
//On cre plusieurs contrles Slider Slider MonSlider1 = new Slider(){Name="Slider1"}; Slider MonSlider2 = new Slider(){Name="Slider2"}; Slider MonSlider2 = new Slider(){Name="Slider3"}; //On dfinit le mme couteur pour chacun deux MonSlider1.ValueChanged += new RoutedPropertyChangedEventHandler<double> (MonSlider_ValueChanged); MonSlider2.ValueChanged += new RoutedPropertyChangedEventHandler<double>(MonSlider_ValueChanged); MonSlider3.ValueChanged += new RoutedPropertyChangedEventHandler<double> (MonSlider_ValueChanged); void MonSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs <double> e) { Debug.WriteLine("ancienne valeur de "+(sender as Slider).Name+": "+e.OldValue); Debug.WriteLine("nouvelle valeur de "+(sender as Slider).Name+": "+e.NewValue); }

Dans le code ci-dessus, vous rcuprez le nom du Slider dont la valeur a t modifie par lutilisateur et cela de manire compltement dynamique. Bien sr, lintrt dun tel code est relatif la tche de chaque Slider. Si ceux-ci font sensiblement la mme chose, le couplage faible apporte un rel confort de conception et factorise votre code.

Chapitre 8

Interactivit et modle vnementiel

217

8.3.2 Simplifier le code du lecteur vido


Nous allons appliquer ce concept notre lecteur vido. Vous le trouverez dans les exemples du livre: chap8/PlayerVideo_Couplage.zip. Ouvrez le projet au sein de Blend et de Visual Studio. Notre code est pour linstant redondant, peu optimis et inlgant. En voici un exemple criant: si vous voyez un jour ce type de code, cest quil y a une erreur de conception :
//Gre les transitions vers les tats de couleurs ColorStates Group ForwardBtn.MouseEnter += new MouseEventHandler(ForwardBtn_MouseEnter); BackwardBtn.MouseEnter += new MouseEventHandler(BackwardBtn_MouseEnter); VolumeDownBtn.MouseEnter += new MouseEventHandler(VolumeDownBtn_MouseEnter); VolumeUpBtn.MouseEnter += new MouseEventHandler(VolumeUpBtn_MouseEnter); PlayPauseBtn.MouseEnter += new MouseEventHandler(PlayPauseBtn_MouseEnter); ControlsRingArea.MouseLeave += new MouseEventHandler (ControlsRingArea_MouseLeave); void ControlsRingArea_MouseLeave (object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Normal", true); } void VolumeUpBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Purple", true); } void VolumeDownBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Cyan", true); } void BackwardBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Orange", true); } void ForwardBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Green", true); } void PlayPauseBtn_MouseEnter(object sender, MouseEventArgs e) { VisualStateManager.GoToState(this, "Black", true); }

Comme vous le constatez, chaque couteur fait exactement la mme chose. Lorsquun objet est survol, les couteurs excutent une transition vers un tat de couleur spcifique via le gestionnaire dtats visuels. Un seul couteur pourrait raliser tout ce travail simplement. Si les boutons survols contenaient chacun un indice de ltat de couleur cibl, il deviendrait simple de rfrencer le diffuseur et de pointer vers le bon tat de couleur. Nous pourrions renommer chaque bouton dune autre manire pour faire rfrence ltat cibl.

218

Partie II

Interactivit et cration graphique

Toutefois, ce nest pas une bonne pratique car le nom dun objet indique avant tout sa fonctionnalit et non la forme ou la transition laquelle il fait rfrence. Le mieux est dutiliser la proprit Tag (de type Object) propre tout objet FrameworkElement et dy stocker le nom de ltat de couleur cibl. Dans Blend, slectionnez chaque bouton les uns aprs les autres et entrez le nom de ltat de couleur cibl pour chacun. Par exemple, pour le bouton ForwardBtn, dpliez compltement le panneau Common Properties, vous pouvez entrer la chane de caractres Green dans le champ de saisie Tag (voir Figure8.4). Noubliez pas de modifier galement la proprit Tag de lobjet ControlsRingArea qui permettra de revenir ltat visuel Normal.
Figure8.4
Configuration de la proprit Tag.

Une fois que vous avez finalis cette partie, vous pouvez simplifier le code existant en ne dfinissant quune seule mthode dcoute:
//Gre les transitions vers les tats de couleurs ColorStates Group ForwardBtn.MouseEnter += new MouseEventHandler(GotoColorState); BackwardBtn.MouseEnter += new MouseEventHandler(GotoColorState); VolumeDownBtn.MouseEnter += new MouseEventHandler(GotoColorState); VolumeUpBtn.MouseEnter += new MouseEventHandler(GotoColorState); PlayPauseBtn.MouseEnter += new MouseEventHandler(GotoColorState); PlayPauseBtn.MouseEnter += new MouseEventHandler(GotoColorState); ControlsRingArea.MouseLeave += new MouseEventHandler(GotoColorState); void GotoColorState(object sender, MouseEventArgs e) { //on vrifie que lobjet cliqu est de type ButtonBase if (sender as FrameworkElement!= null) { var TargetedState = (sender as FrameworkElement).Tag; VisualStateManager.GoToState(this, TargetedState.ToString(), true); } }

Chapitre 8

Interactivit et modle vnementiel

219

Transtyper un objet vers FrameworkElement permet de rcuprer la proprit Tag pour nimporte quel type de contrles Silverlight. Comme lvnement est diffus par trois types diffrents dobjets (Canvas, Button, ToggleButton), utiliser FrameworkElement dont ces objets hritent est pratique. Dans le code prcdent, chaque vnement est cout par la mme mthode nomme Goto ColorState. Grce au couplage faible entretenu entre lcouteur et le diffuseur, nous sommes capables de rcuprer dynamiquement la valeur de la proprit Tag. Celle-ci tant type Object, il nous faut utiliser la mthode ToString pour rcuprer la valeur sous forme de chane de caractres.
NOTE INFO

La proprit Tag est de type Object, elle peut donc recevoir nimporte quel type dobjet. Comme nous ne sommes pas dans un langage dynamique, tel que JavaScript ou Action Script, il nest pas possible dajouter dynamiquement des proprits aux objets daffichage du framework. La proprit Tag permet de contourner cette limitation tout en centralisant le contenu que vous souhaitez ajouter aux objets. Selon les coles, et notamment pour les adeptes de la POO, ajouter dynamiquement des proprits aux objets natifs nest pas une bonne pratique de conception. Cela gnre un code souvent difficile maintenir mme si cela permet parfois plus de souplesse de dveloppement dans certaines situations.

Vous pouvez trouver le lecteur finalis dans les exemples du livre: chap8/PlayerVideo_CouplageFinal.zip.

8.3.3 Affectation dynamique danimations


Nous allons voir comment raffecter une animation dynamiquement en fonction de lobjet diffuseur. Ouvrez le projet nomm AnimRebond_CouplageDynamic (). Trois balles sont prsentes sur LayoutRoot. La premire est cible par un Storyboard nomm Anim Rebond. Lors de lexcution, si vous cliquez sur celle-ci, lanimation est joue grce au code ci-dessous:
public MainPage() { InitializeComponent(); MaBalle1.MouseLeftButtonUp += new MouseButtonEventHandler (MaBalle1_MouseLeftButtonUp); } void MaBalle1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { AnimRebond.Begin(); }

Nous pourrions crer autant danimations que de balles, mais nous allons profiter du couplage faible pour rassigner dynamiquement lanimation la balle clique. Nous pouvons ainsi crire:
public MainPage() { InitializeComponent(); MaBalle1.MouseLeftButtonUp += new MouseButtonEventHandler (MaBalle_MouseLeftButtonUp);

220

Partie II

Interactivit et cration graphique

MaBalle2.MouseLeftButtonUp += new MouseButtonEventHandler (MaBalle_MouseLeftButtonUp); MaBalle3.MouseLeftButtonUp += new MouseButtonEventHandler (MaBalle_MouseLeftButtonUp); } void MaBalle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { Storyboard.SetTarget(AnimRebond, (sender as Grid)); AnimRebond.Begin(); }

Toutefois, si vous faites le test, vous remarquez que lassignation dynamique ne fonctionne quune seule fois. Ceci est d la gestion en mmoire des instances de Storyboard par Silverlight. Les ressources de type Storyboard doivent tout dabord tre libres avant dtre accessibles la modification. Il suffit dinvoquer la mthode Stop sur le Story board, puis de lui rassigner une nouvelle cible:
void MaBalle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { AnimRebond.Stop(); Storyboard.SetTarget(AnimRebond, (sender as Grid)); AnimRebond.Begin(); }

Cette fois, vous pouvez cliquer sur chaque balle pour raffecter la cible et jouer lanimation. Lancienne balle anime revient sa position de dpart. Ce principe est intressant plus dun titre puisque cela vite aux designers de crer autant danimations que dobjets. Pour viter le ct saccad d lappel de la mthode Stop, vous pouvez galement affecter une animation de retour lancien objet cibl. Cela serait particulirement utile pour un grand nombre dobjets animer. Pour viter un appel injustifi de la mthode Stop, vous pouvez galement tester ltat actuel de lanimation:
void MaBalle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (AnimRebond.GetCurrentState()!= ClockState.Stopped) AnimRebond.Stop(); Storyboard.SetTarget(AnimRebond, (sender as Grid)); AnimRebond.Begin(); }

Le principal avantage rside au niveau de la rapidit de production entre dveloppeur et designer. La maintenance est galement plus facile puisquil suffit au designer de modifier une seule animation pour mettre jour lapplication. Le dveloppeur, quant lui, ne fait rfrence qu une seule animation pour un groupe dobjet ayant une fonctionnalit similaire.

8.4 Propagation vnementielle


La propagation vnementielle est propre aux objets graphiques imbriqus. Cette logique vnementielle ne sapplique donc quaux objets hritant de la classe UIElement. Cette spcificit du modle vnementiel permet damliorer les performances et pure le code logique produit.

Chapitre 8

Interactivit et modle vnementiel

221

8.4.1 Principe
Le principe est simple: un vnement, lorsquil est diffus, parcourt larborescence des objets graphiques de manire verticale. Au sein de Silverlight, une seule direction existe. Lvnement part de llment diffuseur le plus bas dans la hirarchie et se dirige vers son parent le plus haut. Durant ce trajet, chaque parent de lobjet source peut, son tour, diffuser cet vnement. Cest la phase de remonte vnementielle, ou Bubbling. On considre que les vnements sont comme des bulles dair remontant la surface de leau. Vous pouvez couter lvnement sur chaque parent de lobjet qui est lorigine de lvnement. Cette notion explique le sens de nombreux comportements. Par exemple, lorsque vous placez des formes au sein dune grille, vous pouvez couter lvnement MouseLeftButtonUp sur cette grille mme si elle ne possde pas de remplissage. Pourquoi? Simplement parce que lvnement est diffus par lune des formes contenues et que celui-ci remonte vers son conteneur parent qui le diffuse son tour. En loccurrence, le conteneur parent en question est la grille (voir Figure8.5).
Figure8.5
Principe de la propagation vnementielle.
coute du conteneur Grille : maGrille.MouseLeftButtonUp += ClickMenuItem;

Composant StackPanel sans couleur de remplissage (no Background)

Clic de la souris sur un menu, ce menu est l'objet source diffusant l'vnement : e.OriginalSource typ Object

Phase de remonte vnementielle appele Bubbling

Comme vous le constatez la Figure8.5, lavantage principal rside dans le fait quil suffit au dveloppeur dcouter un vnement sur un conteneur plutt que sur chaque objet contenu. Il est possible de connatre lobjet diffuseur originel via la proprit OriginalSource de lobjet vnementiel. Attention toutefois au fait que seuls certains des vnements achemins (dits routs et typs RoutedEvent) utilisent la propagation vnementielle. En voici une liste:

MouseLeftButtonUp est un vnement diffus lors du relch du bouton gauche de la souris. MouseLeftButtonDown est notifi lors de lappui sur le bouton gauche de la souris. MouseMove est dclench lorsque la souris bouge. KeyUp est diffus lorsquune touche du clavier est relche. KeyDownest diffus lors de lappui sur une touche du clavier. GotFocusest un vnement diffus lorsquun composant bnficie de lintrt utilisateur ou focus.

222

Partie II

Interactivit et cration graphique

LostFocusest diffus lorsquun composant perd le focus utilisateur. MouseWheelest un vnement diffus lors de lutilisation de la molette de la souris. BindingValidationErrorest un vnement diffus lorsquune erreur est leve lors de lassignation dune valeur non conforme.

Chacun des vnements ci-dessus est une interaction fondamentale de lutilisateur. Ainsi, lvnement Click nest quun vnement spcifique propre aux composants orients utilisateur, alors que MouseLeftButtonUp est un vnement diffusable par toutes les classes drives de UIEle ment.

8.4.2 Un exemple simple de propagation


Nous allons mettre en pratique les notions que nous venons dapprendre. Tlchargez le projet nomm "Propagation" depuis les exemples du livre: chap8/Propagation.zip. Ce projet constitue un cas trs simple de propagation vnementielle. Un conteneur de type Grid contient une forme de type Rectangle. Le premier est rempli dune couleur gris fonc; le rectangle, quant lui, affiche une couleur de fond gris clair (voir Figure8.6).
Figure8.6
Visuel du projet Propagation.

Ajoutez un champ TextBlock nomm Resultat en haut gauche au sein du conteneur Layout Root. coutez ensuite lvnement MouseLeftButtonUp sur chacun des deux objets (Conteneur Grille et UnRectangle) de cette manire:
public MainPage() { InitializeComponent(); UnRectangle.MouseLeftButtonUp += new MouseButtonEventHandler (MouseLeftButtonUp_generique); ConteneurGrille.MouseLeftButtonUp += new MouseButtonEventHandler (MouseLeftButtonUp_generique); } void MouseLeftButtonUp_generique(object sender, MouseButtonEventArgs e) { string NomObjet = (sender as FrameworkElement).Name; Resultat.Text += "Diffuseur:: " + NomObjet +"\n"; }

Lorsque vous cliquez sur le rectangle gris clair, le champ texte vous confirme que les deux composants ont diffus le relch de la souris. Lorsque vous cliquez sur la grille sombre en revanche, seule celle-ci diffuse lvnement. Grce la propagation vnementielle, vous ntes pas oblig dcouter lvnement deux fois. Vous pouvez utiliser la proprit OriginalSource pour

Chapitre 8

Interactivit et modle vnementiel

223

dterminer quel objet a t cliqu au sein de la grille. Ajoutez deux autres rectangles nomms Deux Rectangle et TroisRectangle au sein de la grille et rpartissez-les quitablement (voir Figure8.7).
Figure8.7
Mise en place du projet propagation.

Vous pouvez optimiser le code en ne dfinissant lcouteur que sur la grille nomme Conteneur Grille:
public MainPage() { InitializeComponent(); ConteneurGrille.MouseLeftButtonUp += new MouseButtonEventHandler (MouseLeftButtonUp_generique); } void MouseLeftButtonUp_generique(object sender, MouseButtonEventArgs e) { string NomObjet = (sender as FrameworkElement).Name; Resultat.Text = " Objet cout en dur:: " + NomObjet+"\n"; Resultat.Text += " Objet diffuseur originel de lvnement:: " + (e.OriginalSource as FrameworkElement).Name+"\n"; }

Le code en gras permet de tracer lobjet la source de la diffusion. Celui-ci peut tre diffrent de lobjet cout directement dans votre code. Compilez et testez votre application en cliquant sur chacun des rectangles puis sur ConteneurGrille. Chaque rectangle peut tre responsable de la diffusion de lvnement MouseleftButtonUp, vous pouvez rcuprer la rfrence de lobjet diffuseur source grce la proprit OriginalSource de lobjet vnementiel. Le code est ainsi beaucoup plus simple maintenir.

8.4.3 viter la diffusion dvnements


Parfois, vous devrez empcher les vnements dtre diffuss. Reprenons lexercice des balles, nous pourrions tre tent damliorer le code en gras ci-dessous grce la propagation vnementielle:
public MainPage() { InitializeComponent(); MaBalle1.MouseLeftButtonUp += new MouseButtonEventHandler (MaBalle_MouseLeftButtonUp); MaBalle2.MouseLeftButtonUp += new MouseButtonEventHandler (MaBalle_MouseLeftButtonUp); MaBalle3.MouseLeftButtonUp += new MouseButtonEventHandler (MaBalle_MouseLeftButtonUp); }

224

Partie II

Interactivit et cration graphique

Il suffit pour cela dcouter le conteneur parent commun chaque balle. Dans ce cas, il correspond la grille principale LayoutRoot:
public MainPage() { InitializeComponent(); LayoutRoot.MouseLeftButtonUp += new MouseButtonEventHandler (MaBalle_MouseLeftButtonUp); } void MaBalle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (AnimRebond.GetCurrentState()!= ClockState.Stopped) AnimRebond.Stop(); Storyboard.SetTarget(AnimRebond, (e.OriginalSource as Grid)); AnimRebond.Begin(); }

Si vous testez ce code, vous vous apercevrez quil ne fonctionne pas pour diverses raisons. La premire tant que le premier objet lorigine de la diffusion de lvnement est forcment de type Ellipse. Les balles contiennent chacune trois ellipses qui diffuseront lvnement en premier. Laffectation de cible ne fonctionnera pas. La seconde raison est du mme ordre. Lvnement aura tendance tre diffus par LayoutRoot lui-mme. Lorsque vous cliquerez sur la grille LayoutRoot, lanimation ne sera pas joue car elle ne contient pas le nud RenderTransform lui permettant dtre cible par lanimation. Il nous faut donc raliser deux tches diffrentes qui ont toutes deux pour objectif dviter la diffusion dun vnement. Tout dabord, il faut que les objets de type Ellipse ne puissent pas diffuser lvnement MouseleftButtonUp. Pour cela, nous pouvons passer leur proprit IsHitTestVisible false, nous y aurons accs en dpliant compltement longlet Common Properties, situ au sein du panneau Properties. Ensuite, il est ncessaire de tester le nom de la rfrence renvoye par e.OriginalSource. Si cette rfrence est LayoutRoot, on sort de la mthode sans rien faire via linstruction return. Voici le code dfinitif:
public MainPage() { InitializeComponent(); LayoutRoot.MouseLeftButtonUp += new MouseButtonEventHandler (MaBalle_MouseLeftButtonUp); } void MaBalle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { //on teste le nom de lobjet diffuseur if ((e.OriginalSource as Grid).Name == "LayoutRoot") return; //on teste ensuite ltat actuel de lanimation if (AnimRebond.GetCurrentState()!= ClockState.Stopped) AnimRebond.Stop(); Storyboard.SetTarget(AnimRebond, (e.OriginalSource as Grid)); AnimRebond.Begin(); }

Testez et compilez, les balles sont cette fois ractives au clic gauche de la souris. Les instances dEllipse ne diffusent plus lvnement MouseLeftButtonUp, laissant ce rle aux grilles Ma Balle1, MaBalle2 et MaBalle3. Gardez cependant lesprit que cela est possible parce que Ma Balle1, MaBalle2 et MaBalle3 possdent un fond transparent. Leur proprit Fill possde donc

Chapitre 8

Interactivit et modle vnementiel

225

une valeur hexadcimale de type 0x00xxxxxx. Une grille qui ne possde pas de remplissage ne peut diffuser les vnements que grce aux objets quelle contient. Comme les ellipses au sein des balles ne sont plus cliquables, il est obligatoire que les grilles MaBalle1, MaBalle2 et MaBalle3 possdent un fond. Toutefois, cette solution nest pas entirement satisfaisante dans notre cas. La surface cliquable par lutilisateur correspond en fait aux dimensions rectangulaires de chaque grille. Lutilisateur pourra donc cliquer dans lespace invisible situ entre la surface de la balle et la surface restante de la grille. Nous allons maintenant tudier une manire dempcher la diffusion dvnements propags.

8.4.4 Arrter la propagation vnementielle


Stopper la propagation vnementielle est pratique dans le cas o vous ne souhaitez pas quun objet conteneur diffuse un vnement dj cout par ses enfants. Par exemple, vous pourriez avoir besoin dcouter le mme vnement sur un conteneur et sur ses enfants tout en invoquant deux mthodes dcoutes diffrentes. Lune concernerait le conteneur, lautre se dclencherait lorsque lun des enfants diffuse lvnement. Vous pourriez dcider que lune ou lautre mthode dcoute se dclenche, mais pas les deux en mme temps. Cest exactement le cas dans le projet que nous allons voir maintenant. Ouvrez le projet nomm Propagation_Handled (chap8/Propagation_Handled.zip). Compilez et testez lapplication. En haut gauche du conteneur principal, vous apercevez un composant TextBlock nomm TestTxt. Il va nous permettre dafficher toutes les mthodes dcoute dclenches dans lordre de diffusion. Au centre de LayoutRoot se trouve un conteneur StackPanel. Il contient plusieurs rectangles gris qui reprsentent chacun un voyant (voir Figure8.8).
Figure8.8
Visuel du projet Propagation_Handled.

Au sein de ce projet, deux mthodes dcoute sont dclenches pour le mme vnement Mouse LeftButtonDown diffus:

La premire mthode, ConteneurMenus_MouseLeftButtonDown, est diffuse par le Stack Panel. Ce dernier possde un remplissage sous forme de dgrad linaire reprsentant trois zones horizontales. Lorsque lutilisateur clique sur ce conteneur, nous testons lendroit o lutilisateur a cliqu (vnement MouseLeftButtonDown), puis nous repositionnons le conteneur dans lapplication en fonction de la zone de clic. Cette tche est ralise grce au gestion-

226

Partie II

Interactivit et cration graphique

naire dagencement fluide vu au Chapitre7. Par exemple, si lutilisateur clique dans la partie gauche du StackPanel, il salignera gauche de lapplication. Voici le code permettant de grer ce comportement:
public MainPage() { // Required to initialize variables InitializeComponent(); ConteneurMenus.MouseLeftButtonDown +=new MouseButtonEventHandler (ConteneurMenus_MouseLeftButtonDown); } private void ConteneurMenus_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { StackPanel MonConteneur = sender as StackPanel; // chaque fois que lon clique sur le conteneur //on passe la couleur darrire-plan de tous ses enfants en gris foreach (Rectangle rec in MonConteneur.Children) { rec.Fill = new SolidColorBrush (Colors.Gray); } //on teste lendroit qui a t cliqu //et qui est relatif aux conteneurs double XClic = e.GetPosition(MonConteneur).X; string pos=""; if ( XClic >= MonConteneur.ActualWidth*2/3) { VisualStateManager.GoToState(this,"RightPosition",true); pos = " - clic dans la zone droite"; } else if (XClic < MonConteneur.ActualWidth*2/3 && XClic >= MonConteneur.ActualWidth/3) { VisualStateManager.GoToState(this,"CenterPosition",true); pos = " - clic dans la zone du centre"; } else if (XClic < MonConteneur.ActualWidth/3) { VisualStateManager.GoToState(this,"LeftPosition",true); pos = " - clic dans la zone gauche"; } //On finit en incrmentant le champ TextBlock //afin davertir de la diffusion de lvnement TestTxt.Text += "\n - "+MonConteneur.Name + pos; }

La seconde mthode dclenche est commune tous les objets de type Rectangle qui sont contenus au sein du StackPanel (soit Menu1, Menu2, etc.). Lobjectif est simple: nous souhaitons leur donner un rle dindicateur visuel en changeant leur couleur de remplissage par du blanc. Cela est ralis lors de chaque clic de la souris sur lun des rectangles (Mouse LeftButtonDown). Gardez galement lesprit que lorsque lutilisateur clique sur leur conteneur StackPanel, leur couleur est rinitialise. Cette fonctionnalit est gre par le code en

Chapitre 8

Interactivit et modle vnementiel

227

gras ci-dessus dans la mthode Conteneur Menus_Mouse Left ButtonDown. Voici lcouteur dclench lorsque les menus diffusent lvnement MouseLeftButtonDown:
public MainPage() { InitializeComponent(); ConteneurMenus.MouseLeftButtonDown += // chaque fois que lon trouve un enfant au sein du conteneur on //souscrit la mthode dcoute Menu_MouseLeftButtonDown foreach (UIElement e in ConteneurMenus.Children) { e.MouseLeftButtonDown +=new MouseButtonEventHandler (Menu_MouseLeftButtonDown); } } private void Menu_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Rectangle MenuClic = (sender as Rectangle); MenuClic.Fill = new SolidColorBrush(Colors.White); TestTxt.Text = "Objets diffusant MouseLeftButtonDown dans lordre de remonte:: "; TestTxt.Text += "\n - "+(sender as FrameworkElement).Name; }

Si vous compilez et cliquez sur chaque menu, le rsultat attendu par ce code ne fonctionne pas. La couleur darrire plan des rectangles ne devient pas blanche. Cest en fait trs logique. La mthode appele par le conteneur est dclenche aprs celle excute par les menus. La couleur de chaque menu est rellement modifie, mais ensuite la mthode ConteneurMenus_MouseLeftButtonDown la rinitialise. Le champ texte en haut gauche le prouve, les rectangles diffusent lvnement avant le conteneur (voir Figure8.9).
Figure8.9
Ordre de diffusion mis en valeur par le champ TestTxt.

Il est tout fait possible dcrire ce code sans connatre le concept de propagation vnementielle. Il devient alors difficile de diagnostiquer certains comportements comme celui que nous avons rencontr linstant. Pour remdier ce problme, nous devons arrter la propagation de lv-

228

Partie II

Interactivit et cration graphique

nement aprs que les enfants du conteneur laient diffus. La proprit Handled de lobjet vnementiel, lorsquelle est passe true, permet dattraper lvnement et lempche de remonter au niveau suprieur pour tre diffus par le parent. Voici le code mis jour pour la mthode dcoute de chaque rectangle:
private void Menu_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Rectangle MenuClic = (sender as Rectangle); MenuClic.Fill = new SolidColorBrush(Colors.White); TestTxt.Text = "Objets diffusant MouseLeftButtonDown dans lordre de remonte:: "; TestTxt.Text += "\n - "+(sender as FrameworkElement).Name; //On stoppe la propagation e.Handled = true;

Cette fois-ci, tous les rectangles changent de couleur. Si vous cliquez directement sur larrireplan du conteneur, il se repositionne en fonction de la zone clique, et rinitialise les couleurs de chaque enfant en gris. Vous pouvez ainsi dfinir des interactions la fois diffrentes et complmentaires pour un conteneur et ses enfants partir dun unique vnement.

8.4.5 Glisser-dposer et capture des vnements souris


Les oprations de glisser-dposer sont aujourdhui communes et ntonnent personne au sein des interfaces riches. Ce nest pas un effet de mode, puisque cela existe depuis les premires interfaces graphiques. Cest un type dinteraction largement adopt et offrant une ergonomie performante et accentuant limpression de libert daction. Ce type dinteraction, au sein de Silverlight, nest pas si simple raliser du fait de la nature mme de lvnement MouseMove. Cet vnement est assez particulier: il subit la propagation vnementielle sans pour autant permettre larrt de sa propagation via la proprit Hand led. Lexplication en est simple : lobjet vnementiel, qui est de type MouseEventArgs, ne possde pas cette proprit. De plus, le type de propagation est lgrement diffrent, lvnement neffectue pas vraiment la phase de remonte. En ralit, chaque parent diffuse lun aprs lautre lvnement par lui-mme. Il est ainsi impossible darrter cette pseudo propagation. Nous allons maintenant gnrer cette interaction en connaissance de cause. Crez un projet nomm ClickAndDrag. Vous utiliserez les transformations relatives de translation pour grer le glisser-dposer. cette fin, il est prfrable de tlcharger la bibliothque ProxyRender Transform que je mets disposition cette adresse: http://proxyrd.codeplex.com/. Lavantage des Render Transform est de pouvoir dplacer un objet quelque soit le type de contrainte impose par le conteneur parent de lobjet dplacer. Rfrencez le fichier dll que vous avez tlcharg en cliquant droit sur le rpertoire Reference, puis en choisissant le menu Add Reference. Attention ensuite bien faire rfrence la bibliothque au sein du code C# via linstruction using Proxy RenderTransform. Crez un rectangle nomm MonRectangle sur la grille principale Layout Root. Ouvrez maintenant le fichier MainPage.xaml.cs au sein de Blend ou de Visual Studio. Si vous dcomposez linteraction de glisser-dposer, vous remarquez que trois vnements sont ncessaires son fonctionnement:

Chapitre 8

Interactivit et modle vnementiel

229

Lvnement MouseLeftButtonDown sur lobjet dplacer permettra de lier lobjet aux coordonnes de la souris. Lvnement MouseLeftButtonUp, correspondant au relch de la souris diffus par lobjet, aura la charge de librer lobjet du dplacement de la souris. Pour finir, MouseMove se dclenchant chaque dplacement de la souris grera le dplacement de lobjet.

Attention toutefois au fait que MouseMove est coteux en termes de performance. Lidal serait de ne le diffuser que lorsque cest ncessaire. Cest tout fait possible de limiter sa diffusion. Dans la vie courante, vous ne dessinez sur le papier que lorsque la mine de votre crayon est appuye et quelle se dplace sur la feuille mais pas lorsquelle est au-dessus. Cela parat vident et cest tant mieux car le comportement de glisser-dposer est similaire. Vous ne dplacez lobjet que lorsque vous cliquez dessus tout en laissant le bouton appuy. Ainsi, vous navez pas besoin de diffuser lvnement MouseMove de manire permanente, mais uniquement quand le bouton gauche de la souris reste appuy. Vous pouvez commencer par dfinir lcoute des vnements MouseLeft ButtonDown et MouseLeftButtonUp dans le constructeur de MainPage:
public MainPage() { InitializeComponent(); MonRectangle.MouseLeftButtonDown += new MouseButtonEventHandler (MonRectangle_MouseLeftButtonDown); MonRectangle.MouseLeftButtonUp += new MouseButtonEventHandler (MonRectangle_MouseLeftButtonUp); }

Comme vous lavez vu plus haut, vous pouvez dfinir lcoute de lvnement MouseMove seulement quand lutilisateur appuie sur lobjet. Il faut galement arrter labonnement de lcouteur au relch du bouton. Ainsi vous pouvez dj crire les mthodes dcoute correspondantes:
void MonRectangle_MouseLeftButtonDown(object sender,MouseButtonEventArgs e) { //Lorsquon appuie sur le rectangle //on coute le dplacement de la souris MonRectangle.MouseMove += new MouseEventHandler(MonRectangle_MouseMove); } void MonRectangle_MouseLeftButtonUp(object sender,MouseButtonEventArgs e) { MonRectangle.MouseMove -= new MouseEventHandler(MonRectangle_MouseMove); }

Pour vous persuader de lefficacit en termes de performance, vous pouvez tracer une variable incrmente chaque fois que MouseMove est diffuse. Vous verrez que celle-ci ne sincrmente que lorsque vous dplacez la souris au-dessus du rectangle aprs avoir appuy dessus:
int i =0; void MonRectangle_MouseMove(object sender, MouseEventArgs e) { //On incrmente une variable }

230

Partie II

Interactivit et cration graphique

ATTENTION

Il faut relcher la souris au-dessus du rectangle pour arrter la souscription lvnement Mouse Move. Il y a en effet une diffrence entre relcher au-dessus de lobjet et relcher lextrieur. Dans le premier cas, lvnement MouseLeftButtonUp sera bien diffus, pas dans le second.

ce stade, il nous reste dfinir la mthode dcoute MonRectangle_MouseMove et crer lalgorithme de dplacement. Voici le code complt, notez quil utilise la position de la souris ainsi que les transformations relatives sans aucun besoin des marges de lobjet dans la grille. Il est beaucoup plus simple de procder ainsi:
void MonRectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { MonRectangle.MouseMove -= new MouseEventHandler(MonRectangle_MouseMove); } void MonRectangle_MouseMove(object sender, MouseEventArgs e) { //On redfinit les nouvelles transformations relatives //par rapport au repre dorigine Point p = e.GetPosition(null); MonRectangle.SetX(p.X - coordX); MonRectangle.SetY(p.Y - coordY); } void MonRectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //Lorsquon appuie sur le rectangle, on coute le dplacement //de la souris MonRectangle.MouseMove += new MouseEventHandler(MonRectangle_MouseMove); //On rcupre la diffrence entre les coordonnes de la souris //et les transformations relatives de lobjet. coordX = e.GetPosition(null).X - (double)MonRectangle.GetX(); coordY = e.GetPosition(null).Y - (double)MonRectangle.GetY(); }

Testez et compilez le projet. Si vous dplacez lentement lobjet MonRectangle, tout fonctionne bien. Toutefois, ds que la souris va trop vite et sort des limites du rectangle, plus rien ne va. Les bogues qui apparaissent ont deux raisons similaires. Tout dabord, MouseMove nest diffus que lorsque la souris est dans les limites imparties par le rectangle. Or, si vous allez un peu trop vite dans les dplacements de la souris, celle-ci sort des limites de lenveloppe et lobjet nest plus dplac. En second lieu, si vous relchez le bouton de la souris en dehors de lenveloppe, encore une fois parce que vous allez un peu trop vite, lvnement MonRectangle_MouseLeftButtonUp nest pas diffus. La consquence directe de ce comportement, c'est que vous allez souscrire une seconde fois lvnement MouseLeftButtonDown, lorsque vous allez le recliquer. Il devient alors impossible darrter lcoute de lvnement MouseMove. Vous allez rgler ces deux problmes en une seule fois en capturant tous les vnements lis la souris. Ceci est ralis grce aux mthodes CaptureMouse et ReleaseMouse Capture propres aux objets hritant de la classe UIElement. Ainsi, lvnement MouseMove continuera dtre diffus mme lorsque la souris sortira des dimensions du rectangle. Pour la mme raison, lvnement MouseLeftButtonUp sera diffus mme si lutilisateur relche la souris en dehors du rectangle. Voici le code finalis de lapplication:

Chapitre 8

Interactivit et modle vnementiel

231

using using ProxyRenderTransform; namespace DragAndDropObject { public partial class MainPage: UserControl { double coordX; double coordY; public MainPage() { InitializeComponent(); MonRectangle.MouseLeftButtonDown += new MouseButtonEventHandler (MonRectangle_MouseLeftButtonDown); MonRectangle.MouseLeftButtonUp += new MouseButtonEventHandler (MonRectangle_MouseLeftButtonUp); } void MonRectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { //on arrte la capture des vnements propres la souris MonRectangle.ReleaseMouseCapture(); MonRectangle.MouseMove -= new MouseEventHandler (MonRectangle_MouseMove); } void MonRectangle_MouseMove(object sender, MouseEventArgs e) { MonRectangle.SetX(e.GetPosition(null).X - coordX); MonRectangle.SetY(e.GetPosition(null).Y - coordY); } void MonRectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //MonRectangle capture tous les vnements //diffuss par la souris MonRectangle.CaptureMouse(); //Lorsquon appuie sur le rectangle on coute //le dplacement de la souris MonRectangle.MouseMove += new MouseEventHandler (MonRectangle_MouseMove); //On rcupre les coordonnes de la souris sur LayoutRoot coordX = e.GetPosition(null).X - (double)MonRectangle.GetX(); coordY = e.GetPosition(null).Y - (double)MonRectangle.GetY(); } } }

Testez et compilez votre projet, vous verrez que cette fois, tout se droule comme prvu. Vous trouverez cet exercice corrig dans: chap8/DragAndDropObject.zip.

232

Partie II

Interactivit et cration graphique

8.5 Les comportements


Le concept de comportement repose sur le pattern Dcoration ou Decorator. Ce modle de conception permet dattacher des fonctionnalits ou des caractristiques non natives aux objets de manires dynamique et non intrusive. Dcorer un objet ne modifie pas son code natif, mais tend ses possibilits. Cela permet des architectures objet bien plus facile produire et maintenir que lhritage. Ajouter des comportements un objet va dans ce sens. Utiliser des comportements ou ajouter des fonctionnalits via un langage logique sont deux manires quivalentes darriver un mme rsultat, linteractivit. Pourtant ces deux mthodologies se diffrencient sur plusieurs points: la souplesse dutilisation selon les cas de figure, loptimisation des performances et la philosophie du flux de production entre designers et dveloppeurs. Il est galement possible de vouloir ajouter des capacits un objet sans pour autant que celles-ci soient lies une quelconque interaction utilisateur.

8.5.1 Comportements versus programmation vnementielle


Au sein de Silverlight, le mot comportement est reli linterface de Blend et aux designers. Les comportements sont reprsents sous forme de petites icnes que vous pouvez placer sur un objet. Utiliser des comportements se rvle efficace dans deux situations.Dans le premier cas, le designer souhaite atteindre un objectif rapidement sans coder pour produire une maquette semi-fonctionnelle. Il peut alors utiliser les comportements de navigation fournis en standard pour dclencher un Storyboard, affecter une proprit ou accder un tat visuel. La seconde situation apparat lorsque lobjectif atteindre est trs complexe. Par exemple, vous souhaitez ajouter des interactions physiques vos objets comme la gravit ou les collisions, ou capturer les mouvements de la souris. Cest typiquement le genre dinteractivit difficile mettre en place, mais qui pourrait tre paramtre par un designer. Lapport dun dveloppeur est alors crucial. Celui-ci peut fournir un jeu de comportements que le designer pourra librement affecter aux objets de son choix et paramtrer loisir dans Blend. Coder les vnements est pourtant plus souple dun autre point de vue. Le comportement est instanci dans le projet par le designer dans la plupart des cas. Le dveloppeur pourrait donc ne pas tre inform de leur existence puisquils apparaissent au sein du code dclaratif. Cela peut gnrer des quiproquos ou des conflits dinteractivit si la communication intermtiers nest pas correctement tablie. La deuxime raison, qui pousse les dveloppeurs grer eux-mmes linteractivit, est la centralisation du code logique et loptimisation des performances de lapplication. Sil est possible pour un graphiste dajouter des comportements au sein de Blend nimporte quel lment visuel, il est en revanche impossible pour lui de le faire durant lexcution de lapplication. De mme, supprimer des comportements dynamiquement nest pas ralisable pour lui sans code. Il devra donc faire appel un dveloppeur pour ces tches. La programmation vnementielle reste donc utilise dans90% des cas ce qui est heureux. Il faut maintenir un quilibre constant en fonction des quipes, des comptences de chacun et surtout justifier lutilisation des comportements soit par une phase de production rapide, soit par des besoins spcifiques.

8.5.2 Les diffrents types de comportements


On distingue deux grandes familles de comportements: les comportements simples hritant de la classe Behavior et les comportements daction dclenche qui sont typs TriggerAction et

Chapitre 8

Interactivit et modle vnementiel

233

TargetedTriggerAction. Au sein de Blend, ces deux familles sont voques par des icnes diffrentes que vous pouvez voir dans le panneau Assets. Les comportements simples sont reprsents par un pictogramme en forme dengrenage et leur nom se termine par Behavior. Les comportements daction cibls, ou non, ont quant eux une icne compose dun engrenage sur lequel sajoute une flche de lecture. Ils sont suffixs du mot Action (voir Figure8.10).
Figure8.10
Les deux familles de comportements.

8.5.2.1 Principe des comportements simples


Le but dun comportement simple est dajouter des fonctionnalits. Il contient cette fin des gestionnaires dvnements. Toutefois, la logique vnementielle permettant ce type de comportements n'est pas accessible au designer sous Blend. Celle-ci est ferme la modification. Cest exactement le cas du comportement MouseDragElement Behavior. Ouvrez un nouveau projet dans Blend, crez un simple rectangle dans LayoutRoot, puis glissez-dposez le comportement MouseDragElementBehavior sur celui-ci. Dans le panneau des proprits, vous pouvez voir les proprits paramtrables du comportement simple (voir Figure8.11).
Figure8.11
Proprits du comportement simple MouseDragElementBehavior.

Comme vous pouvez le voir, il nest pas possible daccder la logique vnementielle, mais seulement des proprits qui vont influencer la manire dont le comportement sexcutera. Dans le cas prsent, vous pouvez choisir si lobjet dplacer restera ou non dans les limites imparties par le conteneur.

8.5.2.2 Les comportements daction dclenche


Les comportements simples affectent les fonctionnalits de lobjet auquel ils sont attachs, une fois pour toute la compilation. Les comportements daction sont plus volus car ils vous per-

234

Partie II

Interactivit et cration graphique

mettent de choisir lvnement qui dclenchera leur excution ainsi que lobjet diffuseur. Cela peut-tre trs utile pour un designer car il naura pas coder en C# la logique vnementielle, mais simplement paramtrer les proprits du comportement. Cest exactement le cas de GoToState Action. Crez deux tats visuels, nommez le premier RedState et le second GreenState. Slectionnez ltat RedState, puis assignez une couleur rouge ple au remplissage de LayoutRoot ; procdez de mme pour ltat GreenState en lui assignant une couleur verte. Placez ensuite deux boutons sur Layout Root et glissez le comportement GoToStateAction sur les deux boutons. Vous pouvez maintenant permettre lutilisateur de passer dun tat un autre en paramtrant les deux comportements (voir Figure8.12).
Figure8.12
Proprits du comportement daction cibl GoToStateAction.

Les comportements daction reproduisent compltement la logique vnementielle et donnent accs son paramtrage. Longlet Trigger (dclencheur) centralise les proprits grant la diffusion et permet notamment de choisir lobjet diffuseur ainsi que lvnement couter. Par dfaut, lobjet diffuseur est lobjet auquel le comportement a t attach. Vous pouvez ensuite dcider de lvnement dclencheur. Dans ce projet, lvnement choisir est Click car les boutons ne diffusent pas MouseLeftButtonDown par dfaut. Vous avez la possibilit de choisir un objet cible ainsi que ltat afficher et lutilisation ou non dune transition anime. Le paramtrage est au final trs simple et ne demande aucune ligne de code. Le comportement GoToStateAction est particulier car il vous permet de choisir une instance de Control. Pour cette raison, il est de type TargetedTriggerAction.

8.5.3 Crer des comportements personnaliss


8.5.3.1 Ajouter la fonctionnalit filigrane aux champs de saisie
Nous allons maintenant crer un comportement simple personnalis. Son objectif est simple, nous le dposerons sur un champ de saisie. Tant quil naura pas t rempli par lutilisateur ou naura pas le focus utilisateur, il affichera une chane de caractres en gris clair permettant dindiquer le type dinformation saisir. Nous allons crer, de cette manire, un champ de saisie avec filigrane, ou WatermarkTextBox. Crer le comportement est relativement ais puisque Blend et Visual Studio gnrent une partie du code initial. Crez un nouveau projet Silverlight nomm YourBehaviors. Au sein du panneau Projects, cliquezdroit sur le projet et choisissez le menu Add New Item Dans la bote de dialogue qui saf-

Chapitre 8

Interactivit et modle vnementiel

235

fiche, vous avez le choix entre un comportement simple (Behavior) et un comportement daction (TiggerAction). Slectionnez Behavior, puis nommez la classe WatermarkBehavior.cs (voir Figure8.13).
Figure8.13
Cration du comportement WatermarkBehavior.

Comme vous le constatez, dans le code logique du comportement par dfaut, la classe est paramtre avec DependencyObject par dfaut. Cette classe est la plus gnrique possible car elle est parente de UIElement. Cela nest pas pratique car ce comportement na de sens que sil est affect sur des instances de TextBox, il nous faut donc dfinir le type dobjet paramtr comme tant de type TextBox:
public class WatermarkBehavior: Behavior<TextBox> { public WatermarkBehavior() { } }

Outre le constructeur de la classe WatermarkBehavior, deux mthodes ont t gnres : On Attached et OnDetaching. Bien que visible dans larbre visuel et logique sous Blend, un comportement nest pas un objet visuel mais purement logique. Il ne possde pas la mthode dinitialisation Loaded propre aux objets daffichage, mais OnAttached la remplace. Celle-ci se dclenche la compilation ou lexcution lorsque le comportement est attach un objet. La mthode OnDetaching est invoque lorsque le comportement est supprim ou dtach de lobjet lexcution. Pour tre fonctionnel, notre comportement doit possder au moins une proprit permettant au designer de choisir le message afficher lorsque le champ de saisie nest pas rempli. Nous pouvons commencer par la crer. Voici la proprit cre en C# au sein de la classe:
public class WatermarkBehavior: Behavior<TextBox> { private string watermark = "Veuillez saisir une information"; public string Watermark { get { return watermark; } set { watermark = value; } } }

236

Partie II

Interactivit et cration graphique

Le scnario dutilisation est simple: lorsque le champ de saisie sera initialis ou perdra le focus utilisateur, un test sera ralis sur le contenu de sa proprit Text. Si la valeur de Text est vide, alors le champ affichera la chane de caractres, contenue par la proprit WatermarkText, en gris. Lorsque le champ texte obtiendra le focus utilisateur, si sa proprit Text contient une chane de caractres correspondant la proprit Watermark Text, alors il se videra pour laisser lutilisateur saisir les informations personnalises ncessaires. Tout se joue donc sur les vnements propres la gestion du focus utilisateur: LostFocus et GotFocus. Toutefois, dans notre cas, le sujet (ou diffuseur de lvnement) est en fait le champ de saisie sur lequel vous glisserez le comportement. Pour rcuprer une rfrence du futur champ de saisie attachant le comportement, vous pouvez utiliser la proprit hrite de la classe Behavior: AssociatedObject. Attention toutefois au fait que AssociatedObject nest affecte de linstance de lobjet attach qu' l'instant o celui-ci lest effectivement dans l'interface de Blend. Autrement dit, au sein du constructeur de la classe, la proprit AssociatedObject ne contient aucune instance de TextBox. Linitialisation des couteurs doit donc tre centralise dans la mthode OnAttached. Voici le code qui contient la gestion des vnements ncessaires:
public class WatermarkBehavior: Behavior<TextBox> { private string watermarkText = "Please enter information here"; public string WatermarkText { get { return watermarkText; } set { watermarkText = value; } } public WatermarkBehavior() { } protected override void OnAttached() { base.OnAttached(); //on teste par dfaut le champ de saisie pour afficher le filigrane //si le champ est vide AssociatedObject_LostFocus(this.AssociatedObject, null); AssociatedObject.GotFocus += new RoutedEventHandler (AssociatedObject_GotFocus); AssociatedObject.LostFocus += new RoutedEventHandler (AssociatedObject_LostFocus); } //lorsque le champ de saisie perd le focus void AssociatedObject_LostFocus(object sender, RoutedEventArgs e) { //on teste le nombre de caractres contenus si rien nest //rempli alors on affecte le champ texte de la valeur en filigrane if (AssociatedObject.Text.Length ==0) { AssociatedObject.Text = WatermarkText; } } //lorsque le champ de saisie obtient le focus void AssociatedObject_GotFocus(object sender, RoutedEventArgs e) {

Chapitre 8

Interactivit et modle vnementiel

237

//on regarde si la valeur de la proprit Text correspond //au filigrane. Si elle correspond, on vide le champ texte //pour que lutilisateur puisse saisir les informations if (AssociatedObject.Text.Contains(WatermarkText)) { AssociatedObject.Text = ""; } } }

Compilez le projet. Pour le tester efficacement, vous devez crer plusieurs champs de saisie sur LayoutRoot crer cinq champs serait idal. Au sein du panneau Assets, slectionnez longlet Project. Vous faites ainsi apparatre tous les composants crs pour le projet. Le comportement WatermarkBehavior est donc prsent dans la liste. Dposez-le sur chacun des champs de saisie. Supprimez leur contenu texte, puis dans les paramtres de chaque comportement, dfinissez respectivement les chanes de caractres: "saisir votre nom", "saisir votre prnom", "saisir votre adresse", "saisir votre code postal", "saisir votre ville". Vous pouvez galement rpartir ces champs au sein dun StackPanel. Une fois cette tche ralise, il est plus facile de tester le projet. Au sein du navigateur, utilisez la touche Tabulation afin de passer dun champ lautre (voir Figure8.14).
Figure8.14
Test des champs de saisie au sein du navigateur.

Pour parfaire le comportement, il faudrait griser le texte lorsque le filigrane est affich. Rien de plus simple, il suffit daffecter la proprit Foreground du champ de saisie. Toutefois, il est obligatoire de sauvegarder au sein dune variable la couleur dorigine. Ceci nous permettra dafficher le texte de manire normal lorsque les informations sont saisies correctement. Il serait galement avantageux de laisser le soin au designer de choisir la couleur du filigrane afin de respecter la charte graphique. Voici le code complet du comportement:
using using using using using using using using System; System.Collections.Generic; System.Text; System.Windows; System.Windows.Controls; System.Windows.Data; System.Windows.Documents; System.Windows.Input;

238

Partie II

Interactivit et cration graphique

using using using using

System.Windows.Media; System.Windows.Media.Imaging; System.Windows.Shapes; System.Windows.Interactivity;

//permet entre autres choses de grer la rpartition des //proprits dans Blend using System.ComponentModel; namespace YourBehaviors { public class WatermarkBehavior: Behavior<TextBox> { private string watermarkText; [Category("Watermark Properties")] [DefaultValue("saisir un texte")] public string WatermarkText { get { return watermarkText; } set { watermarkText = value; } } //couleur dorigine private SolidColorBrush originColor; //couleur du filigrane private SolidColorBrush watermarkForeground = new SolidColorBrush(Colors.Gray); public SolidColorBrush WatermarkForeground { get { return watermarkForeground; } set { watermarkForeground = value; } } public WatermarkBehavior(){ } protected override void OnAttached() { base.OnAttached(); //on commence par sauvegarder la couleur dorigine originColor = (SolidColorBrush)AssociatedObject.Foreground;

//on initialise par dfaut le champ AssociatedObject_LostFocus(this.AssociatedObject, null); //on coute les vnements AssociatedObject.GotFocus += new RoutedEventHandler (AssociatedObject_GotFocus); AssociatedObject.LostFocus += new RoutedEventHandler (AssociatedObject_LostFocus); } protected override void OnDetaching() { base.OnDetaching(); //on reste fidle aux bonnes pratiques en supprimant //lcoute des vnements dont on na plus besoin AssociatedObject.GotFocus -= AssociatedObject_GotFocus; AssociatedObject.LostFocus -= AssociatedObject_LostFocus; }

Chapitre 8

Interactivit et modle vnementiel

239

void AssociatedObject_LostFocus(object sender, RoutedEventArgs e) { //on teste le nombre de caractres contenus //si rien nest rempli alors on affecte le champ texte //de la valeur en filigrane if (AssociatedObject.Text.Length ==0) { AssociatedObject.Text = WatermarkText; AssociatedObject.Foreground = watermarkForeground; } else { AssociatedObject.Foreground = originColor; } } //on regarde si la valeur de la proprit Text correspond //au filigrane. Si elle correspond, on vide le champ texte //pour que lutilisateur puisse saisir les informations void AssociatedObject_GotFocus(object sender, RoutedEventArgs e) { AssociatedObject.Foreground = originColor; if (AssociatedObject.Text.Contains(WatermarkText)) { AssociatedObject.Text = ""; } } } }

Nous pourrions encore perfectionner ce comportement en affectant, par exemple, le ToolTip du champ de saisie par la valeur de lindication. Nous pourrions galement prvoir tous les cas de mauvaise utilisation. Que se passe-t-il si lobjet auquel on attache le comportement nest pas un champ de saisie de type TextBox? Il faudrait pouvoir le grer directement au sein de Blend. Une autre problmatique est que nous utilisons la proprit Text du champ de saisie, ainsi si le formulaire ne vrifie que la prsence ou non dune chane de caractres, lindication sera envoye en lieu et place dune saisie correcte de lutilisateur. Il faudra donc galement vrifier que la valeur du champ ne correspond pas la valeur de la proprit WatermarkText et lever une erreur si tel est le cas. Nous allons maintenant crer un autre comportement, plus volu par certains cts puisquil rend disponible la gestion des vnements.

8.5.3.2 Recopie bitmap dun composant ou comment simuler les pinceaux visuels WPF
Depuis la version3 de Silverlight, il est possible de gnrer une image bitmap partir de nimporte quelle arborescence au sein de larbre visuel. Notre comportement aura pour vocation de crer un clich bitmap dun composant auquel il est attach et de laffecter, soit la proprit Fill dune forme (Shape), soit la proprit Background dune instance de la classe Control. Au sein du panneau Projects, cliquez-droit sur le projet et choisissez le menu Add New Item... Dans la bote de dialogue qui saffiche, optez pour un comportement daction (TriggerAction), puis nommez la classe SnapshotAction.cs (voir Figure8.15).

240

Partie II

Interactivit et cration graphique

Figure8.15
Cration dun comportement daction.

Blend ouvre automatiquement le fichier SnapshotAction.cs, affichant ainsi le code gnr. Supprimez les commentaires gnrs si leur prsence vous gne:
namespace YourBehaviors { public class SnapshotAction: TriggerAction<DependencyObject> { public SnapshotAction() { } protected override void Invoke(object o) { } } }

La mthode Invoke est dclenche lorsque lvnement que le designer a choisi sera diffus. Pour mieux comprendre ce concept, compilez votre projet puis crez un rectangle sur LayoutRoot et glissez le comportement daction SnapshotAction dessus. Le panneau des proprits met en vidence les proprits paramtrables par dfaut (voir Figure8.16).
Figure8.16
Proprit dun comportement daction standard.

Chapitre 8

Interactivit et modle vnementiel

241

Comme vous le constatez, le designer peut dfinir lcoute dun vnement diffus par le sujet de son choix. Par dfaut, lobjet diffuseur de lvnement est lobjet attach. Dans notre cas, il sagit du rectangle. Le comportement est lgrement plus avanc puisque nous dsirons galement pouvoir dfinir une cible afin den crer un clich bitmap. Nous pourrions, par exemple, vouloir cibler le conteneur StackPanel contenant les champs de saisie. Pour arriver nos fins, il nous faut un comportement de type TargetedTrigger Action. Il suffit dtendre cette classe au lieu de TriggerAction. Nous allons cibler des composants utilisateur. Vous pouvez galement modifier le type paramtr comme suit:
namespace YourBehaviors { public class SnapshotAction: TargetedTriggerAction<UIElement> { public SnapshotAction() { } protected override void Invoke(object o) { } } }

Puis, compilez nouveau le projet pour voir les changements apports dans le panneau des proprits du comportement (voir Figure8.17). La nouvelle proprit TargetName a t ajoute. Il est maintenant possible de slectionner lobjet dont nous souhaitons crer un clich. Le code en lui-mme est assez simple, il faut tout dabord vrifier que lespace de noms System.Windows.Media.Imaging est rfrenc.
Figure8.17
Proprit dun comportement daction cibl.

Nous allons utiliser la classe WritableBitmap qui permet de faire linstantan de nimporte quel contrle:
protected override void Invoke(object o) { //on dclare une nouvelle image bitmap

242

Partie II

Interactivit et cration graphique

WriteableBitmap Wb; //on linstancie en lui passant lobjet //dont elle doit crer un instantan Wb = new WriteableBitmap(this.Target, null); //on cre un nouveau pinceau dimage ImageBrush Ib = new ImageBrush(); Ib.Stretch = Stretch.None; //on affecte limage binaire de linstantan //la proprit ImageSource du pinceau dimage Ib.ImageSource = Wb; //Ensuite on teste le type et on affecte //la bonne proprit en fonction de ce dernier if (AssociatedObject is Shape) ((Shape)AssociatedObject).Fill = Ib; else if (AssociatedObject is Panel) ((Panel)AssociatedObject).Background = Ib; else if (AssociatedObject is Control) ((Control)AssociatedObject).Background = Ib; }

Il ny a rien dautre faire, mis part dfinir les vnements qui invoqueront la mthode (voir Figure8.18).
Figure8.18
Paramtrage du comportement daction cibl SnapshotAction.

Voici un exemple simple du formulaire avec un effet de reflet cr laide du comportement.

Chapitre 8

Interactivit et modle vnementiel

243

Figure8.19
Effet de reflet dun formulaire en ligne via le comportement daction SnapshotAction.

Nous pourrions, encore une fois, amliorer grandement ce comportement de plusieurs manires. Lutilisation de conditions if / else if est un peu lourde et maladroite. Nous avons la possibilit de rcuprer le type de lobjet associ dynamiquement et de rechercher si ce dernier possde la proprit Fill ou Background. Nous pouvons galement automatiser la cration du reflet grce une instance de DispatcherTimer. Elle permettrait de rafrachir le clich bitmap selon un laps de temps indiqu par le designer ou le dveloppeur et plus seulement via les vnements proposs. Nous nirons cependant pas plus loin dans ce chapitre car nous avons abord lensemble des notions indispensables permettant dlaborer une interactivit performante. Vous trouverez ce projet dans les exemples de ce livre: chap8/YourBehaviors.zip. Dans le prochain chapitre, nous allons apprendre les principes de base de la projection3D. Nous pourrons ainsi amliorer le lecteur vido que nous avons conu auparavant. Nous nous servirons de la projection3D pour prototyper nos applications au sein de Blend avec le nouvel outil rvolutionnaire quest SketchFlow (Chapitre10). Il tait important dapprendre les bases du modle vnementiel avant de nous y plonger et cest maintenant chose faite.

9
Les bases de la projection3D
Dans ce chapitre, vous allez dcouvrir les bases de la 3D adaptes la plateforme Silverlight. Vous aborderez les proprits 3D dobjets et leur fonctionnement. Vous apprendrez cibler et manipuler ces proprits, au sein de linterface graphique Expression Blend, mais galement dans Visual Studio via le code logique C#. Pour finir, vous mettrez en pratique les connaissances acquises pour raliser deux exercices dont lun vous permettra damliorer le lecteur vido ralis dans le chapitre prcdent. Ainsi, vous vous confronterez aux problmatiques de production les plus courantes lorsquil sagit de crer des interfaces en trois dimensions.

9.1 Lenvironnement3D
Limage en trois dimensions, ou3D, est apparue trs tt dans les Beaux-Arts. Les peintres Pierro Della Francesca et Filippo Brunelleschi furent parmi les premiers utiliser et concevoir les techniques de perspective. Leurs uvres, bien quassez proches de celles de leurs contemporains, se dmarqurent par lutilisation de la perspective. Pierro della Francesca diffuse, lpoque, plusieurs ouvrages traitant directement de la gomtrie dans lespace. Ainsi, il est considr de nos jours comme lun des pionniers du dessin denvironnement raliste et de la renaissance artistique. Lutilisation de la perspective et par consquent la reprsentation en trois dimensions dune scne mythologique ou religieuse apporte la peinture une nouvelle vision. Si le point de fuite au sein dune perspective conique reprsente linfini, un nouvel acteur invisible est mis en valeur: le spectateur. Ce dernier, sans faire explicitement partie de la toile, participe la scne peinte ou dessine. Cest de son point de vue que celle-ci est reprsente. Ainsi, limagerie3D, quelle soit de synthse, de peinture ou de dessin, replace ltre humain au centre de laction. Elle enflamme notre imagination et nous immerge directement dans laction. Au sein des interfaces riches, elle nest pas une fin en soi, mais un moyen dexpression au mme titre quun autre. Lutilisation dune interface en pure3D se rvlerait assez catastrophique dun point de vue utilisateur. Trs peu de personnes sont aujourdhui capables de se localiser dans un environnement de ce type (les pilotes davions et les joueurs invtrs en font par exemple partie).

246

Partie II

Interactivit et cration graphique

Nen abusez donc pas dans vos interfaces et faites en sorte de toujours mettre la3D au service de lexprience utilisateur. Lobjectif final tant que ce dernier sapproprie et se plonge dans lapplication. Nous allons maintenant tudier son fonctionnement et son intgration dans la plateforme Silverlight.

9.1.1 Introduction
Au sein des moteurs de rendu, on distingue deux grandes catgories. Les moteurs3D temps rel (comme en possdent souvent les jeux vido) et les moteurs dimages3D prcalcules. Silverlight tant un moteur vectoriel interactif, il se positionne demble dans la premire catgorie. Il vous permet donc, par exemple, de dplacer des objets en redfinissant leur trajectoire lexcution. Toutefois, il ne dplacera pas rellement dobjets3D, mais simplement des projections planaires de ces derniers. Nous allons maintenant aborder ce principe. Des logiciels comme Maya,3D Studio Max, Blender, Lightwave ou Softimage font partie des deux mondes. Dun ct, ils gnrent des images prcalcules, de lautre, ils donnent accs une interface ddition labore, en3D temps rel. Alors quun environnement en 2D permet aux graphistes de crer ou modifier les objets selon un axe horizontal et vertical, nots respectivement x et y, les environnements 3D grent galement laxe z reprsentant la profondeur. Par dfaut, quatre vues sont donc proposes lutilisateur dans les logiciels que nous avons voqus: la vue de dessus, de ct, de face et une perspective avec point de fuite. Chacune de ces vues permet linfographiste de se reprer dans lespace pour mieux concevoir les objets et agencer lespace tridimensionnel. Ces vues sont en ralit des camras particulires car, mis part la vue de perspective, elles sont isomtriques, donc sans point de fuite. Une scne3D standard possde toujours au moins une camra, une lumire ainsi quun objet3D ou2D mettre en scne (voir Figure9.1).
Figure9.1
Exemple dune scne en trois dimensions.

Avec ce type de logiciels, le designer conoit et interagit avec des objets en vraie3D. Cela signifie que ceux-ci possdent une hauteur, une largeur et une profondeur. Il est toutefois possible de mettre en scne des objets en deux dimensions comme un disque ou un plan (voir Figure9.2).

Chapitre 9

Les bases de la projection 3D

247

Figure9.2
Exemple dune scne en trois dimensions avec plan2D.

Comme dans la ralit, les camras3D possdent un angle douverture ainsi quune longueur de focale dont les valeurs sont directement lies lune lautre. Modifier la focale revient modifier langle douverture et inversement. Pour finir, la camra est plus ou moins distante des objets quelle encadre. Au sein de Silverlight, le principe est exactement le mme, la diffrence prs que les camras ne sont pas des objets directement manipulables par le designer interactif, mais un point de vue abstrait, implicite et non modifiable. Nous aborderons la notion de camra de manire plus approfondie plus loin dans ce chapitre. Comme vous le constatez aux Figures9.1 et9.2, laxe des y est orient vers le haut. Ce nest pas le cas au sein de Silverlight dont les objectifs de production sont diffrents. Laxe3D des ordonnes est orient vers le bas, laxe z des profondeurs est orient vers le spectateur (voir Figure9.3).
Figure9.3
Orientation des axes x, y et z au sein de Silverlight et de linterface Blend.

Vue par dfaut au sein de Blend, des instances de UIElement dans l'environnement 3D.

Reprsentation fictive en perspective avec point de fuite, l'axe z est dirig vers l'utilisateur.

9.1.2 Le plan de projection


Depuis sa version3, Silverlight permet dafficher des objets dans un espace en trois dimensions. Toutefois, Silverlight tant lorigine un moteur vectoriel temps rel, il naffiche en premier lieu que des objets en deux dimensions. Laffichage des objets vectoriels2D est calcul par le processeur de lordinateur. Tous les contrles utilisateur hritant de UIElement ont la capacit dvoluer dans lespace3D. Pour des raisons de performances daffichage, lorsque les contrles utilisateur

248

Partie II

Interactivit et cration graphique

sont dfinis dans lespace en trois dimensions, ils sont rendus sous forme dimages bitmap projetes sur un plan. Cela vite un recalcul constant et coteux au processeur. Les objets restent interactifs et peuvent, si besoin, changer de visuel. Ainsi, un bouton peut toujours afficher un tat diffrent au survol ou au clic de la souris. Le fait de rendre les vecteurs sous forme bitmap limite grandement le nombre de calculs ncessaires laffichage; les images sont places en mmoire vive et mises jour uniquement lorsquune interaction survient. Pour placer une instance de UIElement dans lespace en trois dimensions de Silverlight, il suffit de lui appliquer une transformation3D. La conversion des vecteurs en images implique une trs lgre dgradation de laffichage des objets. Cest tout fait logique et ne se remarque que lorsque vous effectuez un zoom au sein de Blend ou que vous appliquez des transformations3D de manire extrme. Cela est d au fait que les vecteurs sont rendus sous forme dimages dont les pixels sont dfinis une fois pour toute (voir Figures9.4 et9.5).
Figure9.4
Effet de pixellisation suite la rotation dun rectangle sur laxe y.
Instance de la classe Rectangle sans projection 3D Rotation de 80 sur l'axe y

Zoom sur l'effet de pixellisation d la projection planaire bitmap

Comme vous le constatez, les bords sont lisss: pour viter un effet de crnelage, le rendu des images est automatiquement liss. Les contrles utilisateur, quels quils soient, peuvent galement subir une transformation3D (voir Figure9.5).
Figure9.5
Effet de pixellisation suite au dplacement dune CheckBox sur laxe z de500 pixels.

Avant translation sur l'axe z

Aprs translation de + 500 pixels sur l'axe z

Vous remarquez leffet pixellis gnr lors du dplacement sur laxe des profondeurs. Ceci est un effet direct de la projection bitmap. Mme si les objets ont la capacit dvoluer dans un espace en trois dimensions, ils ne possdent pas de relle profondeur. Pour cette raison, on utilise le terme de2,5D lorsque lon voque la3D dans Silverlight. Lespace est en3D, mais les objets restent en2D.

Chapitre 9

Les bases de la projection 3D

249

9.2 Les proprits3D


Nous allons maintenant tudier les proprits3D accessibles au sein de Silverlight et voir comment elles nous permettent de manipuler les objets de type UIElement.

9.2.1 Rotation3D
Les rotations reprsentent les transformations 3D par excellence car elles mettent directement le ou les points de fuite en valeur. Crez un nouveau projet nomm "Test3D". Crez ensuite un rectangle de200pixels de large par200 pixels de haut. Puis, assignez-lui un dgrad, en tant que remplissage. Vous pourriez galement utiliser un composant Image afin de mieux visualiser les effets de perspective. Pour accder aux projections3D, slectionnez le rectangle ou le contrle Image, puis, dans le panneau Properties, dpliez longlet Transform en dessous de la partie ddie aux transformations relatives: vous trouverez le menu Projection compos de quatre panneaux. Chacun deux reprsente un type de proprit3D (voir Figure9.6).
Figure9.6
Menu des projections 3D.

Le premier onglet concerne les rotations. Changez la valeur de chaque proprit de rotation. Procdez par tape afin de visualiser leur effet de manire spare (voir Figure9.7). Vous constatez quun manipulateur interactif, situ gauche des champs de saisie, vous permet galement de modifier la rotation. Toutefois, cet outil, bien quintuitif, est au final assez peu pratique car trop imprcis.
Figure9.7
Rotation3D.

Rotation sur l'axe Y

Rotation sur l'axe X

Rotation sur l'axe Z

250

Partie II

Interactivit et cration graphique

Le fait de dfinir des proprits de projection indpendamment des transformations relatives est assez rvlateur. Comme les RenderTransform, les proprits de projections3D nappartiennent pas directement aux objets, mais leurs sont attaches lorsque cela est ncessaire. Un nud est cr cette fin, voici le code XAML y faisant rfrence:
<Rectangle HorizontalAlignment="Left" Width="200" Height="200" RenderTransformOrigin="0.5,0.5"> <Rectangle.Projection> <PlaneProjection RotationY="60"/> </Rectangle.Projection> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="Black" Offset="0"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle>

Comme nous lavons dj prcis, tout UIElement possde la proprit Projection, qui accepte les instances de type PlaneProjection ou Matrix3DProjection. Comme la gestion de la3D est centralise par cette proprit, vous pouvez ds lors considrer quil est possible de mlanger les transformations relatives et les projections3D. Ces deux types de proprits sont cousines et se ressemblent donc en de nombreux points. Le code XAML ci-dessous est donc non seulement ralisable mais raliste en termes de production:
<Rectangle HorizontalAlignment="Left" Width="200" Height="200" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <TransformGroup> <ScaleTransform ScaleX="2" ScaleY="2"/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Rectangle.RenderTransform> <Rectangle.Projection> <PlaneProjection RotationY="60"/> </Rectangle.Projection> </Rectangle>

Attention, toutefois, ne pas vous perdre car il nest pas toujours facile de conceptualiser lavance le rsultat visuel manant de diffrents types de transformations. Choisissez les unes ou les autres en fonction de vos besoins. Lorsquil est possible de simuler, de manire efficace, une projection3D en utilisant une ou plusieurs transformations relatives, privilgiez toujours ce choix car les transformations relatives sont plus simples grer.

9.2.2 Laxe de rotation


La rotation3D que vous avez teste a mis en vidence un lment important: laxe de rotation. Sa position est dtermine par trois proprits : CenterOfRotationX, Center OfRotationY et CenterOfRotationZ. Le deuxime panneau, au sein du menu Projection, permet de modifier les coordonnes de cet axe afin davoir plus de contrle sur les rotations obtenues (voir Figure9.8).

Chapitre 9

Les bases de la projection 3D

251

Comme vous le constatez la Figure9.8, les valeurs admises sont relatives sur les axesx et y, il nest donc pas facile de manipuler ces proprits de manire intuitive. Sur laxex, la valeur1 correspond 100% de la largeur du rectangle, sur laxe y cette valeur correspond 100% de la hauteur de ce dernier. Par dfaut, laxe gre les rotations de manire symtrique car il est situ 50% en x et y de linstance de UIElement, soit une valeur de0.5. Ces valeurs napparaissent pas dans linterface de Blend moins de les modifier. Comme les objets nont pas dpaisseur, la valeur de UIElement sur laxe des profondeurs (z) est gale 0. Ainsi, les instances dobjets graphiques subissant une rotation sur les axes x et y ne se sont pas dplaces sur laxe des profondeurs z. De plus, sur laxe z, la plage de valeurs admises nest pas exprime en pourcentage, mais en pixels, du fait que lpaisseur est gale zro. Cela naurait, en effet, aucun sens de demander200% de0pixel dpaisseur. Vous pouvez voir, sur la droite de la Figure9.8, deux vues engendres par le repositionnement de laxe de rotation de50 pixels vers lavant. On obtient des rsultats quivalents en dplaant le centre sur les axes x ou y. Toutefois, utiliser laxe z offre plus de souplesse et se rvle pratique pour manipuler par la suite les objets en3D.
Figure9.8
Rotations avec repositionnement de laxe de rotation3D.
Rotation sur l'axe X CenterOfRotation Y = 1 Rotation sur l'axe X CenterOfRotation Y = 0 Rotation sur l'axe X CenterOfRotation Z = 50 (pixels)

Rotation sur l'axe Y CenterOfRotation X = 1

Rotation sur l'axe Y CenterOfRotation X = 0

Rotation sur l'axe Y CenterOfRotation Z = 50 (pixels)

9.2.3 Les axes de translation


Nous allons maintenant nous concentrer sur les axes de translation. Au sein de Silverlight, deux types de translations cohabitent: les translations locales et globales. Lorsque vous avez effectu une rotation3D du rectangle, vous avez galement modifi la rotation de son axe. Le dernier des quatre onglets vous permet de dplacer le rectangle de manire locale (voir Figure9.9).
Figure9.9
Inspecteur de proprits des translations3D locales.

252

Partie II

Interactivit et cration graphique

Concrtement, le dplacement local dun composant UIElement sera soumis lorientation du centre de rotation. Quel que soit lordre de vos oprations entre rotation et dplacement local, cela revient faire pivoter lobjet, puis le dplacer en suivant laxe de rotation (voir Figure9.10).
Figure9.10
Dplacement du rectangle le long de laxe de rotation local aprs une rotation effectue sur l'axe Y.
30

Rotate Y

Vous pouvez galement choisir de dplacer un objet en utilisant laxe de translation global laide du troisime onglet (voir Figure9.11).
Figure9.11
Inspecteur de proprits des translations3D globales.

Ce repre 3D global est invisible, non modifiable et fait rfrence aux coordonnes propres lcran lui-mme (Figure9.12).
Figure9.12
Laxe global de lcran.

Chapitre 9

Les bases de la projection 3D

253

La translation globale dinstances de UIElement sera soumise lorientation fige de cet axe3D immuable, quelle que soit la rotation de lobjet autour de son axe (voir Figure9.13).
Figure9.13
Rotations avec repositionnement de laxe de rotation3D.
30

Rotate Y

Quel que soit le type de translations utilises, elles seront soumises au point de fuite de la camra. Cest un assez bon moyen de mettre en vidence la perspective et les points de fuite. Pour le constater, crez cinq carrs, puis faites une rotation de90 degrs sur laxey pour chacun deux. Ensuite dplacez-les sur laxe global x afin de mettre en valeur la perspective (voir Figure9.14).
Figure9.14
Rotation de 90 sur laxe y, puis translation sur laxe global x de chaque rectangle.

Il est avantageux de dplacer les rectangles en utilisant laxe global car obtenir le mme rsultat avec laxe local demande un effort de visualisation en trois dimensions. Il nous faudrait en effet dplacer lobjet sur laxe de translation local z, ce qui peut devenir rapidement difficile grer et assez perturbant.

9.2.4 Accs et modification via C#


Les proprits de projection3D sont bien plus faciles lire et modifier que les transformations relatives. Toutefois, vous aurez le mme type de problmatique. Les proprits de projection 3D sont attaches, donc absentes par dfaut, et la proprit Projection de UIElement accepte plusieurs types dont Plane Projection. Elle est nulle par dfaut. Ainsi, vous devrez obligatoirement affecter une instance de PlaneProjection pour cibler les proprits auxquelles vous avez accs par nature dans linterface de Blend. La consquence de cette architecture au sein de Blend est directe, vous ne pouvez pas cibler une proprit de Plane Projection, au sein dun Storyboard,

254

Partie II

Interactivit et cration graphique

si le nud XAML nest pas prsent en dur. Tlchargez le projet: chap9/ProjectionPlan.zip. Ce projet va nous permettre dapprendre cibler les projections via C#. Il contient huit boutons dont lobjectif est de contrler le composant Image en trois dimensions (voir Figure9.15).
Figure9.15
Rotation de90 sur laxe y, puis translation sur laxe global x de chaque rectangle.

Le composant Image ne possde pas de nud lment XAML PlaneProjection. Le pav de flches directionnelles va nous permettre de dplacer limage sur laxe global en x et z. Les flches gauche et droite joueront une animation de rotation sur y, et celle en haut gauche, un pivotement de limage sur x. Le mieux est de stocker linstance de Plane Projection comme membre de la classe MainPage. Vous pouvez ainsi cibler les proprits de manire trs simple:
public partial class MainPage: UserControl { PlaneProjection pp = new PlaneProjection(); public MainPage() { InitializeComponent(); Logo.Projection = pp; MouseLeftButtonUp += new MouseButtonEventHandler(MainPage_ MouseLeftButtonUp); } void MainPage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { pp.RotationY +=10; } }

Bien que trs simple, cette mthode possde un inconvnient. Si le designer, sous Blend, a dj modifi certaines proprits de projection, vous risquez dcraser leur affectation. Il convient donc de tester la valeur de la proprit Projection. Si celle-ci est nulle, on peut lui associer une nouvelle instance ; si celle-ci possde dj une valeur, il convient de vrifier galement son type. Le code logique C#, en gras ci-dessous, est responsable du test de la proprit Projection:
public partial class MainPage: UserControl { PlaneProjection pp = new PlaneProjection();

Chapitre 9

Les bases de la projection 3D

255

public MainPage() { InitializeComponent(); if (Logo.Projection == null) Logo.Projection = pp; else if (Logo.Projection!= null && Logo.Projection is PlaneProjection) pp = (PlaneProjection)Logo.Projection; else throw new NotImplementedException("la projection est de type Matrix3DProjection"); MouseLeftButtonUp += new MouseButtonEventHandler(MainPage_ MouseLeftButtonUp); } void MainPage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { pp.RotationY +=10; } }

Vous pouvez galement utiliser les mthodes hrites de la classe DependencyObject, SetValue et GetValue. Toutefois, le code ncessaire est plus verbeux:
void MainPage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { //pp.RotationY = pp.RotationY +10; double ActualRYValue = (double) pp.GetValue (PlaneProjection. RotationYProperty ); pp.SetValue(PlaneProjection.RotationYProperty, ActualRYValue +10); }

Nous allons animer le composant Image de manire trs simple. Lorsque lune des flches sera presse, le composant se dplacera ou pivotera. Quand vous relcherez le bouton de la souris, lanimation de dplacement ou de rotation sera stoppe. Nous aurions pu utiliser une instance de la classe DispatcherTimer, mais cela aurait engendr plus de code C#. Afin de simplifier au maximum le code logique, les contrles utilisateur sont en majorit des instances de Repeat Button. Seul le bouton ResetPosition est de type Button. Lavantage d'un RepeatButton est dembarquer en son sein le comportement de rptition. Slectionnez le bouton nomm RotateY Left. Dans le panneau Common Properties, vous constatez que celui-ci possde des capacits supplmentaires (voir Figure9.16).
Figure9.16
Proprits Delay et Interval de la classe RepeatButton.

256

Partie II

Interactivit et cration graphique

La proprit Delay accepte une valeur entire (Int32) et permet de spcifier le nombre de millisecondes le temps dattente en position appuye avant que le comportement de rptition ne dbute. Le laps de temps entre chaque rptition, lui aussi exprim en milli-secondes, est dfini grce la proprit Interval (Int32). Le code finalis de lapplication devient trivial:
namespace ProjectionCSharp { public partial class MainPage: UserControl { PlaneProjection pp = new PlaneProjection(); public MainPage() { InitializeComponent(); if (Logo.Projection == null) Logo.Projection = pp; else if (Logo.Projection!= null && Logo.Projection is PlaneProjection) pp = (PlaneProjection)Logo.Projection; else throw new NotImplementedException("la projection est de type Matrix3DProjection"); RotateXBack.Click += new RoutedEventHandler(RotateXBack_Click); RotateYLeft.Click += RotateYLeft_Click; RotateYRight.Click += RotateYRight_Click; GoForward.Click += GoFrontward_Click; GoBackward.Click += GoBackward_Click; GoLeft.Click += GoLeft_Click; GoRight.Click += GoRight_Click; ResetPosition.Click += ResetPosition_Click; } void ResetPosition_Click(object sender, RoutedEventArgs e) { //on utilise une triple galit pour rinitialiser //les projections Logo.Projection = pp = new PlaneProjection(); } void RotateXBack_Click(object sender, RoutedEventArgs e) { pp.RotationX -=5; } void GoLeft_Click(object sender, RoutedEventArgs e) { pp.GlobalOffsetX -=10; } void GoRight_Click(object sender, RoutedEventArgs e) { pp.GlobalOffsetX +=10; } void GoBackward_Click(object sender, RoutedEventArgs e) { pp.GlobalOffsetZ -=10; }

Chapitre 9

Les bases de la projection 3D

257

void GoFrontward_Click(object sender, RoutedEventArgs e) { pp.GlobalOffsetZ +=10; } void RotateYLeft_Click(object sender, RoutedEventArgs e) { pp.RotationY +=5; } void RotateYRight_Click(object sender, RoutedEventArgs e) { pp.RotationY -=5; } } }

Comme vous le constatez, ces proprits sont facilement accessibles. Avec un peu plus de code, nous pourrions envisager des interactions3D performantes sans recourir des notions de mathmatiques complexes. Toutefois, si vous tes frus de gomtrie ou darithmtique, vous pouvez galement utiliser la classe Matrix3DProjection afin damliorer les performances et le code logique de vos interfaces. Vous pouvez tlcharger le projet: chap9/ProjectionCSharp.zip.

9.3 La camra
Nous allons maintenant approfondir les notions de conteneur3D et de camra tout en mettant en pratique ce que nous avons dj appris. Au sein de Silverlight, la camra nest pas vraiment manipulable en tant que telle. Toutefois, elle est bien prsente. La meilleure preuve de son existence est leffet de perspective ds que vous dplacez un objet dans lespace3D. La dformation des objets engendre par la perspective est directement dpendante de diffrentes proprits de la camra. Trois facteurs sont importants. Les deux premiers, directement lis, reprsentent la longueur de la focale et le champ de vision (ou field of view) qui correspond langle douverture verticale de la camra. Le dernier facteur reprsente la distance entre la lentille de la camra et lobjet cibl (voir Figure9.17).
Figure9.17
Principe de la camra.
z x UIElement

Distance Camra - UIElement 999 pixels Angle d'ouverture 57

258

Partie II

Interactivit et cration graphique

9.3.1 Position de la camra dans lespace de projection


Chaque instance de la classe UIElement possde la capacit dtre projete dans un espace indpendant. Cela signifie que chaque objet possde sa propre camra de projection3D. Par dfaut, la camra possde une position gale ActualWidth/2 et ActualHeight/2 pour les axes x et y, et cela par rapport lorigine2D de l'objet, qui est situe en haut gauche. Les proprits Actual Width et ActualHeight reprsentent la valeur relle de la largeur ou de la hauteur dun objet quel que soit son mode de redimensionnement. Si nous dplaons un objet via les proprits de mise en forme standard, la camra de projection accompagnera lobjet dans son dplacement. Nous allons illustrer ce comportement. Crez une nouvelle application Silverlight. Instanciez quatre exemplaires de Rectangle au sein de LayoutRoot et affectez leur largeur et hauteur dune valeur de100 pixels. Alignez-les au sein de la grille de manire crer un damier et appliquez leur une rotation3D de60 sur laxe y (voir Figure9.18).
Figure9.18
Principe des camras de projection indpendante.

Avant rotation de 60 sur y

Aprs rotation de 60 sur y

Comme vous le constatez, les rectangles ne sont pas mis en perspective les uns par rapport aux autres car les proprits de mise en forme standard ne font pas partie de lespace projet. Ainsi leur camra est dplace avec eux. Pour que ces rectangles bnficient de la mme perspective, il faut que leur camra respective soit place exactement au mme endroit les unes par rapport aux autres. Il ne faut donc pas les aligner grce aux proprits de mise en pages standard. Nous devons, la place, utiliser les proprits de projections3D. Supprimez tous ces rectangles et recrez-en un de100 pixels de large par100 pixels de haut. Ensuite, faites-en trois copies. Les rectangles sont maintenant superposs. Utilisez les translations globales x et y afin de les aligner pour en faire un damier, ensuite affectez chacun deux une rotation de60 sur laxe y. Cette fois, vous remarquez que leur position dans lespace3D est cohrente. Vous pouvez galement tester en les alignant grce aux translations locales, puis raffectez une rotation de60. Le rsultat est trs diffrent selon le type de translations employes (voir Figure9.19).

Chapitre 9

Les bases de la projection 3D

259

Figure9.19
Principe des camras de projection indpendantes et alignement grce aux translations globales.

Transition globale

Transition locale

Les deux types de visuels sont valables car les camras de projection propres chaque rectangle sont exactement places au mme endroit. Nous venons de dterminer un fait essentiel : les camras de projection appartiennent chaque objet et sont indpendantes les unes des autres. Il nous reste dterminer la distance par dfaut entre un UIElement et la camra sur laxez. Celleci est assez facile trouver, bien que non documente. Il vous suffit de dplacer un objet de1000 pixels en z pour ne plus voir cet objet. Il nest plus visible car il est pass derrire lobjectif de la camra. Il ne fait plus partie de son champ de vision. Blend vous donne tout de mme un aperu de son enveloppe selon la distance dont lobjet dpasse la camra. La camra est donc situe 999 pixels de linstance UIElement associe. Cette distance nest modifiable quen dplaant lobjet. Aucune proprit ne permet actuellement de modifier la position de la camra. La distance en z a t choisie de manire ce que les objets saffichent de manire2D plane face la camra et 100% de leur dimension relle lorsque ceux-ci nont pas subis de projection3D planaire.

9.3.2 Langle douverture


Langle douverture dans Silverlight est de57 degrs par dfaut. Cette valeur nest pas modifiable, elle est dfinie en dur dans le code source et conditionne directement la longueur de focale fixe 33mm. Il nest donc pas possible de modifier la dformation de perspective de manire aise. Ouvrez le projet nomm ProjectionPlan, que nous avons enrichi la section9.2.4. Compilez-le via le raccourci F5 et faites une rotation sur laxe y du contrle Image (voir Figure9.20).
Figure9.20
Rotation simple de60 sur laxe y, la camra est une distance de999 pixels en z.

260

Partie II

Interactivit et cration graphique

Leffet de perspective est directement dpendant de langle douverture et de la focale de la camra. Il est possible daccentuer cet effet avec deux transformations complmentaires. Revenez sous Blend et dfinissez une translation de +500 pixels sur laxe z du composant Image. Modifiez ensuite les transformations relatives du composant Image pour diviser par deux lchelle de lobjet. Pour cela, affectez les proprits ScaleX et ScaleY chacune de la valeur0.5. Ainsi, nous aurons limpression que lobjet est la mme distance de la camra, mais leffet de perspective d la rotation est trs accentu (voir Figure9.21). Cest un moyen assez simple permettant de simuler un grand angle de prise de vue. Toutefois cette astuce est peu prcise et vous oblige mlanger les deux types de transformations.
Figure9.21
Rotation simple de60 sur laxe y, la camra est une distance de499 pixels en z, mais lchelle de lobjet est divise par deux.

NOTE INFO

Bien que langle douverture soit de57, les objets dpassant le cne reprsentant le champ de vision de57 ne sont pas masqus. Cest une particularit du modle de projection qui est avant tout une reprsentation mathmatique simplifie dun environnement3D. Dans la vie relle, une camra ne peut simplement pas filmer les objets qui ne sont pas dans son champ de vision. Ce nest pas le cas dans Silverlight puisque la camra nexiste pas rellement.

9.3.3 Les conteneurs3D


Comme nous lavons vu prcdemment, chaque instance de UIElement possde son propre environnement de projection3D et donc sa propre camra. Cette particularit a une consquence directe sur la manire dont est gre la projection. Les conteneurs plusieurs enfants, lorsquils subissent une projection, naffectent pas cette projection dynamiquement chacun de leurs enfants. Autrement dit, les conteneurs de projection3D nexistent pas par dfaut dans Silverlight. Le rsultat visuel de comportement est assez simple dmontrer. Dans un nouveau projet, crez une grille, puis un rectangle. Affectez sur ce dernier une rotation de50 sur laxe y. Pour finir, faites une rotation sur laxe y de 50 sur la grille parente du rectangle. Si la grille possdait le comportement dun conteneur3D, le rectangle en son sein serait affich comme sil ne possdait pas de rotation car la rotation de la grille lannulerait. Or ce nest pas le cas, les projections sont calcules sparment et sont appliques lune sur lautre (voir Figure9.22).

Chapitre 9

Les bases de la projection 3D

261

Figure9.22
Projections3D sur un conteneur de type Panel et son enfant de type Rectangle.

Grille avec Rectangle pivot de 50

Grille pivote de - 50 avec Rectangle pivot de 50

Simuler le comportement dun conteneur3D est assez simple mais fastidieux. Lavantage principal de ce type de conteneur rsiderait dans sa capacit affecter les proprits de projection de tous ses enfants lorsque lon modifierait les siennes. Faire une rotation de ce conteneur appliquerait une rotation quivalente tous ces enfants. Pour reproduire ce comportement, il nous faudrait crer les enfants exactement au mme endroit dans un conteneur de type Panel, puis les dplacer de manire locale. Ainsi laxe de rotation serait commun tous les enfants. Au sein dun nouveau projet, crez cinq exemplaires de Rectangle au mme endroit dans la grille principale. Ceux-ci doivent donc tre centrs les uns par rapport aux autres (voir Figure9.23).
Figure9.23
Rectangles centrs au sein de LayoutRoot.

Le fait de centrer les rectangles les uns par rapport aux autres permet de dfinir une camra commune. Espacez-les de50 pixels sur laxe local z. Le rectangle le plus loign doit ainsi possder une position de 100 pixels en z et le plus proche une position de +100 pixels sur ce mme axe. Comme vous utilisez les proprits de projection, la camra reste commune tous (voir Figure9.24).

262

Partie II

Interactivit et cration graphique

Figure9.24
Rectangles dcals via les axes x et y de translations locales de projection3D.

Pour finir, slectionnez-les tous en mme temps, puis affectez-leur une rotation afin dobtenir un effet de perspective (voir Figure9.25). Nous simulons de cette manire le comportement dun conteneur3D. Plusieurs autres techniques existent. Vous pourriez, par exemple, grouper les objets au sein de conteneurs de type Canvas de mmes dimensions et crs aux mmes coordonnes. Lorsque vous affecteriez une projection3D ces conteneurs, les objets qui y sont contenus seraient transforms dans un environnement3D homogne.
Figure9.25
Rotation3D des rectangles.

9.3.4 Le point de fuite


Le point de fuite principal, galement appel centre de projection, correspond par dfaut aux coordonnes de la camra en x et y, linstant de la cration dun objet. Pour positionner le point de fuite, il vous suffit de crer lobjet un endroit prcis, puis de le dplacer sur laxe de translation global ou local. Toutefois, vous ntes pas oblig de reconstruire un projet depuis le dbut. Il vous suffit de modifier lalignement des objets mettre en perspective dans lenvironnement2D habituel, puis de redfinir une translation locale ou globale dans lespace3D. Sur lexemple prcdent, supprimez les rotations3D affectes aux rectangles; vous obtenez un visuel quivalent celui de la Figure9.24. Slectionnez-les tous et modifiez leurs options dalignement pour les fixer en bas droite de la grille LayoutRoot. Pour finir, dplacez-les sur laxe global de 100 en x et de 100 en y. Vous obtenez automatiquement des lignes de fuite diriges vers le coin en bas gauche de la grille, soit le point prcis sur lequel ces rectangles taient aligns dans lespace2D (voir Figure9.26).

Chapitre 9

Les bases de la projection 3D

263

Figure9.26
Effet de perspective3D par simple dplacement autour du point de fuite.

Pour que des objets partagent le mme point de fuite, il vous faudra simplement les crer aux mmes coordonnes.
NOTE INFO

Jusqu maintenant, nous avons vu deux moyens diffrents de grer lordre de superposition des objets. Lordre des enfants dun conteneur de type Panel affecte directement leur superposition. Laffectation de la proprit ZIndex permettait daffiner cette gestion en passant outre lordre daffichage de lindex de lenfant. Un troisime moyen existe, il nest toutefois activ que lorsque la proprit Projection des instances dUIElement possde une valeur, donc uniquement lorsque les enfants sont projets dans un espace 3D. La distance de lobjet la camra va directement conditionner lordre de superposition. Au sein de Silverlight, le tri sur laxe z, donc sur laxe camra objet, est gr sans aucun besoin dun quelconque calcul de votre part. Ce tri est automatique. Vous pouvez le voir luvre sur la Figure9.26. De la mme manire quavec le tri par index denfants, vous pouvez outrepasser le tri sur laxe z via la proprit2D ZIndex.

9.4 Introduction aux matrices


Jusqu maintenant, nous avons abord les transformations3D du point de vue dun graphiste. Bien que nous puissions affecter des transformations3D par C# en utilisant la classe PlanePro jection, celle-ci apparatra limite lorsque vous aurez besoin dappliquer des projections3D plus complexes aux instances dUIElement. La comprhension des matrices permet de saffranchir des limitations de la classe PlaneProjection, puisque vous pourrez utiliser Matrix3DProjection sa place. Attention, cette section est une introduction aux matrices, le but est de vous familiariser avec ce concept. Toutefois si vous ntes pas dveloppeur, vous pouvez compltement occulter cette section et utiliser la classe simplifie PlaneProjection qui rpond 60% des cas. Nous mettrons galement en parallle lAPI3D fournie par Silverlight et celle fournie par DirectX.

9.4.1 Dfinition et principes


Une matrice est une notation mathmatique permettant de reprsenter des quations, des expressions ou des donnes, de manire simplifier les calculs complexes. Elles sont particulirement utiles aux dveloppeurs denvironnement3D, mais galement aux graphistes, qui les emploient sans forcment le savoir (via les outils de modification dobjets). Elles permettent, entre autres, dappliquer des transformations aux objets dans un environnement2D ou3D. Concrtement, une

264

Partie II

Interactivit et cration graphique

matrice contient une srie de nombres (ou dexpressions renvoyant des nombres) formalise sous forme de n lignes et de n colonnes encadres par des crochets (voir Figure9.27).
Figure9.27
Diffrents exemples de matrices.

2 7 3 1 4 4
2 lignes * 3 colonnes

1 0 2 9

7 5 6 4

1 5 2 4

2 1 8 4

5 4 3 9

2 6 4 1

4 lignes * 2 colonnes

4 lignes * 4 colonnes

Les indices de ligne et de colonne permettent aux valeurs contenues dans une matrice dtre accessibles. Ils constituent un systme de coordonnes sous forme de numros de ligne et de numro de colonne. Par convention, ces coordonnes sont notes MnLigne,nColonne (voir Figure9.28).
Figure9.28
Coordonnes de membres de matrices.
M1,1 M1,2 M1,3 M2,1 M2,2 M2,3 M1,1 M1,2 M2,1 M2,2 M3,1 M3,2 M4,1 M4,2
2 lignes * 3 colonnes 4 lignes * 2 colonnes

M1,1 M1,2 M1,3 M1,4 M2,1 M2,2 M2,3 M2,4 M3,1 M3,2 M3,3 M3,4 M4,1 M4,2 M4,3 M4,4
4 lignes * 4 colonnes

Nous avons dj vu les matrices de transformations dans ce livre, mme si nous ne lavons pas formalis, notamment lorsque nous abord les transformations relatives (voir Chapitre5). Le nud TransformGroup contenant tous les types de transformation est en fait la reprsentation simplifie dune matrice de transformation2D:
<Rectangle.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform Angle="15"/> <TranslateTransform X="60" Y="40" /> </TransformGroup> <Rectangle.RenderTransform>

Son principal avantage rside dans sa facilit dutilisation. Il permet, par exemple, aux designers de faire des rotations2D, ce qui nest pas aussi simple quil y parat. Comme nous lavons dj voqu, la proprit RenderTransform des instances dUIElement accepte galement une instance de la classe MatrixTransform. Celle-ci possde la proprit Matrix acceptant une valeur (structure) de type Matrix. Cette dernire est la version brute dune matrice mathmatique constitue de trois colonnes et de trois lignes. Elle permet de contrler entirement les dformations de manire colinaire (voir Figure9.29).

Chapitre 9

Les bases de la projection 3D

265

Figure9.29
Reprsentation de la matrice de transformation vectorielle2D de Silverlight.

3 lignes * 3 colonnes

ScaleX AngleY M1,1 M1,2 AngleX ScaleY M2,1 M2,2 OffsetX OffsetY M3,1 M3,2

0 0 1

AngleX et AngleYreprsentent les proprits d'inclinaison accessibles dans l'onglet Skew, au sein du panneau des transformations relatives.

La matrice correspondant aux transformations du nud RenderTransform (celui que nous avons dcrit en XAML et qui affecte au rectangle +15 degrs pour la rotation, 60pixels de dplacement en X et40 en Y) est dcrite la Figure9.30.
Figure9.30
Reprsentation de la matrice de transformation correspondant au nud RenderTransform.
3 lignes * 3 colonnes

Cos(0.262) Sin(0.262) -Sin(0.262) Cos(0.262) 60 40 1

0 0

Les matrices sous Silverlight traitent uniquement les angles exprims en radians. La valeur 0.262 correspond un angle d'environ 15 degrs. nRadians = PI x nDegrs 180

Au sein dune matrice de transformation, la proprit exprimant la rotation nexiste pas rellement. Elle est en ralit gnre par la combinaison de linclinaison et du redimensionnement de lobjet. Voici la traduction de notre matrice ct XAML:
<Rectangle.RenderTransform> <MatrixTransform> <MatrixTransform.Matrix> <Matrix OffsetY="60" OffsetY="40" M11="0.966" M22="0.966" M12="0.259" M21="-0.259" /> </MatrixTransform.Matrix> </MatrixTransform> </Rectangle.RenderTransform>

266

Partie II

Interactivit et cration graphique

NOTE INFO

Vous remarquez que les indices aux coordonnes M31 et M32 sont directement nots OffsetX et OffsetY au sein de la structure Matrix. Les autres proprits sont accessibles par la notation Mn,m. Cela permet un dveloppeur didentifier et dutiliser simplement les proprits de la matrice qui correspondent aux translations en x et y.

La matrice de transformation2D possde trois colonnes. La troisime colonne contient M1,3=0, M2,3=0 et M3,3=1. Ces valeurs ne sont pas modifiables. Sans rentrer dans une explication mathmatique complexe, cela permet dviter les dformations ou les distorsions des objets2D lorsque ceux-ci subissent des rotations, des mises lchelle ou des inclinaisons. La matrice2D de Silverlight gre ainsi des transformations dites affines, galement appeles transformations colinaires (voir Figure9.31).
Figure9.31
Transformations affines et non affines.

Transformations 2D affines

Transformations 2D non affines

Du ct C#, une instance de MatrixTransform est affecte la proprit RenderTransform dun objet hritant de UIElement. La classe MatrixTransform possde la proprit Matrix qui contient rellement les valeurs entre crochets tudies plus haut:
MatrixTransform Mt = new MatrixTransform(); MonUIElement.RenderTransform = Mt; /* * Renvoie Identity qui fait rfrence * la matrice didentit par dfaut: *1,0,0 *0,1,0 *0,0,1 */ Debug.WriteLine(Mt.Matrix.ToString());

Dans lexemple ci-dessus, lobjet nest pas transform. Lorsque vous instanciez un nouvel objet MatrixTransform, sa proprit Matrix correspond par dfaut une matrice didentit. Une matrice didentit est neutre et napplique aucune transformation lobjet. Elle reprsente ltat de la matrice lorsque lobjet na subi aucune transformation. Vous pouvez galement instancier la structure Matrix afin dappliquer une transformation personnalise lobjet de type UIElement lors de linitialisation:

Chapitre 9

Les bases de la projection 3D

267

Matrix M = new Matrix(1,1, 0,1, 0,0); MatrixTransform Mt = new MatrixTransform(); Mt.Matrix = M; bt.RenderTransform = Mt; /* * Renvoie la matrice affecte: *1,1, *0,1, *0,0 */ Debug.WriteLine(Mt.Matrix.ToString());

Comme vous le constatez, la matrice ne renvoie pas la dernire colonne, celle-ci nest simplement pas accessible ou modifiable.

9.4.2 Les matrices3D


Au sein de Silverlight, les matrices de transformations3D suivent les mmes principes que ceux voqus ci-dessus. Elles grent toutefois les transformations non affines car elles ont pour but dafficher des objets en perspective3D, ce qui dforme les objets dans une certaine mesure. Elles sont constitues de quatre lignes et de quatre colonnes et possdent une notation par ligne quivalente celle que propose DirectX. loppos, les matrices3D fournies par OpenGL et Flash ont une notation par colonne. Vous pouvez facilement identifier le type dcriture utilis en fonction du positionnement des valeurs exprimant le dplacement (voir Figure9.32).
Figure9.32
Reprsentation des matrices3D selon les plateformes.
M1,1 M1,2 M1,3 M1,4 M2,1 M2,2 M2,3 M2,4 M3,1 M3,2 M3,3 M3,4
OffsetX OffsetY OffsetZ

M1,1 M1,2 M1,3 Tx M2,1 M2,2 M2,3 Ty M3,1 M3,2 M3,3 Tz M4,1 M4,2 M4,3 M4,4
Notation par colonne OpenGL adopte par Flash

M4,4

Notation par ligne DirectX adopte par Silverlight

NOTE INFO

Il est galement intressant de noter que laxe z nest pas dirig vers lutilisateur, mais vers lhorizon pour OpenGL et Flash, loppos de DirectX et Silverlight. On voque ce sujet la notion de repre main droite ou gauche : DirectX utilise le repre main gauche alors quOpenGL est bas sur un repre main droite. Il faut galement remarquer que mme si les matrices au sein de Silverlight hritent de DirectX, laxe y ne suit pas la mme direction. Au sein du lecteur Silverlight, il est dirig vers le bas et sous DirectX vers le haut, mais cela ne change rien aux valeurs contenues par la matrice.

La classe Matrix3DProjection est lquivalent de la classe MatrixTransform qui permet les transformations2D. Les instances de Matrix3DProjection ne sont pas affectes la proprit RenderTransform des exemplaires dUIElement, mais leur proprit Projection. La structure

268

Partie II

Interactivit et cration graphique

Matrix3D est homologue Matrix. Il est donc possible daffecter des matrices2D et3D en mme temps. Toutefois, cela est dconseill dans la majorit des situations car le rsultat devient trs vite difficile prdire. Dans tous les cas de projection, il faudra utiliser la proprit Projection Matrix de la classe Matrix3DProjection et lui affecter une instance de la structure Matrix3D. Lcriture en XAML est assez similaire celle que nous avons dj tudie plus haut, mais un peu plus verbeuse:
<Rectangle.Projection> <Matrix3DProjection> <Matrix3DProjection.ProjectionMatrix> <Matrix3D M11="1" M12="0" M13="0" M14="0" M21="0" M22="1" M23="0" M24="0" M31="0" M32="0" M33="1" M34="0" OffsetX="50" OffsetY="0" OffsetZ="0" M44="1" /> </Matrix3DProjection.ProjectionMatrix> </Matrix3DProjection> </Rectangle.Projection>

Vous pouvez galement utiliser cette criture simplifie:


<Rectangle.Projection> <Matrix3DProjection ProjectionMatrix="1,0,0,0, 0,1,0,0, 0,0,1,0, 50,0,0,1" /> </Rectangle.Projection>

En voici une version C#:


//on cre une nouvelle instance de matrice Matrix3D MyMatrix = new Matrix3D(); //On effectue une translation de50 pixels sur laxe x. MyMatrix.M11=1; MyMatrix.M12=0; MyMatrix.M13=0; MyMatrix.M14=0; MyMatrix.M21=0; MyMatrix.M22=1; MyMatrix.M23=0; MyMatrix.M24=0; MyMatrix.M31=0; MyMatrix.M32=0; MyMatrix.M33=1; MyMatrix.M34=0; MyMatrix.OffsetX=50; MyMatrix.OffsetY=0; MyMatrix.OffsetZ=0; MyMatrix.M44=1; //on cre une nouvelle instance de la classe //enveloppante Matrix3DProjection Matrix3DProjection MyMatrix3DProjection = new Matrix3DProjection(); //on lui affecte MyMatrix cre auparavant MyMatrix3DProjection.ProjectionMatrix = MyMatrix; //on affecte la proprit Projection du rectangle MonRectangle.Projection = m3dProjection;

Comme nous lavons dit plus haut, la notation apporte par les matrices prsente lavantage de faciliter les calculs mathmatiques complexes. Lopration la plus courante est la multiplication, nous allons laborder dans la prochaine section.

Chapitre 9

Les bases de la projection 3D

269

9.4.3 Oprations sur les matrices


lorigine, les matrices de transformation possdent de nombreuses mthodes facilitant leur utilisation. LAPI3D de Silverlight tant toute rcente, la plupart des mthodes que vous trouverez sous DirectX ne sont pas intgres nativement dans le lecteur. Microsoft en fournit toutefois un certain nombre au sein de la documentation de Silverlight. Vous pourrez les utiliser pour bnficier de plus de capacits. En premier lieu, il nous faut comprendre certains concepts de base permettant de manipuler des matrices de transformations3D. Si vous possdez un niveau quivalent un DEUG de Maths de premire anne, vous connaissez sans doute les matrices et pouvez passer votre chemin. Dans ce cas, vous pourriez ventuellement vous lancer dans le portage dune partie de lAPI fournie dans DirectX vers la plateforme Silverlight. Pour appliquer une transformation un objet, nous devons utiliser une matrice de transformation. Celle-ci dcrit prcisment ce que vous souhaitez modifier. Si vous voulez, par exemple, changer lchelle dune instance de200% en y, il faut commencer par crer la matrice de transformation dcrivant le redimensionnement, puis multiplier celle de lobjet par cette dernire. Lopration de multiplication est la plus utilise car elle permet dajouter de nouvelles transformations aux objets. Elle obit des rgles prcises (voir Figure9.33)
Figure9.33
Multiplication de matrices.

a b c d

Ta Tb a x Ta + b x Tc = Tc Td c x Ta + d x Tc
Matrice de transformation appliquer.

a x Tb + b x Td c x Tb + d x Td

Matrice de l'objet source modifier.

Matrice finale de l'objet une fois transform.

Comme vous le constatez, nous multiplions les valeurs contenues dans les colonnes par les valeurs prsentes au sein des lignes. Vous pouvez multiplier une matrice A par une matrice B partir de linstant ou le nombre de colonnes de A est gal au nombre de lignes de B. Il est ainsi possible de multiplier une matrice dfinie sur une ligne etquatre colonnes, par une autre de quatre lignes et de quatre colonnes.
NOTE INFO

Du fait de la notation par ligne utilise par Silverlight et hrite de DirectX, lordre de la multiplication est spcifique. Dans notre cas, la premire matrice symbolise lobjet transformer alors que la seconde dsigne la matrice de transformation. loppos, dans lenvironnement de dveloppement OpenGL et Flash, la premire des deux matrices reprsente la matrice de transformation, la seconde est la matrice de lobjet modifier.

Il est peut-tre utile de multiplier deux matrices de transformation entre elles. Par exemple, lune pourrait modifier lchelle en y, et lautre affecterait linclinaison en x (voir Figure9.34).

270

Partie II

Interactivit et cration graphique

Figure9.34
Multiplication de matrices de transformation.

1 0 0 0

0 2 0 0

0 0 1 0

0 0 0 1

1 1 0 0

0 1 0 0

0 0 1 0

0 0 0 1

1 2 0 0

0 2 0 0

0 0 1 0

0 0 0 1

Redimensionnement 200% en y.

Inclinaison de 45 en X.

Matrice de transformation finale, l'inclinaison conserve une valeur de 45 car elle est applique aprs le redimensionnement.

Il reste multiplier la matrice gnre par celle de lobjet pour appliquer les deux transformations en une seule fois. Il est ais de comprendre pourquoi la multiplication de matrice nest pas commutative, cest--dire que lopration Matrice1 x Matrice2 est diffrente de Matrice2 x Matrice1. Si nous reprenons le mme exemple en inversant lordre des matrices, nous nobtenons pas le mme rsultat (voir Figure9.35).
Figure9.35
Ordre invers de la multiplication de matrice initiale.

1 1 0 0

0 1 0 0

0 0 1 0

0 0 0 1

1 0 0 0

0 2 0 0

0 0 1 0

0 0 0 1

1 1 0 0

0 2 0 0

0 0 1 0

0 0 0 1

Inclinaison de 45 en X.

Redimensionnement 200% en y.

Matrice de transformation finale, l'inclinaison en x subit le redimensionnement, elle n'est donc plus gale 45.

Visuellement, la diffrence est flagrante entre les deux multiplications (voir Figure9.36).
Figure9.36
Deux rsultats visuels diffrents selon lordre de multiplication.

1 - Matrice de redimensionnement * 2 - Matrice d'inclinaison

1 - Matrice d'inclinaison * 2 - Matrice de redimensionnement

Comme nous lavons dj voqu plus haut, la rotation nest en fait quune combinaison dinclinaisons et de redimensionnements.
NOTE INFO

Pour le vrifier, vous pouvez prendre nimporte quelle instance de la classe UIElement, puis modifier ses transformations relatives AngleX et AngleY et les affecter respectivement dun angle et de son oppos. Si vous utilisez les valeurs30 et 30, vous remarquez que lobjet subit une rotation ainsi quun agrandissement engendr par les deux inclinaisons combines. Pour palier ce redimensionnement, il faut galement affecter lchelle en x et y (proprits ScaleX et ScaleY) par le cosinus de langle dinclinaison.

Chapitre 9

Les bases de la projection 3D

271

Cest exactement le mme principe pour les matrices3D sauf que nous devons prendre en compte laxe z. Il faut en fait rflchir par plan. La rotation seffectue dans tous les cas sur un plan deux axes. Cest galement le cas pour les matrices de transformation2D permettant les rotations sur le plan xy car la rotation seffectue autour dun axe z abstrait. Nous ne rentrerons pas dans lexplication des formules mathmatiques car cela sort du cadre de ce livre. Toutefois, il suffit dassimiler la rotation dans un environnement2D pour comprendre ces dernires. Nous allons identifier leur emplacement (voir Figure9.37).
Figure9.37
Identification des oprations de rotation dangle a dans la matrice3D Silverlight.
cos(a) -sin(a) sin(a) cos(a)

0 0 1

0 0 0 1

cos(a)

0 1 0

-sin(a)

0 0 0 1

1 2 0

0 0 0 1

1
sin(a)

0
cos(a)

cos(a) -sin(a) sin(a) cos(a)

OffsetX OffsetY OffsetZ


Rotation sur le plan xy autour de l'axe z.

OffsetX OffsetY OffsetZ


Rotation sur le plan xz autour de l'axe y.

OffsetX OffsetY OffsetZ


Rotation sur le plan yz autour de l'axe x.

Le sens de rotation est directement li au fait que les inclinaisons x et y possdent des valeurs opposes. Pour linverser, vous pouvez affecter la valeur sin(a) M21 et sin(a) M12. Dans ce cas, le sens de rotation est loppos de celui gnr par la matrice montre la Figure9.37. Il serait pratique de centraliser les mthodes qui facilitent la manipulation de matrice3D. cette fin, nous pouvons crer une classe statique Matrix3DUtils contenant, entre autres, des mthodes statiques de rotation, de translation ou de redimensionnement:
public static Matrix3D RotateZTransform ( double a ) { //langle a est exprim en radians double sin = Math.Sin(a); double cos = Math.Cos(a); Matrix3D m = new Matrix3D(); m.M11 =cos; m.M12 =sin; m.M13 =0; m.M14 =0.0; m.M21 =-sin; m.M22 =cos; m.M23 =0.0; m.M24 =0.0; m.M31 =0; m.M32 =0.0; m.M33 =0.0; m.M34 =0.0; m.OffsetX =0.0; m.OffsetY =0.0; m.OffsetZ =0.0; m.M44 =1.0; //on retourne la matrice permettant dappliquer la rotation return m; }

Son utilisation faciliterait grandement la transformation dinstances de type UIElement:


Matrix3DProjection M3P = new Matrix3DProjection(); Matrix3D M3D = new Matrix3D(); void MainPage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //on applique une rotation de15 lors du clic gauche de la souris M3D *= Matrice3DUtils.RotateZTransform(15*Math.PI/180); M3P.ProjectionMatrix = M3D; MonRectangle.Projection = M3P; }

272

Partie II

Interactivit et cration graphique

9.4.4 Initialiser une vue perspective


La classe Matrix3D ne fournit pas de perspective par dfaut. Microsoft a volontairement fourni les briques les plus lmentaires afin que les dveloppeurs puissent raliser leur propre moteur3D. Cela permet douvrir le champ des possibilits mais demande quelques connaissances en mathmatique. Vous devez donc passer par plusieurs tapes pour simuler un espace en3D: 1. Choisir la valeur de langle douverture de la camra factice (nomm Field Of View ou FOV en anglais) dont nous avons voqu le rle la section9.3.2. 2. Crer une matrice dfinissant le centre de transformation3D de lobjet projet. 3. Positionner lobjet dans lespace3D linitialisation. 4. Gnrer une matrice simulant leffet de perspective en fonction de langle douverture. 5. Dfinir les limites du champ douverture. Toutes ces initialisations importantes sont fournies aux designers par la classe Plane Projection. Cette classe est malgr tout limite et ne permet pas de modifier la focale, la direction de la camra ou un redimensionnement3D de lobjet projet. Pour bnficier de ce type de contrle personnalis, vous devrez gnrer toutes les matrices dcrites par les tapes que nous venons de lister. Heureusement, Microsoft les propose dans la documentation de Silverlight. Toutefois le code fourni nest pas comment, et les valeurs passes dans lappel de certaines de ces fonctions ainsi que la dfinition de lune dentre elles mritent quelques rajustements afin dtre utilises facilement. Gardez lesprit que lordre dans lequel sont affectes les matrices est rellement important. Voici le code modifi et comment de lappel des mthodes gnrant chaque matrice ainsi que leur affectation la proprit Projection dune instance:
private void AppliquerScene3D(object sender, MouseButtonEventArgs e) { //on dfinit un angle douverture de60 double FovY =60*Math.PI /180; //On cre une matrice dplaant lobjet afin de //repositionner au milieu son centre de transformation //Par dfaut le centre de transformation est au milieu Matrix3D RecentrerPivotDeRotation = TranslationTransform (-BeachImage.ActualWidth /2.0, -BeachImage.ActualHeight /2.0, 0); //angle de rotation double Angle =60.0 * Math.PI /180.0; //diverses matrices de transformation Matrix3D RotationAutourDeX = RotateXTransform(Angle); Matrix3D TranslationSurX = TranslationTransform(200,0,0); Matrix3D RotationAutourDeY = RotateYTransform(Angle); Matrix3D RotationAutourDeZ = RotateZTransform(Angle); //Translation de lobjet afin quil prenne //par dfaut la largeur et la hauteur correspondant // sa reprsentation2D. double TranslationZ = -(LayoutRoot.ActualHeight/2)/Math.Tan(FovY/2); //on gnre une matrice qui loigne lobjet de la camra sur z Matrix3D EloignerObjetDeLaCamera = TranslationTransform (0,0, TranslationZ);

Chapitre 9

Les bases de la projection 3D

273

//Cration de la matrice simulant la perspective //Param1: Angle douverture //Param2: Rapport largeur/hauteur //Param3: Le plan de visibilit le plus proche //Param4: Le plan de visibilit le plus loign Matrix3D EffetDePerspective = PerspectiveTransformFovRH (fovY, LayoutRoot.ActualWidth / LayoutRoot.ActualHeight, 1.0, 2000.0); //Matrice dcrivant la fentre douverture Matrix3D CadreVisible = ViewportTransform (LayoutRoot.ActualWidth, LayoutRoot.ActualHeight, BeachImage.ActualWidth, BeachImage.ActualHeight); //1 - on replace lobjet par rapport // son centre de transformation Matrix3D M = RecentrerPivotDeRotation; //2 - on lui applique toutes les transformations que lon souhaite, //une rotation ainsi quun dplacement sur x dans le cas suivant M = M * RotationAutourDeX; M = M * TranslationSurX; //M = M * RotationAutourDeY; //M = M * RotationAutourDeZ; //3 - on le positionne distance de la camra M = M * EloignerObjetDeLaCamera; //4 - on lui applique leffet de perspective M = M * EffetDePerspective; //5 - on laffiche dans un espace dlimit M = M * CadreVisible; //6 - affectation de la matrice finalise m Matrix3DProjection M3DProjection = new Matrix3DProjection(); M3DProjection.ProjectionMatrix = M; MonUIElement.Projection = M3DProjection; }

Vous remarquez que les transformations appliquer un objet doivent tre affectes avant que les matrices simulant la perspective soient apposes ce dernier. Vous pourriez ainsi stocker dans une matrice unique le positionnement de lobjet, la perspective et les limites du cadre de visualisation. De cette manire, vous finiriez toujours par appliquer cette matrice en dernier lieu aprs avoir modifi lobjet projet. Voici les dfinitions de mthodes gnrant les matrices de transformation3D simples:
private Matrix3D TranslationTransform(double tx, double ty, double tz) { Matrix3D m = new Matrix3D(); m.M11 =1.0; m.M12 =0.0; m.M21 =0.0; m.M22 =1.0; m.M31 =0.0; m.M32 =0.0; m.OffsetX = tx; m.OffsetY return m; } m.M13 m.M23 m.M33 = ty; =0.0; m.M14 =0.0; =0.0; m.M24 =0.0; =1.0; m.M34 =0.0; m.OffsetZ = tz; m.M44 =1.0;

private Matrix3D ScaleTransform(double sx, double sy, double sz)

274

Partie II

Interactivit et cration graphique

{ Matrix3D m = new Matrix3D(); m.M11 = sx; m.M12 =0.0; m.M13 =0.0; m.M14 m.M21 =0.0; m.M22 = sy; m.M23 =0.0; m.M24 m.M31 =0.0; m.M32 =0.0; m.M33 = sz; m.M34 m.OffsetX =0.0; m.OffsetY =0.0; m.OffsetZ return m; } private Matrix3D RotateYTransform(double theta) { double sin = Math.Sin(theta); double cos = Math.Cos(theta); Matrix3D m = new Matrix3D(); m.M11 = cos; m.M12 =0.0; m.M13 = sin; m.M14 =0.0; m.M21 =0.0; m.M22 =1.0; m.M23 =0.0; m.M24 =0.0; m.M31 = -sin; m.M32 =0.0; m.M33 = cos; m.M34 =0.0; m.OffsetX =0.0; m.OffsetY =0.0; m.OffsetZ =0.0; m.M44 =1.0; return m; } private Matrix3D RotateZTransform(double theta) { double cos = Math.Cos(theta); double sin = Math.Sin(theta); Matrix3D m = new Matrix3D(); m.M11 = cos; m.M12 = sin; m.M13 =0.0; m.M14 =0.0; m.M21 = -sin; m.M22 = cos; m.M23 =0.0; m.M24 =0.0; m.M31 =0.0; m.M32 =0.0; m.M33 =1.0; m.M34 =0.0; m.OffsetX =0.0; m.OffsetY =0.0; m.OffsetZ =0.0; m.M44 =1.0; return m; } private Matrix3D RotateXTransform(double theta) { double cos = Math.Cos(theta); double sin = Math.Sin(theta); Matrix3D m = new Matrix3D(); m.M11 =1.0; m.M12 =0.0; m.M13 =0.0; m.M14 =0.0; m.M21 =0.0; m.M22 = cos; m.M23 = sin; m.M24 =0.0; m.M31 =0.0; m.M32 = -sin; m.M33 = cos; m.M34 =0.0; m.OffsetX =0.0; m.OffsetY =0.0; m.OffsetZ =0.0; m.M44 =1.0; return m; } =0.0; =0.0; =0.0; =0.0; m.M44 =1.0;

Voici les mthodes qui grent les effets de perspective, ainsi que le positionnement de ce dernier au sein dune fentre:
private Matrix3D PerspectiveTransformFovRH (double fieldOfViewY, double aspectRatio, double zNearPlane, double zFarPlane) { double height =1.0 / Math.Tan(fieldOfViewY /2.0); double width = height / aspectRatio; double d = zNearPlane - zFarPlane; Matrix3D m = new Matrix3D(); m.M11 = width; m.M12 =0; m.M13 =0; m.M14 =0; m.M21 =0; m.M22 = height; m.M23 =0; m.M24 =0;

Chapitre 9

Les bases de la projection 3D

275

m.M31 =0; m.M32 =0; m.M33 = zFarPlane / d; m.M34 = -1; m.OffsetX =0; m.OffsetY =0; m.OffsetZ = zNearPlane * zFarPlane / d; m.M44 =0; return m; } private Matrix3D ViewportTransform (double viewPortWidth, double viewPortHeight, double projectedObjectWidth, double projectedObjectHeight) { Matrix3D m = new Matrix3D(); m.M11 = viewPortWidth /2.0; m.M12 =0.0; m.M13 =0.0; m.M14 =0.0; m.M21 =0.0; m.M22 = viewPortHeight /2.0; m.M23 =0.0; m.M24 =0.0; m.M31 =0.0; m.M32 =0.0; m.M33 =1.0; m.M34 =0.0; m.OffsetX = projectedObjectWidth /2.0; m.OffsetY = projectedObjectHeight /2.0; m.OffsetZ =0.0; m.M44 =1.0; return m; }

Dans tous les cas, nous ne faisons que simuler un environnement3D travers la dformation de lobjet lui-mme. Les mthodes de perspective et de cadrage sont une combinaison de redimensionnements, dinclinaisons et de translations de lobjet. Vous pouvez maintenant vous amuser modifier la valeur de langle douverture pour obtenir des effets de camra intressants (voir Figure9.38).
Figure9.38
Diffrentes longueurs de focale.

Rotation en x de 50 Angle d'ouverture de 60

Angle d'ouverture de 90

Angle d'ouverture de 120

Le projet finalis est dans larchive des exemples du livre: chap9/Simple3DScene.zip. Vous pouvez amliorer le code propos ci-dessus en crant, par exemple, des mthodes ou des proprits de translations locales et globales quivalentes celles fournies par la classe simple Plane Projection. Vous pourriez galement afficher les deux faces dun objet de manire distincte et ainsi commencer dvelopper votre propre minimoteur de projection3D pour Silverlight. Dans cette optique, je mets disposition une bibliothque gratuite nomme3DLightEngine. Vous la trouverez sur mon blog: http://www.tweened.org. Son code est compltement ouvert la modification et vous pouvez ladapter selon vos besoins. Dans le prochain chapitre, nous aborderons le prototypage dapplications riches via la technologie SketchFlow. La 3D jouera sans aucun doute un rle prpondrant en matire d'exprience utilisateur dans les prochaines annes. Au Chapitre 10, nous utiliserons nos connaissances acquises en 3D pour ajouter une touche de profondeur aux diffrents panneaux de notre application, et amliorer ainsi son ergonomie.

10
Prototypage dynamique avec SketchFlow
Dans ce chapitre, vous dcouvrirez un nouvel outil de prototypage nomm SketchFlow. Bien quil soit intgr Expression Blend, vous ntes pas oblig davoir lu la totalit des chapitres prcdents ou davoir une connaissance approfondie de Blend pour utiliser SketchFlow. Sa facilit dutilisation est lun de ses grands avantages. Que vous soyez responsable de production, directeur technique ou artistique ou encore designer, ce chapitre vous concerne pleinement. Nous y aborderons le prototypage et nous crerons un premier prototype grce SketchFlow. Lun des objectifs de SketchFlow est de faciliter la communication entre les diffrents acteurs du dveloppement afin darriver un consensus. Dans cette optique, nous listerons les moyens mis disposition par SketchFlow pour uvrer en ce sens. Pour finir, nous tudierons les outils facilitant linteractivit utilisateur, ainsi que les diffrentes approches existantes pour la conception dinterfaces utilisateur.

10.1 Lenvironnement
Si SketchFlow est un outil de prototypage, la notion mme de prototype revt des formes nuances ainsi quune mise en pratique diffrente selon les environnements de production rencontrs. Dans cette section, nous allons dfinir ce terme et tudier lintgration de SketchFlow au sein du flux de production. Pour finir, nous listerons les principes et moyens mis en uvre par ce dernier lui permettant de se positionner comme outil de prototypage dynamique.

10.1.1 Le prototypage
Le prototype, mme sil na pas toujours t formalis comme tel, est sans doute lune des notions les plus vieilles de lhistoire de lhumanit. Il y a toujours une premire fois. La premire massue, le premier vlo, le premier avion, et mme la premire souris (voir Figure10.1) ont tous t invents et rapidement mis lpreuve un beau jour. Mme sils nont pas t ds le dpart de

278

Partie II

Interactivit et cration graphique

francs succs techniques ou populaires, ils sont devenus des objets indispensables que lhomme na jamais cess damliorer par la suite.
Figure10.1
Lune des premires souris, cre en1967 (source WikiPedia).

En industrie, un prototype est le premier ou lun des premiers exemplaires fonctionnels dun produit industriel (que lon peut produire en grande quantit de manire rentable). Aujourdhui, le prototypage est trs troitement li au design. Un objet "design" peut se dfinir par trois termes: industrialisable, esthtique et ergonomique. Le but des coles de design est concentr exclusivement autour de la cration de prototypes industriels qui doivent runir ces trois qualits. Si aujourdhui ce concept est totalement intgr lindustrie, cela nest pas forcment de mise concernant le dveloppement informatique. Lindustrialisation du dveloppement informatique nen est aujourdhui qu ses balbutiements, noublions pas que linformatique est un domaine trs jeune compar aux industries traditionnelles. Il est de plus assez difficile dappliquer les recettes de succs industriels dans la conception informatique. En premier lieu, une application est thoriquement unique. Son dploiement ou encore les processus de production peuvent tre industrialiss, mais il ne sert rien de reproduire la mme application250fois. Lorsque lon parle dindustrialisation en matire de dveloppement informatique, on voque plus gnralement la standardisation des procds et des tapes de dveloppement en quipe. En second lieu, une agence web, un studio de cration ou une socit de dveloppement informatique (dans une moindre mesure) doivent produire un site ou une application interactive riche dans des dlais parfois trs courts. Cette phase est donc trs souvent occulte ou alors compltement fusionne la phase de conception graphique. Ce nest pas le cas de produits hardware industriels qui peuvent bnficier de plusieurs annes de production. Il existe toutefois deux phases essentielles, communes au dveloppement informatique et lindustrie: une premire phase de croquis et une seconde de prototypage, qui lancera ou non la mise en production. La moindre bouteille deau en plastique est le rsultat dun prototype, lui-mme tant le rsultat dun schma technique ou dun croquis. Certains logiciels, tels que Catia de Dassault industrie ou Alias Design de la socit Autodesk, permettent aux cratifs de sexprimer tout en avanant les phases de prototypage et dindustrialisation. La souris Arc Mouse de Microsoft a suivi ces tapes avant de pouvoir tre produite en masse et commercialise (voir Figure10.2).

Chapitre 10

Prototypage dynamique avec SketchFlow

279

Figure10.2
Prototype de la souris Arc Mouse (source: site Microsoft Expression).

De nos jours, les phases de croquis et de prototypage sont trs rapproches. Elles sont parfois fondues en une seule grce loutil informatique (cette pratique est encore souvent conteste). Lun des buts poursuivi par SketchFlow est de rduire le temps de conception global. Il entre donc prcisment dans la catgorie doutils liant ces deux phases, mais il permet galement de se rapprocher de lapplication finale. Jusqu quel point le prototype doit se rapprocher ou tre transformer en application est une question actuellement en dbat. Il facilite ainsi la communication entre les cratifs et les ingnieurs. Quel que soit lenvironnement, plusieurs objectifs sont atteints grce au prototype:

Il permet de valider les choix de recherche, dapproche et de conception. Il valide le bon fonctionnement, lergonomie et peut mettre en valeur d'ventuelles intentions de couleurs. Il facilite la correction des erreurs de conception.

Tous ces objectifs sont raliss travers la communication et lchange dides entre les diffrentes parties impliques. Le prototype permet donc datteindre un consensus ncessaire la mise en production. Il faut parfois beaucoup de prototypes avant darriver la version industrialisable dun objet. Quelles que soient les parties impliques dans sa cration, financire, technique, artistique, etc., le prototype permet chacun d'changer et de communiquer ses impressions, et cest l sa grande force. Nous allons maintenant voir comment SketchFlow reprend cette philosophie et engendre plus de productivit et des dveloppements de meilleure qualit.

10.1.2 Quest-ce que SketchFlow?


SketchFlow nest pas un, il est en ralit constitu dun ensemble dlments complmentaires qui ont t introduits dans la version3 dExpression Blend. Il est tout dabord reprsent par un type de projet spcifique gnr via Expression Blend. Visual Studio n'est pas l'outil de prdilection pour prototyper. Cela est logique : la notion de prototype est inhrente celle de design et Blend est avant tout un outil de designer. De plus, lobjectif est de mettre un outil de prototypage disposition des profils cratifs et techniques. Le logiciel Visual Studio nest pas appropri car il demande beaucoup dexprience et fait avant tout appel des comptences de codeur. Son interface en termes de design est limite, compare celle de Blend.

280

Partie II

Interactivit et cration graphique

NOTE INFO

SketchFlow se veut simple et accessible afin de fdrer les acteurs dune production autour dun outil accessible tous. Vous pouvez galement le percevoir comme un enjeu social. Au sein de ce livre, nous avons souvent voqu le flux de production cratif et technique. SketchFlow est lun des outils permettant de rassembler les deux mondes trop longtemps spars dans lhistoire du dveloppement informatique.

Les projets SketchFlow permettent daccder un ensemble de panneaux ddis. Ils sont inaccessibles au sein de linterface de Blend dans le cadre de projets standard. Nous verrons leur utilisation tout au long de ce chapitre. Vous pourrez gnrer des prototypes bass sur SketchFlow aussi bien pour WPF que pour Silverlight (voir Figure10.3). De ce point de vue, il ny a pas de diffrences entre les fonctionnalits proposes sur lune ou lautre de ces plateformes.
Figure10.3
Les projets SketchFlow sous Expression Blend pour Silverlight et WPF.

Le prototypage via SketchFlow consiste avant tout concevoir la navigation, lergonomie, les transitions et lexprience utilisateur de manire globale. Les projets SketchFlow contiennent par dfaut le style Sketch (croquis) pour les contrles utilisateur. Ainsi, lon saffranchit totalement du design de la charte graphique, qui vient aprs ces tapes. Cela peut paratre inutile puisque les composants par dfaut connaissent les mmes fonctionnalits. Ce style est pourtant lun des lments indispensables constituant SketchFlow. Il permet aux non initis dExpression Blend de prendre en main rapidement un projet avec une utilisation minimale du panneau des proprits. Lobjectif est galement de placer lutilisateur dans une rflexion sur lergonomie, lexprience utilisateur, en mode croquis rapide. Lerreur serait de se focaliser sur la production graphique directe, il vaut mieux rendre cette phase abstraite et moins importante dans un premier temps. Vous trouverez souvent plusieurs styles Sketch pour un mme composant. Le contrle TextBlock existe en version align droite, gauche, titre ou bloc de texte, etc. Ainsi, les adeptes de Blend ne sont plus les seuls pouvoir mettre en forme une application. Vous pouvez accder aux styles via le panneau Assets (voir Figure10.4). Encore une fois, le but est de permettre au plus grand nombre daccder la cration de prototypes. Le code logique est donc par dfaut viter car seuls les dveloppeurs ou les designers interactifs confirms peuvent le crer ou le modifier. Un jeu de comportements interactifs spcifiques (Behaviors) est fourni cette fin (voir Figure10.5). Ils sont accessibles via le panneau Assets et sont utilisables de manire simplifie grce de nouveaux menus contextuels. Ceux-ci permettent de les utiliser sans avoir les dposer sur un contrle et les configurer. La cration des prototypes en est grandement acclre.

Chapitre 10

Prototypage dynamique avec SketchFlow

281

Figure10.4
Le panneau Assets sous Blend donnant, entre autres, accs aux styles.

Figure10.5
Les comportements spcifiques SketchFlow.

Pour finir, nous avons voqu depuis le dbut la collaboration intermtiers, mais cela ne serait pas possible sans un outil centralisant et permettant chacun de fournir ses propres impressions. Cest le rle du lecteur SketchFlow. Lorsque vous testez un projet dans le navigateur, le prototype est affich au sein de ce lecteur (voir Figure10.6). Ce dernier donne accs un certain nombre de fonctionnalits aux utilisateurs de lapplication, quels quils soient. Nous tudierons son utilisation la section10.3.
Figure10.6
Le lecteur SketchFlow visible lors de la premire compilation.

282

Partie II

Interactivit et cration graphique

Vous pouvez finalement remarquer que la compilation ne donne pas accs lapplication finalise. Produire une application finalise et optimise nest videmment pas le but de SketchFlow. Vous pourrez toutefois dtacher le cur de votre application grce aux comptences de dveloppeurs et de designers interactifs, mais ce nest pas toujours conseill. Plus lapplication que vous dvelopperez sera complexe et moins cette manire de procder sera viable.

10.1.3 Le flux de production


SketchFlow est utilisable deux niveaux. Dans un premier temps, les projets sont crs par les acteurs directs de la production, quils soient concepteurs techniques ou artistiques:

Comme nous lavons voqu, prototype et design sont lis. SketchFlow sadresse donc avant tout aux designers dans un sens large. Les designers dexprience utilisateur (UX Designers) sont la cible la plus vidente. Ces derniers ont charge de proposer des interfaces intuitives et ergonomiques sans pour autant sattarder sur le graphisme proprement dit. En second lieu, viennent les designers interactifs qui possdent une connaissance de Blend et occupent un rle central dans le flux de production. Ils sont mme dtablir une communication entre les profils techniques et artistiques. Si vous tes graphiste ou directeur artistique, la prise en main technique simplifie de SketchFlow a t conue afin de vous donner un maximum de confort et de productivit. Les dveloppeurs dapplications clientes Winforms ou WPF et de RIA pour Silverlight utiliseront rapidement SketchFlow dans leurs futurs projets afin de concevoir les arborescences et crans de leurs applications. Ils pourront de cette manire acqurir de nouvelles comptences, de prime abord inhrentes aux designers, tout au long des projets. Les architectes dapplications ou dinformations, dont le rle est de proposer des structures organises et performantes, peuvent galement dtourner SketchFlow afin de crer des arborescences complexes, faciles maintenir et partager.

Sur un tout autre plan, SketchFlow est utilisable par les responsables:

Les responsables de projets, les directeurs artistiques, les responsables de production peuvent participer pleinement au projet par le biais de leur feedback. Pour cela, ils peuvent utiliser le lecteur SketchFlow qui permet de communiquer sur le prototype durant sa cration. Le client fait partie du processus de cration. Avec SketchFlow, il devient facile de trouver un consensus, de proposer plusieurs maquettes fonctionnelles ainsi quune direction avant de se lancer dans la production pure et dure.

Vous laurez compris, SketchFlow est un outil de prototypage dynamique et transverse. Dynamique, du fait de la souplesse et de lefficacit quil propose pour passer dune ide une autre et donner un aperu en temps rel des dcisions prises. Transverse car il est facile daccs et quil favorise la communication intermtiers au sein dune production. En bref, le prototype est fait pour tre test et approuv, SketchFlow est donc laffaire de tous. Attention toutefois un axiome bien connu des designers : le cur dune ide est mis par une personne ou deux, celle-ci peut-tre toffe, mais il faut une direction tous projets. Quand une application doit plaire de nombreuses parties et que ces dernires sont dcideuses, le risque de perdre la force de lide originale est lev. Il faudra souvent soumettre plusieurs prototypes avant de trouver le juste milieu, celui-ci pourrait toutefois ne pas tre si enthousiasmant que cela.

Chapitre 10

Prototypage dynamique avec SketchFlow

283

Pour finir, SketchFlow impose dabord une mthodologie efficace dans le flux de production. Cest un lien direct avec le client. La relation doit tre gagnant /gagnant entre prestataire de services et client. Il faut commencer par proposer des maquettes fonctionnelles et ainsi faire vivre le projet. Ce qui avant tait fig est maintenant volutif. Auparavant plusieurs storyboards taient dessins et reprsentaient le scnario interactif de lutilisateur. Le client en choisissait un ou deux, mettait des commentaires et on se lanait dans une sorte de "proof of concept" qui prenait non seulement du temps et de largent, mais qui en plus ntait peut-tre pas valide en fin de parcours. Aujourdhui, travers SketchFlow, nous nous appuyons sur les croquis et storyboards pour crer un prototype dont le scnario, la mise en forme et linteractivit peuvent voluer dans le temps en un minimum de temps et defforts. Le prototype fourni fait en quelque sorte figure de cahier de recette et de contrat autour duquel clients et prestataires peuvent saccorder.

10.2 Prototype simple


Nous allons maintenant crer un premier prototype simple que nous tofferons au fur et mesure des notions abordes. Pour raliser les exercices qui vont suivre, dcompressez les fichiers: chap10/Assets.zip.

10.2.1 Problmatique cliente


Dans tous projets, il faudra proposer des croquis de diffrentes maquettes rpondant la problmatique du client. Ce dernier peut mme vous fournir lui-mme des croquis des diffrentes pages de lapplication. Nous allons prendre lexemple dun concessionnaire de vhicule automobile. Celui-ci souhaite un site vitrine afin de mettre en valeur son savoir-faire et la qualit des voitures vendues. Faisant partie dun secteur trs concurrentiel, il souhaite galement se dmarquer, en proposant aux visiteurs du site la possibilit de choisir la voiture de leur rve travers lutilisation dun configurateur riche. Nous dtaillerons ce terme la section10.5.2. Le configurateur riche doit tre accessible au sein du site sous forme dapplications Silverlight. Afin de crer un premier prototype, le client fournit une premire bauche de maquette sous forme de cinq croquis simples que nous avons numriss, puis retouchs sous Photoshop. Nous avons ajout un code couleur pour chaque page et menu afin de reconnatre facilement les pages du futur site. Ces croquis reprsentent lensemble des pages du site quil souhaite mettre en ligne (voir Figure10.7). La premire page reprsente la page daccueil du site donnant accs toutes les autres pages. La deuxime liste les critres certifiant la qualit cologique des vhicules. La troisime dcrit les prestations diverses et le service aprs-vente. La quatrime page met en avant linnovation technologique et lergonomie dutilisation des vhicules les plus rcents, grce une galerie dimages et un lecteur vido. La cinquime page contient le configurateur riche, celui-ci permettra au visiteur de trouver le vhicule idal en fonction de critres. Nous allons utiliser SketchFlow pour lui proposer une maquette fonctionnelle du site global, puis nous mettrons laccent sur le configurateur riche. De ce point de vue, SketchFlow peut vous permettre de prototyper nimporte quel type darborescence visuelle.

284

Partie II

Interactivit et cration graphique

Figure10.7
Les cinq pages de croquis retouches sous Photoshop.

Nous allons maintenant crer une premire solution SketchFlow.

10.2.2 Le projet SketchFlow


Ouvrez Expression Blend et crez un prototype nomm CarReseller. Vous remarquez demble lapparition de nouveaux panneaux, dont nous verrons lutilisation ultrieurement. Affichez le panneau Project sil nest pas visible, vous constatez que la solution est scinde en deux projets distincts (voir Figure10.18).
Figure10.18
Arborescence du projet SketchFlow CarReseller.

Le premier projet correspond au lecteur SketchFlow lui-mme, il porte le nom original que vous avez dfini (CarReseller). Le second contient le prototype, cest le mme nom suffix du mot Screens. Cest dans ce dernier que vous travaillerez. Vous remarquez plusieurs diffrences avec les applications standard. Le second prototype possde tout dabord un rpertoire Fonts contenant trois polices utilises par le style Sketch (croquis). Ce style est un lment important des projets SketchFlow, il est fourni par le fichier SketchStyles.xaml prsent la racine du projet. Ce type de fichier est assez nouveau pour nous. Il sagit en fait dun dictionnaire de ressources qui permet dexternaliser et de partager certains types de ressources utiles un ou plusieurs projets.

Chapitre 10

Prototypage dynamique avec SketchFlow

285

NOTE INFO

Il est facile de rutiliser le style Sketch au sein dun projet standard. Il vous suffira dajouter le fichier SketchStyles.xaml, ainsi que les polices du rpertoire Fonts votre projet. Les styles dfinis dans le dictionnaire de ressources utilisent ces polices, cest pourquoi il ne faut pas les oublier.

Comme nous lavons dj prcis, ce type de projet contient des comportements (Behaviors) spcifiques SketchFlow. Attendez-vous donc trouver des rfrences de nouvelles bibliothques dynamiques dans le rpertoire References du projet. Nous navons pas rellement besoin de dcrire le rle de chaque bibliothque, mais celles-ci sont indispensables au bon fonctionnement du projet. Le fichier Sketch.Flow est le dernier que nous voquerons. Vous pouvez louvrir sous lapplication NotePad, par exemple. Il sagit dun fichier au format XML, qui dcrit une partie du travail ralis dans le prototype (crans, transitions, etc.), ainsi que dun ensemble de paramtres propres au projet, quil peut tre utile de personnaliser (comme les couleurs dcran par exemple). Vous pouvez modifier ce fichier de deux manires diffrentes, soit directement avec un diteur de texte, soit en passant par le menu Project, puis en cliquant sur SketchFlow Project Settings Une bote de dialogue vous permettra de modifier quelques-unes des options prsentes dans le fichier XML (voir Figure10.9).
Figure10.9
Options propres au projet SketchFlow en cours.

Vous allez modifier certains des paramtres afin de travailler plus confortablement. Comme nous lavons prcis, le site est cr avec un code quatre couleurs. Elles vont nous tre utiles pour gnrer une carte de navigation avec ce code couleur. Si vous prfrez modifier le fichier, vous pouvez remplacer les quatre dernires couleurs dfinies au sein de la balise VisualTags par celles exposes ci-dessous:
<VisualTags> <VisualTag> <Name>OurServices</Name> <Color>FFFF9711</Color> </VisualTag> <VisualTag> <Name>MyCar</Name> <Color>FF48FEFF</Color> </VisualTag> <VisualTag>

286

Partie II

Interactivit et cration graphique

<Name>Eco2Way</Name> <Color>FF2EF872</Color> </VisualTag> <VisualTag> <Name>Innovation</Name> <Color>FFF93CA5</Color> </VisualTag> </VisualTags>

Sauvergardez le fichier, puis retournez dans Blend. Celui-ci a dtect la modification et vous propose de recharger le fichier Sketch.Flow. Dans la bote de dialogue, cliquez sur OK; si tout ce passe bien le fichier est recharg proprement. Si les nuds XML sont mal formats, Blend vous proposera de recrer un nouveau fichier. Nous verrons le rsultat de cette opration dans trs peu de temps. Il reste encore un paramtre rgler avant de commencer notre prototype. Chaque cran correspondra un croquis fourni par le client, lidal serait que chaque nouvel cran que nous gnrerons possde, par dfaut, des dimensions identiques celles des croquis. Il existe plusieurs manires de procder. Vous pouvez, par exemple, dfinir des dimensions dcran par dfaut pour lensemble des projets SketchFlow. Dans la barre du haut, choisissez Tools> Options Dans la fentre qui saffiche, slectionnez longlet SketchFlow. Une srie doptions propres ce type de projets est propose. Cochez loption Default size for new screens, puis dfinissez une largeur de660 pixels et une hauteur de517pixels. Ces dimensions correspondent aux croquis raliss par le client et retouchs par nos soins. Tous les crans que nous gnrerons possderont par dfaut ces dimensions (voir Figure10.10).
Figure10.10
Options de mise en pages propres lensemble des projets SketchFlow.

Cette mthode prsente un dsavantage : si vous travaillez avec de nombreux prototypes aux dimensions diffrentes, ce rglage nest pas vraiment pertinent et vous devrez le changer rgulirement. Vous pouvez galement utiliser la carte de navigation reprsente par le panneau SketchFlow Map. Cliquez sur Screen1. Dans larbre visuel, slectionnez le UserControl racine et affectez-lui une largeur (Width) de660pixels et une hauteur (Height) de517pixels. Faites ensuite un clic-droit sur Screen1 dans la carte, puis cliquez sur loption Set As default Navigation Screen Size. Cette option modifie les valeurs de lune des balises XML contenues dans le fichier Sketch. flow. Lorsque vous concevrez de nouveaux crans, ceux-ci auront par dfaut des dimensions correspondantes lcran dorigine. Lavantage de ce rglage est dtre li aux proprits du projet. Il est donc recharg par dfaut lorsque vous ouvrirez nouveau le projet dans Blend.

Chapitre 10

Prototypage dynamique avec SketchFlow

287

10.2.3 La carte de navigation


Nous allons gnrer un premier prototype grce au panneau SketchFlow Map. Cette fentre reprsente le cur du travail de prototypage au sein de Blend (voir Figure10.11). Les prototypes sont constitus de diffrents crans. Chacun deux reprsente une interface utilisateur. Ce panneau permet de grer larborescence et lenchanement logique des interfaces utilisateur de manire globale. Celui-ci donne galement accs la gestion des transitions animes.
Figure10.11
Le panneau SketchFlow Map affiche la carte de navigation du projet.

En bas du panneau se trouve une srie doutils sous forme dicnes. Voici leur fonctionnalit de gauche droite:

Vous bnficiez tout dabord dun zoom quivalent celui prsent dans le panneau de cration et fonctionnant de manire identique. Les deux icnes reprsentant des flches ( ) permettent dannuler ou de refaire une action SketchFlow. Celles-ci sont particulirement utiles car SketchFlow gnre un couple de fichiers XAML et C# pour chaque nouvel cran cr. Lannulation classique ne fonctionnera donc pas toujours puisque SketchFlow manipule une arborescence de fichiers. Si vous avez cr un cran par erreur, utilisez ces actions pour revenir sur vos pas. Les troisime ( ) et quatrime icnes ( ) servent ajouter un nouvel cran ou un nouveau composant dcran. Nous reviendrons sur le principe des composants dcran par la suite. Le cinquime pictogramme ( ) efface un cran slectionn au sein de la carte SketchFlow, quel que soit son type (composant dcran ou cran). Lorsque vous effacez un cran, le couple de fichiers qui lui est associ nest pas rellement supprim du projet. Si vous souhaitez rellement supprimer ces derniers, il vous faudra utiliser le panneau Projects. loppos, vous pouvez dfinir un couple XAML/C# en cran SketchFlow (voir Figure10.12). Les deux boutons suivants ( ) vous permettent de zoomer, soit sur la totalit de la carte, soit sur les crans en cours de slection. Ces deux derniers sont vraiment trs pratiques pour accder aux crans que vous souhaitez modifier. Vous pouvez galement maintenir la barre despace et le bouton gauche de la souris appuys pour vous dplacer dans la carte. La molette de la souris est galement prise en compte pour le zoom. Vous pouvez diminuer lopacit des liaisons de navigation ou de composants qui ne sont pas slectionnes grce aux deux dernires icnes : . Cela permet dy voir un peu plus clair lorsque votre carte commencera stoffer.

288

Partie II

Interactivit et cration graphique

Figure10.12
Ajouter un couple XAML / C# comme cran SketchFlow.

Tous ces outils vous permettent de crer une carte de navigation assez simplement. Blend propose toutefois dautres options qui sont directement accessibles lors du survol dun cran ou dune liaison de la carte. Dans ce cas, un menu apparat en dessous de lcran survol (voir Figure10.13).
Figure10.13
Menu droulant affich au survol dun cran.

Il existe deux manires de crer des crans. La premire consiste utiliser licne approprie dans le menu bas de la fentre. En procdant ainsi, lcran gnr nest reli aucun autre par dfaut. La deuxime faon de procder consiste employer les icnes du menu droul au survol. Survolez lcran nomm Screen1, maintenez le bouton gauche de la souris enfonc sur la premire icne, puis dplacez la souris pour gnrer un deuxime cran. Positionnez-le lgrement lextrieur. Relchez le bouton gauche. Le nouvel cran est dfinitivement cr et celui-ci est reli lcran dorigine par une transition reprsente par une courbe directionnelle (voir Figure10.14).
Figure10.14
Transition directionnelle de Screen1 vers Screen2.

La courbe indique que lutilisateur pourra naturellement passer de lcran1 (Screen1) lcran2 (Screen2). La ligne reprsente galement la transition anime qui aura lieu. Gardez toutefois lesprit que cette liaison ne reprsente pas la fonctionnalit en propre qui permettra de passer dun cran lautre, mais simplement un lien de navigation logique et une transition. Dun seul coup dil sur une carte SketchFlow, vous devez tre capable de traduire un scnario dutilisation. Vous remarquez dailleurs que la courbe possde une direction, il est donc logique pour lutilisateur de

Chapitre 10

Prototypage dynamique avec SketchFlow

289

passer de Screen1 Screen2, mais pas forcment de Screen2 Screen1. Une animation de transition sera joue dans le premier cas, mais pas dans le second. Crez une seconde liaison au survol de Screen2 en cliquant sur la seconde icne et ciblez Screen1 (voir Figure10.15).
Figure10.15
Transition bidirectionnelle entre Screen1 et Screen2.

NOTE INFO

Screen1 possde une icne reprsentant une flche verte, qui indique que Screen1 est lcran de dmarrage du prototype. Vous pouvez dcider tous moment de changer lcran de dmarrage via un clic-droit sur celui de votre choix au sein de la carte. Un menu contextuel vous permet de redfinir cet cran comme cran initial.

Pour dfinir une transition anime personnalise, vous pouvez cliquer-droit sur la courbe de transition et redfinir loption Transition Style. Par dfaut, celle-ci est un fondu enchan assez efficace. Vous pouvez conserver le fondu actuel. Nous allons crer une premire carte de navigation. Comme nous concevons un site Internet, nous partons du principe que lutilisateur peut naviguer entre chaque page. Nous dfinirons donc une transition entre chaque cran, mise part la page Home qui ne sert qu atteindre les autres. Ce nest quune page daccueil ne contenant aucune information importante. Elle pourrait contenir une vido ou une animation dintroduction plein cran. Lutilisateur, une fois sur le site, naura thoriquement pas besoin de revenir sur la page Home. Nous avons tout de mme prvu un bouton cet effet, dans le pied de page de notre site. Une transition ne serait pas forcment utile. Crez une carte de navigation (voir Figure10.16).
Figure 10.16
bauche de la carte de navigation.

NOTE INFO

Afin de vous aider mieux visualiser la carte, vous pouvez modifier la couleur de fond de chaque cran. Dans le menu droulant au survol des crans (la dernire icne de couleur) ou lors dun clicdroit, vous trouverez loption Change Visual Tag. Comme nous avions modifi la palette de couleur dfinie au sein du fichier Sketch.Flow, vous avez disposition un code couleur correspondant chaque page du site.

290

Partie II

Interactivit et cration graphique

Dcompressez le fichier au format zip tlcharg prcdemment, lemplacement de votre choix sur votre disque dur. Dans le rpertoire Assets dcompress, vous trouverez le rpertoire Flat Screens contenant plusieurs images au format jpg. Au sein de Blend, crez un nouveau rpertoire nomm Croquis dans le projet CarResellerScreens, puis un deuxime rpertoire lintrieur nomm EcransSimples. Cliquez-droit sur le rpertoire EcransSimples et choisissez loption Add Existing Item Slectionnez toutes les images contenues dans le rpertoire FlatScreens dcompress, puis cliquez sur OK. Vous venez dimporter toutes les images du rpertoire dun seul coup (voir Figure10.17).
Figure10.17
Importation des croquis au format jpg.

Le fichier nomm ItsTimeToChange.jpg correspond au visuel de la page Home. Les autres fichiers sont explicitement nomms. Dans la carte de navigation, double-cliquez sur la page Eco2 Way. La fentre de design affiche la page, celle-ci est vide par dfaut. Elle possde exactement la mme structure que les pages dapplications Silverlight standard. Dans le panneau Projects, double-cliquez sur Eco2Way.jpg. Vous venez linstant de placer limage dans lcran Eco2Way. Procdez de mme avec tous les autres crans. Veillez aux dimensions du UserControl racine, celui-ci doit possder des dimensions de 660pixels de large par 517de hauteur. Vous venez de crer un premier prototype simple, Sauvegardez tous les fichiers modifis via le menu File ou le raccourci Ctrl+Maj+S. Compilez ensuite le projet pour voir le prototype dans le lecteur SketchFlow. Vous dcouvrirez ses fonctions dans la prochaine section. Lexercice corrig est dans: chap10/ CarReseller_Simple.zip.

10.3 Le lecteur SketchFlow


Le lecteur SketchFlow donne vos collgues et toute personne implique dans le projet la capacit de communiquer et de commenter le prototype. Lorsque vous avez compil le projet, il a t embarqu dans le lecteur. Le navigateur affiche donc celui-ci ainsi que le prototype quil intgre en son sein. Le lecteur lance par dfaut lcran de dmarrage que vous avez dfini dans Blend (voir Figure10.18).

Chapitre 10

Prototypage dynamique avec SketchFlow

291

Figure10.18
Chargement de la page de dmarrage au sein du lecteur SketchFlow.

Nous allons maintenant dcouvrir et utiliser les fonctionnalits du lecteur.

10.3.1 Navigation
La fentre de gauche nomme SketchFlow Player centralise toutes les fonctionnalits. Nous allons les dcrire en partant du haut vers le bas. Elle donne tout dabord accs un mininavigateur: licne reprsentant une maison ( ) permet tout instant de revenir lcran de lancement. Les flches retour et avant permettent de revenir sur le cheminement que vous avez suivi. Vous remarquez une barre dadresse indiquant lcran dans lequel vous vous situez. Il nest pas possible dentrer manuellement une adresse. Rafrachir la page actuelle seffectue par un clic gauche sur la dernire icne ( ). chaque fois que vous naviguez dans un cran, longlet Navigate met jour la liste des pages disponibles partir de celle en cours. Cette liste est base sur les transitions dfinies dans la carte sous Blend. Il est ainsi impossible dutiliser cet onglet pour atteindre un cran qui ne serait pas li par une transition. La direction de la transition est prise en compte pour son affichage. La page Home possde une transition vers lensemble des autres crans de lapplication, ceux-ci sont donc tous prsents dans la liste. Dans la liste, cliquez sur lcran Eco2Way. La transition de fondu enchan est joue, la liste est mise jour, mais la page Home ny figure pas. Cest tout fait logique puisquaucune transition ne cible cet cran. Pour finir, vous bnficiez dune rglette vous permettant de zoomer laffichage du prototype en cours. Si vous avez un grand cran, cela devient vite indispensable car les croquis sont souvent sommaires et donc en faible rsolution ; les agrandir est dans ce cas trs pratique. Nous tudierons le panneau FEEDBACK la section10.3.2. Longlet MAP autorise une navigation libre de toute transition (voir Figure10.19).

292

Partie II

Interactivit et cration graphique

Figure10.19
Longlet MAP au sein du lecteur.

Lorsque vous double-cliquez sur lun des crans, il saffiche droite. Si une transition est dfinie entre lcran initial et celui darrive, elle est joue. Dans le cas contraire, la page est simplement affiche de manire brute. Vous avez galement la possibilit de zoomer dans la carte de navigation via la rglette situe au-dessus. Vous aurez toutefois quelques difficults zoomer sur une zone lorsque les cartes de navigation seront complexes car longlet MAP nest pas redimensionnable. Pour faciliter la navigation, la carte peut galement tre affiche en surimpression de lapplication prototype (voir Figure10.20). Il suffit pour cela de cliquer sur licne dagrandissement ( ).
Figure10.20
La carte de navigation en surimpression.

Nous venons de passer en revue les fonctionnalits de navigation. Vous remarquez quil nest nul besoin pour linstant de crer de relles interactions utilisateur pour passer dun cran lautre. Cela est trs pratique et permet de se concentrer sur lenchanement des crans. Nous aborderons les interactions utilisateur la section10.4.

10.3.2 Collaboration transverse avec SketchFlow


Lun des enjeux les plus importants de ces dernires annes est certainement la communication et la collaboration intermtiers. Cest une problmatique qui a toujours exist. Celle-ci passe aujourdhui au premier plan du fait de la ncessit grandissante dchanger et de partager les ides et contraintes de production entre cratifs et techniques. Si le XAML est lun des moyens techniques permettant cette communication, SketchFlow en est bien lhritier et lun des plus puissants le-

Chapitre 10

Prototypage dynamique avec SketchFlow

293

viers uvrant en ce sens. Les onglets Feedback prsents la fois dans le lecteur et dans Blend permettent lensemble des acteurs de communiquer autour du prototype. Mme si ces derniers ne fourmillent pas de milliers doptions, celles qui y sont prsentes ajoutent une dimension supplmentaire et engendrent ainsi de nouvelles manires de produire.

10.3.2.1 Annotation versus retour utilisateur


Dans tout projet, vous trouverez quatre types de feedback. Le premier vient toujours du client, puisque vous rpondez avant tout une problmatique client et sans ce dernier, pas de projet. Ses critiques sont donc prpondrantes. Le deuxime est fourni par les chefs de projet, les directeurs technique ou artistique, les managers, ils ont une vision globale de la situation. Lutilisateur final a aussi son mot dire. Il ny a pas pire quune application qui nest pas avant tout pense pour lutilisateur final et teste par ce type de public. Le diable est dans les dtails, lutilisateur final est souvent le critique le plus difficile sur un moyen terme. Pour finir, vous pouvez mettre des commentaires en tant que concepteur du prototype, que vous soyez dveloppeur ou designer. Les communications seffectuent dans deux sens diffrents. Dune part, les ressentis utilisateur peuvent tre adresss aux concepteurs, dautre part les concepteurs peuvent faire remonter des informations et des remarques, ou encore exposer des problmatiques imprvues (voir Figure10.21).
Figure10.21
Principe dchanges de feedback utilisateur et dannotation concepteur.
Annotations cres sous Blend et lisibles par le lecteur SketchFlow Ressentis gnrs et exports au format XML depuis le lecteur SketchFlow et lisibles sous Blend

Chefs de projet

Managers

Clients

Les concepteurs utilisant Blend : - Designers - UxDesigners - Dveloppeurs

Directeur artistique

Directeur technique

Les trois premiers types de feedback concernent les acteurs qui mettront des commentaires dun point de vue utilisation. Ils navigueront dans le prototype via le lecteur SketchFlow et pourront partager leurs ressentis sous forme de fichiers XML. Ces fichiers sont imports et affichables directement au sein de Blend. un autre niveau, les concepteurs du prototype peuvent crer des annotations au sein dExpression Blend qui seront ensuite lisibles par le lecteur SketchFlow, lors de la navigation test. Nous allons endosser le rle du concepteur et crer des annotations. Au sein de Blend, slectionnez lcran MyCar. Vrifiez ensuite que laffichage des annotations est correctement activ. Licne de la bulle dinformation ( ) en bas de la fentre de cration vous permet dactiver ou de

294

Partie II

Interactivit et cration graphique

dsactiver laffichage des annotations. Lorsque vous annotez un projet, vous utilisez un identifiant sous forme dinitiales. Cest exactement le mme principe que sous Word ou Excel. Pour paramtrer lidentifiant, vous devez ouvrir le menu Tools (outils), slectionner Options, puis choisir longlet Annotations (voir Figure10.22).
Figure10.22
Paramtrage de longlet Annotations.

Pour crer un nouveau commentaire, utilisez le raccourci Ctrl+Maj+T. Vous pouvez galement ouvrir le menu Tools, puis cliquer sur Create Annotation (voir Figure10.23).
Figure10.23
Une annotation dans lcran MyCar.

Compilez la solution au sein du lecteur SketchFlow, slectionnez la page MyCar, puis cliquez sur longlet FEEDBACK. Vous y trouverez une icne permettant laffichage des annotations ( ). Lorsque vous la survolez, les annotations, sil y en a, sont affiches temporairement. Cliquez-les pour activer leur affichage tout au long de la navigation (voir Figure10.24).
Figure10.24
Afficher les annotations.

Chapitre 10

Prototypage dynamique avec SketchFlow

295

Comme vous le constatez, les annotations sont assez simples crer et consulter. Laissez le navigateur ouvert, nous allons utiliser le lecteur SketchFlow afin de crer quelques notes du point de vue responsable de production, client ou utilisateur final. Il existe deux manires de gnrer un commentaire dans le lecteur. Soit vous crez une ou plusieurs notes associes pour chaque page, soit vous dessinez directement sur la page via les outils proposs par SketchFlow. Le panneau FEEDBACK contient cet effet trois outils: un stylo et un surligneur dont vous pouvez rgler lpaisseur et la couleur ainsi quun correcteur. Pour ajouter une note de page, il suffit de cliquer sur le texte gris Type your feedback here (voir Figure10.25). Il suffit maintenant dexporter les croquis et commentaires sous forme dun fichier .feedback au format XML. Cliquez sur licne reprsentant un rpertoire. Deux options soffrent vous: vous pouvez supprimer tous vos commentaires par une rinitialisation ou les exporter. Choisissez loption Export Feedback Vous devez fournir votre nom ainsi que vos initiales. Nous nous mettrons dans la peau de notre chef des projets spciaux, Nicolas. Il dcide dexporter ses commentaires pour nous les envoyer ensuite par e-mail, il cre donc un fichier nomm Nicolas.feedback (voir Figure10.26).
Figure10.25
Ajouter un feedback utilisateur.

Figure10.26
Un exemple de fichiers feedback.

Le contenu de ce fichier est rcuprable tout instant. Pour cela, vous devez cliquer sur licne dajout depuis le panneau Feedback. Puis, slectionnez le fichier .feedback. Vous pouvez importer plusieurs fichiers de ce type mais nen visionner quun seul la fois (voir Figure10.27). Ces

296

Partie II

Interactivit et cration graphique

fichiers sont automatiquement recopis dans votre projet dans le rpertoire Feedback Files. Si ceux-ci ont t gnrs alors que vous avez modifi le projet entre temps, Blend vous signale qu'ils peuvent tre obsoltes. Ds cet instant, il vous appartiendra de dterminer la fiabilit de ces remarques. Lorsque des annotations ou des remontes utilisateur existent dans un cran, des icnes indiquent leur prsence au-dessus de cet cran dans la carte de navigation (voir Figure10.27). Vous pouvez activer ou dsactiver laffichage des commentaires utilisateur en cliquant sur licne en haut droite du panneau Feedback ( ). Vous connaissez maintenant les outils facilitant la collaboration et le travail de prototypage en quipe. Il reste toutefois quelques zones dombres concernant laccs au prototype lui-mme.
Figure10.27
Visualiser les remontes utilisateur dans Expression Blend.

10.3.2.2 Partager un projet SketchFlow


Notre problmatique ce stade est assez simple. Nous pouvons crer des retours utilisateur parce que nous sommes dtenteur du projet Blend. Nous pouvons compiler le projet tout instant et avoir accs au lecteur ainsi qu la sauvegarde des commentaires. Toutefois, le partage des retours ne concerne pas rellement le concepteur, mais plutt les directeurs de production, le client et lutilisateur final. Il vous faut donc partager le projet SketchFlow sur un serveur web ou un espace disque accessible. Blend vous fournit une manire simple de grer ce type de problmatique et cre pour vous le site web complet contenant le prototype et le lecteur SketchFlow qui lembarque. Il vous suffit simplement douvrir le menu File, puis de cliquer sur loption Package SketchFlow Project (voir Figure10.28). Choisissez le dossier qui recevra le projet compil. Il vous suffira ensuite de tlcharger ces fichiers sur le serveur web de votre choix via une connexion FTP ou SFTP. Vous navez rien dautre faire quattendre la rception des fichiers feedback par e-mail ou par tout autre moyen. Vous avez galement la possibilit de crer un fichier au format Word contenant une description complte du prototype. Choisissez alors le menu Export to Microsoft Word Vous obtiendrez un document comme montr la Figure10.29.

Chapitre 10

Prototypage dynamique avec SketchFlow

297

Figure10.28
Mettre en forme un projet SketchFlow pour le partage.

Figure10.29
Rsultat dune exportation au format Word.

Ce type de document est surtout avantageux lorsque les diverses parties se sont accordes sur un prototype. Vous pouvez le considrer comme un cahier des charges macroscopique que vous pouvez tout instant consulter et modifier. Il pourra mme vous tre utile pour rdiger un cahier de recettes validant lapplication livrable.
NOTE INFO

Un cahier de recettes est souvent rdig lorsque les projets atteignent une certaine dimension en tout dbut de production. Il concentre toutes les informations propres l'application livrable et ses fonctionnalits, dans sa version finale. Ainsi, lors de la remise du projet au client, celui-ci peut recenser l'ensemble des fonctionnalits initialement prvues dans le cahier de recettes afin d'viter tout oubli. Le cahier des charges est quant lui ddi aux quipes techniques, il dcoule des impratifs et du livrable. Son contenu est utile tout au long de la production et guide les quipes techniques.

Dans les prochaines sections, nous allons grandement amliorer notre prototype et lui donner vie. Vous ntes pas oblig de connatre entirement le logiciel Blend pour crer des prototypes. Cest l lune des grandes forces de SketchFlow.
NOTE INFO

Il est possible de convertir un projet SketchFlow en projet de production et ainsi de le dtacher du lecteur Silverlight. Les tapes sont diffrentes selon le langage et la plateforme utilise, Silverlight ou WPF. Elles sont dcrites dans la documentation accessible via linterface d'Expression Blend.

298

Partie II

Interactivit et cration graphique

10.4 Interactivit
Jusqu maintenant, lutilisateur ne peut naviguer dans le prototype qu travers lutilisation des fonctionnalits fournies par le lecteur SketchFlow. Cela est vraiment utile et vite de compliquer inutilement la conception du prototype dans la premire phase de rflexion. Toutefois, lorsque vous aurez trouv un consensus sur ses grandes lignes, il est possible de donner au client un aperu de lexprience utilisateur finale en lui appliquant une couche dinteractivit. Au sein de SketchFlow, linteractivit utilisateur se traduit de deux manires diffrentes. Vous pouvez, comme dans toutes les autres applications, crer du code logique ou glisser des comportements interactifs sur les instances dUI Element. Leur nombre est plus important dans ce type de projet et ils sont plus simples dutilisation. Le prototype acquiert ainsi plus de profondeur et concrtise une partie de la conception. Dune manire compltement diffrente, vous pouvez simuler des interactions utilisateurs via le panneau SketchFlow Animation. Cette fonctionnalit compltement nouvelle peut tre apprhende de diffrentes manires. Nous tudierons son fonctionnement la section10.4.3.

10.4.1 Importer des fichiers PSD


Depuis sa version3, Expression Blend rend possible limportation de fichiers Photoshop (.psd). La rpartition et la composition de visuels par le biais de calques confre aux fichiers .psd de nombreux avantages. Bien qu'il ne soit pas le seul dans ce cas, Photoshop est ainsi utilis depuis des annes dans le Web afin de maquetter de nombreux sites XHTML ou Flash. Dsormais, les applications Silverlight peuvent tre entirement conues graphiquement, puis tre intgres par les designers interactifs ou les dveloppeurs dans un deuxime temps. Contrairement ce principe, et juste titre, Microsoft place la phase de croquis avant celle de la conception graphique pure et dure. Lutilisation de Photoshop de ce point de vue reste dactualit. Il est trs simple de scanner vos croquis, puis de les retoucher et de les organiser en calques dans un format .psd. Nous allons importer ce type de fichiers pour donner de la profondeur notre application. Nous pourrons de cette manire sparer et grer les lments interactifs individuellement.
NOTE INFO

L'importation de fichiers Illustrator est galement possible depuis la version3 de Blend. Illustrator est avant tout utilis pour concevoir le visuel finalis, ainsi son emploi concerne moins le maquettage et le prototypage. Nous aborderons ce type d'importation au Chapitre11.

Supprimez tous les composants Image au sein des crans de la carte de navigation ainsi que le dossier EcransSimples. Dans le rpertoire Assets dcompress, vous trouverez le rpertoire PSD contenant les mmes crans, mais au format Photoshop et organiss en plusieurs calques. Dans la carte de navigation SketchFlow, double-cliquez sur la page Home. Dans le panneau Project, slectionnez le rpertoire Croquis. Ouvrez le menu File, puis loption Import Adobe Photoshop File... Accdez au rpertoire PSD et choisissez le fichier ItsTimeToChange.psd. Une fentre dimportation est affiche au premier plan, elle vous permet de grer limportation de ce type de fichiers (voir Figure10.30).

Chapitre 10

Prototypage dynamique avec SketchFlow

299

Figure10.30
Fentre dimportation des fichiers Photoshop.

La structure du fichier est entirement affiche. Il faut veiller cocher loption Check all layers to import. Lorsque le contenu d'un calque est cach dans le fichier .psd, il ne sera import que si cette option ou la case cocher adjacente sont coches. Validez limportation du fichier. Comme vous avez slectionn lcran Home, le contenu du fichier est directement intgr la page. Si lagencement et les marges sont sauvegards, la transparence subira parfois quelques modifications changeant lgrement le visuel import. Cela na que peu dimportance pour nous car nous travaillons sur un prototype. Lors de limportation, chaque calque est transform sous forme dimage au format png. Pour le vrifier, vous pouvez dplier le rpertoire ItsTimeToChange_Images cr lors de limportation. Vous y trouverez les images png du visuel final.
NOTE INFO

Pour obtenir un rsultat visuel fidle au document dorigine, il faut viter toutes les spcificits propres au format psd. Rastrisez chaque calque, la plupart des effets ne sont pas conservs (seuls les projections dombre et le flou le sont). Il est galement plus efficace de recrer les textes sous Blend ou de pixeliser ces derniers sils ne sont pas interactifs. Toutes les options de fusion propres aux calques Photoshop sont galement proscrire. Suivez cette logique et vous naurez pas de difficults lors de limportation.

Suivez les tapes dcrites ci-dessus pour chaque cran du prototype. Veillez bien slectionner le dossier Croquis afin dorganiser proprement le projet (voir Figure10.31).
Figure10.31
Le rpertoire gnr ItsTimeToChange_Images.

300

Partie II

Interactivit et cration graphique

Dans larbre visuel de chaque cran, vous remarquez quun conteneur de type Canvas a t gnr. Son nom correspond celui de limage importe. En son sein, plusieurs contrles de type Image ont t crs et font rfrence une image png. Ils reprsentent les calques dorigine et possdent en consquence un nom en correspondance avec chacun deux (voir Figure10.32). Comme vous le constatez, le nommage des calques et des objets est crucial. Cest un moyen simple et efficace pour faciliter la communication entre chaque ple mtier. Il ny a qu lire pour comprendre lutilit de chaque calque. Nous allons maintenant profiter du dcoupage des calques pour gnrer une interactivit utilisateur propre chaque cran.
Figure10.32
Larbre visuel de lcran Innovation.

10.4.2 Navigation utilisateur


Afin de permettre lutilisateur de naviguer, il nous faut dabord reconstruire le menu principal et le pied de page. Nous pouvons pour cela utiliser de simples instances de Button ayant le style Sketch et regroupes au sein dun conteneur. Slectionnez lcran Home et supprimez linstance dImage correspondant au menu. Crez ensuite un conteneur StackPanel dans la grille principale et nommez-le Menu. Disposez-le de manire laligner en bas droite de la grille et dfinissez lempilement de ses enfants en mode horizontal. Glissez quatre boutons lintrieur de manire recrer le menu. Choisissez une couleur conforme au code couleur de chaque cran. Procdez de faon identique pour le pied de page, vous pouvez utiliser un dgrad sur le bord pour crer un effet correspond au croquis original (voir Figure10.33).
Figure10.33
Le menu et le pied de page recrs avec des instances de Button et le style Sketch.

Chapitre 10

Prototypage dynamique avec SketchFlow

301

Nous allons maintenant ajouter un peu de logique au visuel. Rien de plus simple au sein dun projet SketchFlow: faites un clic-droit sur le bouton Eco2Way_menu et slectionnez loption Navigate To. La liste des crans accessibles apparat, choisissez lcran Eco2Way (voir Figure10.34). Rptez lopration pour chaque bouton du menu. Ce que nous avons fait est non seulement traduit en XAML, mais consiste simplement ajouter un comportement chaque bouton sur lequel vous avez dfini une navigation. Le comportement est donc accessible dans larbre visuel. Dans les projets SketchFlow, il nest pas ncessaire de savoir ce fait pour utiliser le comportement. Une majorit d'interactions peut tre ralises par un simple clic-droit. Si vous tes designer interactif, cela peut toutefois tre utile dans les cas complexes dinteraction.
Figure10.34
Dfinir une navigation vers lcran Eco2Way.

Par dfaut, laccs aux crans se dclenchera sur un clic de lutilisateur, vous pourriez excuter cette action lorsquun autre vnement est diffus. Une autre problmatique se pose si vous souhaitez crer cette navigation pour le bouton Home_footer contenu dans le pied de page. Comme vous tes sur la page Home, Blend ne vous propose pas de naviguer vers celle-ci. Si vous connaissez un peu les comportements, vous pouvez biaiser en choisissant un autre cran dans la liste afin de crer le comportement sur Home_footer. Vous navez plus qu modifier son paramtre Target Screen (voir Figure10.35).
Figure10.35
Paramtrage du comportement affect Home_footer.

La page Home est maintenant presque aboutie. Il est trs facile de dupliquer les deux StackPanel dans les autres crans. Faites un copier-coller de ces derniers dans lcran Eco2Way, replacez le menu en haut de la page pour recouvrir limage du menu dj prsente. Vous navez ensuite qu

302

Partie II

Interactivit et cration graphique

supprimer cette dernire ainsi que limage du pied de page dans larbre visuel. Les comportements sont automatiquement copis avec. Vous venez de crer une navigation utilisateur en moins de5minutes.

10.4.3 Simuler un flux dutilisation


Nous allons maintenant simuler les actions de lutilisateur via le panneau SketchFlow Animation. Ce dernier nexiste que dans ce type de projet, il permet de crer des animations temporises et dtectes par le lecteur SketchFlow lors de la navigation utilisateur. La personne testant le proto type pourra ainsi avoir un aperu de linteractivit tout en vitant un code fastidieux. Chaque cran du prototype peut possder son propre jeu de simulations utilisateur. Vous allez simuler le clic de lutilisateur sur un bouton afin de dplier une zone de texte cache par dfaut. Dans la carte de navigation (SketchFlow Map), double-cliquez sur lcran OurServices. Vous constatez que le panneau SketchFlow Animation est vide (voir Figure10.36).
Figure10.36
Panneau SketchFlow Animation vide.

Il contient un premier cran nomm Base, qui indique ltat par dfaut de lcran. Vous devez modifier quelques proprits avant de crer la simulation utilisateur. Slectionnez, dans le Canvas nomm Service, les composants Image MoreOver et ActivateMore. Passez les valeurs de leur proprit Opacity 0. Ajouter une animation SketchFlow ou crer des animations standard sont des actions similaires. Cliquez sur licne reprsentant le signe plus, puis nommez lanimation AccessMoreInformation. Il suffit pour cela de cliquer sur le nom affich par dfaut et de le modifier. Slectionnez le premier tat nouvellement gnr droite de ltat de base. Il est reprsent par une vignette affichant le visuel de lcran. Vous passez en mode enregistrement dtat visuel. Au sein de SketchFlow, ces tats sont appels Frame ou image-cl ( ne pas confondre avec cl danimation). Cliquez sur MoreOver, passez la valeur de la proprit Opacity 100. Cliquez ensuite sur licne du signe plus situ en haut droite de la vignette (voir Figure10.37).
Figure10.37
Cration d'un nouvel tat d'animation.

Vous crez ainsi un nouvel tat partir de ltat modifi. Cliquez sur ActivateMore, passez la valeur de la proprit Opacity 100. Vous remarquez que lorsque vous survolez un cran, une valeur exprime en secondes apparat. Il sagit du temps de pause durant lequel cet cran est affich lors de la lecture de lanimation globale. Entre chaque cran, vous pouvez galement spcifier une

Chapitre 10

Prototypage dynamique avec SketchFlow

303

dure ainsi quun type de transition. Vous pouvez activer dfinitivement laffichage des tempos en cliquant sur licne de lhorloge.
Figure10.38
Les dures de pause affiches pour chaque cran.

Lorsque vous modifiez des proprits dont les valeurs ne sont pas interpolables (donc diffrentes des valeurs de type Point, Double ou Color), vous pouvez activer le systme dagencement fluide qui assure une transition anime de ces proprits (voir section7.4). Testez lanimation SketchFlow directement au sein de Blend via le bouton de lecture. Nhsitez pas revoir les tempos, si besoin, afin de simuler lenchanement des images-cls de manire raliste. Compilez votre projet et naviguez jusqu lcran OurServices pour accder lanimation du point de vue de lutilisateur du prototype (voir Figure10.39).
Figure10.39
Lanimation SketchFlow accessible.

Cliquez sur le lien pour jouer lanimation que vous venez de dfinir. Ce type danimation est en fait bas sur le gestionnaire dtats visuels tudi au Chapitre7. Nous allons maintenant aborder son fonctionnement au sein des projets SketchFlow.

10.4.4 tats visuels


Chaque cran peut se comparer une page de notre application. Les diffrentes pages peuvent donc possder leurs propres tats visuels. Au sein de la carte de navigation, double-cliquez sur lcran nomm Innovation. Il permet linternaute de visualiser les tous derniers modles de voiture disponibles sous forme de galerie dimages ou via un simple lecteur vido. La galerie ou la vido seront affiches tour de rle. Pour ce faire, vous allez crer deux tats visuels au sein de lcran Innovation via le panneau States. Crez un groupe dtats nomm DisplayStates, puis deux tats nomms respectivement Galery et Video. Par dfaut la vido est affiche. Slectionnez ltat Galery, puis passez lopacit des objets videoSelected et PlayerVideo 0. Passez ensuite false la valeur de la proprit IsHitTestVisible de lobjet videoSelected. Dans cet tat, lobjet ne reoit plus les interactions en provenance de la souris. Revenez dans ltat de base puis

304

Partie II

Interactivit et cration graphique

faites un clic-droit sur lobjet videoSelected, slectionnez loption Activate State puis Innovation /Galery (voir Figure10.40). Vous venez de crer un comportement interactif sur cet objet. Lors du clic de la souris, lutilisateur affichera ltat Galery. Vous pouvez crer un rectangle transparent, sous lobjet videoSelected, ayant pour objectif dafficher ltat Video. Spcifiez une dure de transition pour le groupe dtats qui nexcde pas une seconde. Lorsque vous testez le prototype, vous avez la possibilit daccder aux tats visuels de chaque cran (voir Figure10.41). Si vous tes graphiste et que vous ntes pas un familier de Blend, laccs simplifi aux tats visuels est une vraie valeur ajoute en termes de temps. Lutilisation de comportements est lune des cls de cette russite, nous les emploierons nouveau de manires diffrentes dans le chapitre suivant. Le prototype interactif est dans le dossier: chap10/CarReseller_Interactive.zip.
Figure10.40
Activer un tat visuel via un clic-droit.

Figure10.41
Accs aux tats visuels via le lecteur SketchFlow.

10.5 Interface riche


Jusqu prsent larborescence de notre prototype est exclusivement constitue dcrans simples, privilgiant ainsi une approche de conception page par page, trs proche des sites XHTML classiques nombreux sur Internet. Cette approche possde certains dfauts que nous allons identifier.

Chapitre 10

Prototypage dynamique avec SketchFlow

305

10.5.1 cran versus composant


Comme vous le constatez, lensemble des pages du prototype partage deux lments identiques, le menu principal et le pied de page. Le fait de conserver un design quivalent pour ces deux lments facilite grandement la navigation et linterprtation des pages pour linternaute. Dun point de vue technique, cela pose toutefois problme car si vous souhaitez changer la disposition de ce menu, vous devrez le faire dans chaque page de votre projet. Ces deux lments peuvent tre considrs comme des instances de composants autonomes assurant leur propre logique. De cette manire, modifier le composant revient changer toutes ses occurrences dans le projet. Au sein de SketchFlow, ce type de module est appel composant dcran. Il sagit dans les faits dun UserControl au mme titre que notre application principale (voir Chapitre12). Pour crer ce type dobjet, vous pouvez soit utiliser la carte de navigation, soit slectionner un (ou plusieurs) contrle dans lun des crans existant, pour le transformer par la suite en composant dcran. Nous allons utiliser cette mthodologie dans un premier temps, puis nous utiliserons le panneau SketchFlow Map pour finaliser notre approche. Dans lcran Home, faites un clic-droit sur le contrle Stack Panel nomm Menu, puis choisissez loption Make Into Component Screen Une bote de dialogue apparat vous demandant de nommer le composant dcran (voir Figure10.42).
Figure10.42
Fentre Make Into Component Screen.

Le nom MenuComponent propos par dfaut est loquent, vous pouvez donc le conserver. Cliquez sur OK, la carte de navigation est automatiquement mise jour. Vous remarquez quun nouveau type de connexion est gnr. Celle-ci est en pointills de couleur verte, apparence attribue par dfaut aux connexions de composants. Un couple de fichier XAML C# est galement cr, Blend ouvre par dfaut le fichier XAML correspondant larbre visuel de notre menu. Il est possible dinstancier ce composant en le reliant (MenuComponent) chaque cran. De cette manire, lorsque vous modifierez le composant source, chacune de ses instances sera mise jour au sein des crans du projet. Pour crer de nouvelles connexions partir du composant, il suffit dutiliser la dernire icne apparaissant lors du survol du composant au sein de la carte de navigation (voir Figure10.43).
Figure10.43
Connexion de composants.

306

Partie II

Interactivit et cration graphique

Il est ncessaire de repositionner correctement le composant pour chaque cran, non seulement dans lespace, mais galement dans larbre visuel afin de remplacer parfaitement lespace occup par les menus dj prsents. Il ne vous reste plus qu supprimer chaque ancien menu StackPa nel. Vous pouvez procder de manire identique pour le pied de page. Si vous souhaitez avoir une meilleure visibilit de lun des deux types de connexions (composant ou cran), vous pouvez diminuer la luminosit de lun ou de lautre. Les composants dcran possdant par nature de nombreuses connexions, vous pourriez galement claircir leur couleur afin de les mettre en valeur. Un vert lumineux est idal dans ce cas. Utilisez loption SketchFlow Project Settings (menu Project) pour modifier la couleur actuelle (voir Figure10.44). Les composants dcran sont en fait de simples instances de UserControl. Si dun point de vue technique SketchFlow nest pas une rvolution et repose sur de solides bases existantes, la facilit de conception quil apporte est rellement novatrice et pertinente. Le modle technique XAML/C#, propos ds le dpart par .Net3, est un terreau propice ce genre davances. Maintenant que les fondements sont poss, vous pouvez vous attendre lclosion de ce type dinnovations de manire rgulire dans lavenir. Nous allons maintenant utiliser les composants dcran dune manire diffrente afin de crer un prototype simple dinterface riche.
Figure10.44
Connexions de composants mise en valeur.

10.5.2 Lexemple du configurateur riche


La notion de configurateur riche est apparue dans le Web avec les technologies asynchrones comme AJAX. Lide gnrale est de faciliter un processus travers une interface enrichie. Cela peut aller de la rservation htelire la configuration dune cuisine comme le proposent certaines applications. Au sein de cette section, nous allons prototyper une interface permettant un internaute de slectionner et de configurer une voiture. L'objectif final est de faciliter la prise de rendez-vous pour un test de conduite.

10.5.2.1 Le flux dutilisation


Comme nous lavons prcis au dbut de cette section, la navigation page par page possde quelques dfauts. Elle force notamment lutilisateur relire la totalit de chaque nouvelle page affiche. Cette contrainte peut videmment tre trs utile si vous affichez un contenu radicalement diffrent des prcdents. Cest toutefois rarement le cas et, dans90% des situations, le flux dutilisation est compltement cass par ce que lon appelle laveuglement dinformations caus par le rafrachissement.

Chapitre 10

Prototypage dynamique avec SketchFlow

307

Lorsque vous utilisez une application, vous entrez parfois dans le flux, un tat idal dutilisation dans lequel tout vous parat logique et vident. Vous enchanez ainsi rapidement et simplement les actions et accdez facilement aux informations sans vous poser de questions existentielles. Dans ce cas, votre tat de concentration est optimal. Laveuglement dinformations peut vous forcer quitter cet tat. Cest un peu comme si un animateur dcidait de faire bouger tous les personnages dun dessin anim en mme temps avec exactement la mme amplitude pour chacun deux. Le traitement des informations par lil est tellement important quil nest pas possible de tout analyser en mme temps. On pourrait galement percevoir cela comme une forme de censure ou de bruit visuel, tous deux engendrs par un trop plein dinformations impossibles traiter. Ds lors, vous quittez le flux dutilisation afin de conserver une distance suffisante et garder une vision globale de la situation. Cette situation est au final assez dsagrable car elle vous force prendre du recul et rflchir l o tout devrait tre simple et comprhensible. Le flux dutilisation peut tre dstabilis par dautres facteurs comme une mauvaise comprhension ou formalisation de linterface ou des ralentissements qui obligent prendre du recul du point de vue utilisation. Au final, vous pouvez trs rapidement dcourager linternaute ou lutilisateur de lapplication si vous ny prenez pas garde. Lune des solutions permettant la mise en place de flux dutilisation consiste permettre une navigation au sein dune seule et mme page. Vous ne rafrachissez ainsi quune portion de la page et attirez lattention de lutilisateur au bon endroit et au bon moment. Les composants dcran permettent de raliser ce type dexprience assez simplement car vous ne rafrachirez pas toute la page, mais juste une portion de celle-ci. Lutilisateur est beaucoup moins dsorient dans ce cas et peut mme prvoir intuitivement un certain nombre de comportements de linterface. Ce qui est prvisible le confortera dans son exprience et dans ses choix dutilisation. Nous allons maintenant illustrer ce principe travers le prototypage dun configurateur riche. Ce dernier est une petite application. Elle sera contenue dans lcran MyCar et permettra lutilisateur de slectionner un vhicule partir dune liste de critres. Lcran est constitu de trois panneaux reprsentant chacun une tape dans le processus dutilisation (voir Figure10.45).
Figure10.45
Les trois panneaux du configurateur riche.

10.5.2.2 Crer les composants


Afin de se concentrer sur notre problmatique, dzippez le projet: chap10/CarReseller_Flux.zip. Au sein du projet, lcran MyCar contient une arborescence qui a t gnre partir de dessins

308

Partie II

Interactivit et cration graphique

scanns et retouchs sous Photoshop et de composants ayant le style Sketch. Les crans vus prcdemment sont tout trois rpartis au sein de grilles. Le premier permet de slectionner les critres et affiche une liste mise jour dynamiquement. Le deuxime cran donne un aperu de la voiture et permet de personnaliser ses options. Le dernier cran est un formulaire renseign par le client qui souhaite tester la voiture slectionne sur circuit ou sur route. Slectionnez la grille Design, puis faites-en un composant dcran. Dans le composant nouvellement cr, dfinissez des dimensions en mode automatique pour le composant de type UserControl racine, ainsi que pour la grille nomme Design. Pour finir, simplifiez limbrication en dgroupant la grille LayoutRoot. Vous pouvez raliser cela via un clic-droit et slectionner loption Ungroup. Revenez dans lcran MyCar et rptez lopration pour les grilles Perso et test.
NOTE INFO

Dans lcran MyCar, vous constatez la prsence dencadrs jaunes autour des composants nouvellement gnrs ainsi quun point dexclamation en haut gauche. Cela indique que vous devez compiler le projet pour voir le rsultat visuel final de ces composants. Pour compiler sans tester le projet, utilisez le raccourci Ctrl+Maj+B. Lorsque la compilation est termine, les bordures jaunes et le point dexclamation disparaissent.

Vous obtenez trois composants dcran lis lcran MyCar dans la carte de navigation, ainsi quun rsultat visuel similaire celui dorigine pour cet cran (voir Figure10.46).
Figure10.46
Les trois composants du configurateur riche et larbre visuel.

Comme vous le constatez, les deux premiers composants sont partags en deux zones distinctes. Lorsque l'un ou l'autre de ces composants perdra le focus utilisateur, seule l'une des deux parties de ce composant sera visible, lautre sera simplement rtracte avec une petite animation de fondu. Lorsque lun des panneaux recevra le focus, il sera mis au premier plan avec un dplacement sur laxe 3D en z. Ce comportement permet l'utilisateur de ne pas tre submerg d'informations inutiles. Pour crer ce type de transition, il faut crer des tats correspondant au focus utilisateur pour chaque composant, ainsi que pour lcran MyCar. Dans lcran MyCar, inversez lordre des composants de manire ce que le panneau DesignComponent soit au premier plan et que le composant TestComponent soit au dernier. Crez ensuite un nouveau groupe dtats visuels nomm Focused Component, ainsi que trois tats nomms en son sein, ayant pour noms respectifs, Design Focus, PersoFocus et TestFocus. Dfinissez une transition globale pour le groupe dtats

Chapitre 10

Prototypage dynamique avec SketchFlow

309

de 6/10de seconde environ avec une courbe de dclration de votre choix Cubic Out semble une bonne option (voir Figure10.47).
Figure10.47
Les tats visuels de lcran MyCar.

Dans ltat DesignFocus, modifiez la profondeur sur laxe 3D z global (GlobalOffsetZ) des composants PersoComponent et TestComponent avec des valeurs respectives de 100 et 200 pixels. Ceux-ci se trouvent larrire-plan, automatiquement lun derrire lautre. Slectionnez ltat PersoFocus, puis modifiez cette fois la position sur laxe z global de DesignComponent et de TestComponent de 50 et de 200 pixels. Pour finir, dans ltat TestFocus, passez la position sur laxe z global de DesignComponent 200 et celle de PersoComponent 100. Dans cet tat, le panneau de TestComponent sera lavant-plan, puis viendra le panneau PersoComponent au second plan et au dernier plan DesignComponent.
NOTE INFO

Lorsque lun des panneaux possde le focus, il ne subit aucune projection3D. Cela est assez positif pour votre visuel final car lorsquun objet possde une projection, il est rendu sous forme de bitmap (voir Chapitre9). Cela occasionne un lissage des pixels et peut engendrer des textes ou des vecteurs flouts. Les consquences de ce rendu bitmap sont moins gnantes pour les panneaux situs larrire-plan, car ils nont pas lintrt utilisateur. Vous pouvez galement vous permettre de repositionner en x les panneaux afin de mettre celui qui a le focus utilisateur en valeur. Utilisez cette fin les RenderTransform afin dviter de rastriser les vecteurs en bitmap. Le mlange des deux types de transformations est donc non seulement possible mais conseill pour les panneaux ayant le focus qui ne sont pas affects de projections3D.

La problmatique, ce stade, est de toujours faire apparatre une portion des composants en arrireplan de celui qui possde le focus. Allouer les marges de manire prcise nest pas forcment ais cet instant car vous devez anticiper le fait que les composants seront eux-mmes dans des tats visuels modifiant leur largeur. Vous pourrez galement modifier lagencement des composants la suite d'une srie de test de l'application et procder ainsi de manire empirique.

10.5.2.3 Transitions et tats visuels de composants


Nous avons ralis la premire partie de notre prototype. Il nous reste crer les tats visuels inhrents chaque composant dcran. Dans la carte de navigation, double-cliquez sur lcran DesignComponent et crez un groupe dtats visuels nomm FocusStates ainsi que des tats, la transition et une dure globale (voir Figure10.48).

310

Partie II

Interactivit et cration graphique

Figure10.48
Les tats visuels de DesignComponent.

Slectionnez ltat List, puis passez la largeur (Width) ainsi que lopacit de lobjet Options Design 0. Modifiez ensuite la largeur de lobjet ColorDesign 150. Cliquez sur ltat Unfocus et dfinissez lopacit et la largeur de lobjet CurrentSelectionDesign 0. Passez ensuite la largeur de lobjet ColorDesign 200. Dans la carte de navigation, double-cliquez sur le composant PersoComponent. Nous allons rpter les mmes tapes. Crez deux tats ayant les mmes proprits de transition, nomms respectivement Focus et Unfocus. Cliquez sur ltat Unfocus, puis slectionnez lobjet nomm PersoRight. Passez la valeur de ses proprits dopacit et de largeur 0. Dfinissez ensuite la largeur du composant Image ColorPerso 220pixels. Pour finir, nous allons modifier le composant TestComponent. Crez deux groupes d'tats nomms FocusStates et FillStates. Le premier nous permettra dafficher le visuel en fonction du focus utilisateur, le second grera le visuel selon que l'utilisateur aura rempli ou non le formulaire. Dans ltat de base, passez la proprit Visibility du composant Message Collapsed. De cette manire, le texte de confirmation de lenvoi du formulaire nest pas visible au chargement du configurateur. Crez les tats Focus et Unfocus au sein du groupe d'tat adquat, puis les tats Filled et NotFilled pour le groupe FillStates (voir Figure10.49).
Figure10.49
Les tats visuels de TestComponent.

Lobjectif est maintenant de ne laisser afficher que le titre et larrire-plan pour ltat Unfocus. Slectionnez les objets ContentTestDrive, Message et ColorTestDrive pour modifier leur opacit 0. Fixez galement la largeur de ContentTestDrive et de ColorTestDrive 170 pixels. Afin de grer les tats visuels concernant la saisie du formulaire, slectionnez l'tat Filled, puis modifiez la valeur de la proprit Visibility Collapsed pour ContentTestDrive ainsi que pour le bouton. loppos, changez la valeur de cette proprit Visible pour le composant Message. Nous venons dviter un conflit de proprit entre les tats visuels du groupe FillStates et Focus States. En effet, nous naurions pas pu utiliser la proprit Opacity dans les deux groupes dtats sans engendrer de bogues lexcution (voir Chapitre7). Il ne nous reste plus qu crer le

Chapitre 10

Prototypage dynamique avec SketchFlow

311

code logique et les comportements interactifs ncessaires pour donner vie linterface. Le projet contenant tous les tats visuels est accessible dans: chap10/CarReseller_Etats.zip.

10.5.2.4 Interactivit avance


Vous trouverez un rsum de tous les tats crs pour chaque cran ainsi que lactivation de ceuxci en fonction de chaque tape dutilisation au Tableau10.1. Ce type de rcapitulatif est assez pratique pour concevoir des interfaces riches. Cest une sorte de feuille de route vous permettant de vous y retrouver. Par exemple, pour la premire phase dutilisation, lcran MyCar affiche ltat DesignFocus, les composants DesignComponent, Perso Component et TestComponent affichent respectivement les tats Focus, Unfocus et Unfocus. Une fois le vhicule choisi dans la liste, lcran MyCar active ltat PersoFocus, le panneau Design Component affiche ltat List, etc. Vous remarquez que pour la dernire tape, TestComponent est Focus, mais quil peut galement tre dans ltat Filled ou NotFilled. Celui-ci bnficie en effet de deux groupes dtats visuels distincts et affiche donc deux tats. Nous allons commencer par initialiser la premire tape.
Tableau10.1 : tats visuels en fonction de l'tape

tats visuels cran MyCar Composant DesignComponent Composant PersoComponent Composant TestComponent

tape1 DesignFocus Focus Unfocus Unfocus

tape2 PersoFocus List Focus Unfocus

tape3 TestFocus Unfocus Unfocus Focus / Filled / NotFilled

cette fin, vous allez ajouter de la logique via C#. Vous pouvez vous rfrer au Tableau10.1 pour vous faciliter ainsi la tche. Ouvrez le fichier C# Screen_1_3.cs dans Blend ou Visual Studio et utilisez la classe statique VisualStateManager, comme montr ci-dessous:
public Screen_1_3() { InitializeComponent(); Loaded +=new System.Windows.RoutedEventHandler(Screen_1_3_Loaded); } private void Screen_1_3_Loaded(object sender, RoutedEventArgs e) { VisualStateManager.GoToState(this,"DesignFocus",false); VisualStateManager.GoToState(designComponent,"Focus",false); VisualStateManager.GoToState(persoComponent,"Unfocus",false); VisualStateManager.GoToState(testComponent,"Unfocus",false); }

Le troisime paramtre indique si une transtion anime est utilise. Dans notre cas, la transition na pas besoin dtre joue, ce paramtre est donc false. Au sein du composant dcran Design Component, cliquez-droit sur le composant CurrentSelectionDesign, puis dans le menu Activate State, slectionnez ltat List. Lutilisateur passe automatiquement dans la seconde tape

312

Partie II

Interactivit et cration graphique

dutilisation lorsquil cliquera sur le composant. Si nous nous rfrons au Tableau 10.1, nous devrions galement activer trois autres tats : PersoFocus pour lcran MyCar, Focus pour le composant PersoComponent et Unfocus pour le composant TestComponent. ce stade, nous ne pouvons pas piloter ces tats visuels de manire identique pour deux bonnes raisons. La premire est que linterface de Blend ne nous autorise pas y accder via la liste des tats affichs dans le menu Activate State par le clic-droit. La seconde est assez ennuyeuse: mme si nous y avions accs, ltat ainsi slectionn remplacerait celui que nous avons dj spcifi dans larbre visuel. Autrement dit, vous ne pouvez pas spcifier plus dun comportement de mme type sur un composant en utilisant le menu contextuel par clic-droit. En ralit, cela est possible, mais uniquement en XAML ou par glisser-dposer du comportement. Nous allons simplement ajouter ces comportements en modifiant le code XAML. Pour cela, passez en mode mixte afin que le code apparaisse, puis slectionnez CurrentSelectionDesign. Voici la dclaration XAML du comportement:
<i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. DesignComponent" TargetState="List"/> </i:EventTrigger> </i:Interaction.Triggers>

Ajoutez une balise EventTrigger (dclencheur dvnements) au sein de la liste des dclencheurs et modifiez le code comme ci-dessous:
<i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. DesignComponent" TargetState="List"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens.Screen_1_3" TargetState="PersoFocus"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen=" CarResellerScreens. PersoComponent" TargetState="Focus"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. TestComponent" TargetState="Unfocus"/> </i:EventTrigger> </i:Interaction.Triggers>

Testez le prototype dans le navigateur, lorsque vous cliquez sur la liste, trois transitions sont joues simultanment. La premire concerne le panneau design lui-mme lorsqu'il passe dans ltat List. La deuxime est joue au sein de lcran MyCar et affiche ltat PersoFocus. La troisime affiche le composant PersoComponent en mode Focus. Il faudrait maintenant jouer la transition inverse lorsque lutilisateur souhaite modifier ses critres de slection. Cela consiste rafficher ltat DesignFocus de lcran MyCar lorsque lutilisateur clique sur le titre du panneau TitleDesign dans DesignComponent. Comme le titre du panneau est situ en dessous de lobjet ColorDesign, le clic de lutilisateur ne sera pas diffus. Pour rgler ce problme, il suffit de passer la proprit IsHitTestVisible de lobjet ColorDesign false. De la mme manire que prcdemment, ajoutez les balises XAML comme montr ci-dessous:
<Image x:Name="TitleDesign" Height="44" HorizontalAlignment="Left" Margin="6,3,0,0" VerticalAlignment="Top" Width="99"

Chapitre 10

Prototypage dynamique avec SketchFlow

313

Source="DesignPanel_Images/TitleDesign.png"> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. DesignComponent" TargetState="Focus"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. Screen_1_3" TargetState="DesignFocus"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. PersoComponent" TargetState="Unfocus"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. TestComponent" TargetState="Unfocus"/> </i:EventTrigger> </i:Interaction.Triggers> </Image>

Vous avez la possibilit de consulter le rsum des tats pour visualiser les transitions. Testez le prototype; vous constatez que cette fois, vous pouvez passer dun tat lautre tout moment en cliquant alternativement sur la liste et le titre.
NOTE INFO

Notre application met en valeur une erreur de conception classique. Lorsque lutilisateur a slectionn sa voiture dans la liste, le composant PersoComponent est mis au premier plan et seule la liste des voitures slectionnables est visible. Si cette voiture ne lui correspond pas et quil souhaite changer ses critres, aucun indice visuel ne lui indique que le titre lui permet de rafficher la totalit du panneau DesignComponent. Il naura pas forcment lide de le cliquer. Le mieux, dans ce cas, est dafficher une icne sous forme de flche de retour afin que linternaute puisse aisment revenir sur ses pas.

Si besoin, nhsitez pas modifier les marges de chaque lment, pour obtenir un alignement des objets sans effets de bords. Une fois que lutilisateur a personnalis sa voiture (dans le deuxime panneau), il est temps pour lui de demander un rendez-vous pour la tester en condition relle. Au sein du composant TestComponent, cliquez-droit sur le composant ColorTestDrive, puis au sein du menu Activate State, slectionnez ltat Focus. Lorsque lutilisateur cliquera sur ce panneau, celui-ci se dpliera et affichera le formulaire. Vous devez galement grer les quatre autres transitions que nous avons dj voques auparavant. Vous pouvez une fois de plus modifier le code XAML:
<i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens.Screen_1_3" TargetState="TestFocus"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. TestComponent" TargetState="Focus"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. DesignComponent" TargetState="Unfocus"/>

314

Partie II

Interactivit et cration graphique

</i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. PersoComponent" TargetState="Unfocus"/> </i:EventTrigger> </i:Interaction.Triggers>

Dans un premier temps, il vous suffit de grer cette navigation en ajoutant les comportements ncessaires sur le composant PersoComponent, directement au sein de lcran MyCar:
<i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens.Screen_1_3" TargetState="PersoFocus"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. TestComponent" TargetState="Unfocus"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. DesignComponent" TargetState="List"/> </i:EventTrigger> <i:EventTrigger EventName="MouseLeftButtonDown"> <pb:ActivateStateAction TargetScreen="CarResellerScreens. PersoComponent" TargetState="Focus"/> </i:EventTrigger> </i:Interaction.Triggers>

Dans la carte de navigation, double-cliquez sur le composant dcran TestComponent. Vous devez encore activer ltat Filled affich lorsque lutilisateur soumet correctement le formulaire de rendez-vous. Cliquez-droit sur le bouton de soumission et choisissez ltat Filled, le projet est termin. Vous avez peut-tre remarqu plusieurs messages dalerte dans linterface de Blend tout au long de lexercice (voir Figure10.50).
Figure10.50
Messages dalerte.

Ces messages sont assez clairs, ils vous signalent que le mot Focus est dj utilis et hrit en interne par les contrles utilisateur standard. Vous risquez de rendre cette proprit inaccessible, voir de lcraser. Ce nest pas grave dans la mesure o vous crez un prototype. Par contre, en mode de production, nommer les tats avec des noms identiques certains du framework Silverlight, peut engendrer des conflits et des bogues difficiles prvoir. Pour viter ce type de message, vous pouvez modifier le nom des tats visuels lis au focus en les francisant. Le prototype finalis est accessible dans: chap10/CarReseller.zip. Au prochain chapitre, nous approfondirons nos connaissances des ressources graphiques utilisables dans les projets Silverlight. Nous aborderons galement les bonnes pratiques de production concernant leur organisation et leur partage.

Partie III Conception dapplications riches 11


Ressources graphiques
Depuis le dbut de ce livre, nous avons largement voqu la capacit de Silverlight quant la simplification de la communication entre chaque acteur. Depuis quelques annes, cette collaboration intermtiers est une problmatique centrale et incontournable. Le dveloppement informatique a dbut ds les annes quarante grce des personnages emblmatiques comme Alan Turing. Ds lors, nous avons vu lapparition de nombreux modles de conception toujours plus performants. Ce secteur est aujourdhui parvenu une sorte de maturit et offre un large ventail de modles de conception.

316

Partie III

Conception dapplications riches

Toutefois, larrive de technologies comme WPF ou Silverlight remet en cause un certain nombre dhabitudes acquises au profit de lergonomie et de lexprience utilisateur. Comparativement, la technologie Winforms, tourne essentiellement vers la fonctionnalit, na que trs peu besoin dvoluer, elle produit du fonctionnel de manire trs satisfaisante et ne prend pas vraiment en compte la conception dinterfaces graphiques avances. Certaines entreprises ont simplement dcid de ne pas voluer vers WPF pour cette raison. Cela peut se comprendre aisment bien que ce soit au dtriment de lutilisateur. Le design, lergonomie ou tout type de contrainte qui nest pas directement lie la fonctionnalit, met en danger sa conception mme. Pourquoi? Parce quil est bien plus facile de concevoir une application fonctionnelle en Winforms ou en Java, que dobtenir la mme qualit de conception tout en ajoutant des contraintes techniques et architecturales lies lexprience utilisateur ou au design. Le but des plateformes WPF et Silverlight est prcisment de rpondre cette problmatique consistant marier le design dinterfaces visuelles (sous tous ses aspects) et le dveloppement informatique. Ces plateformes russissent ce pari de manire lgante et efficace dun point de vue architecture et productivit. Une partie de cette russite provient de la notion de ressources. Une bonne gestion des ressources est lune des cls du succs et facilite grandement ladaptation des savoir-faire. Si vous souhaitez simplifier votre manire de produire une application travers la mise en place dune collaboration intermtiers efficace, ce chapitre est fait pour vous. Dans un premier temps, vous apprendrez catgoriser les ressources et dcouvrirez les principes de base inhrents leur utilisation. Par la suite, vous utiliserez les ressources graphiques de manire concrte travers lintgration graphique dun lecteur multimdia. Ainsi, vous aborderez lutilisation des ressources de couleurs et de pinceaux, puis celles qui sont lies lutilisation de mdias externes, comme les images ou les polices de caractres. Dans un second temps, vous concevrez des styles et des modles personnaliss permettant de modifier laffichage des contrles Silverlight. Vous dcouvrirez ainsi le confort de conception apport par les mcanismes de liaison et comment crer des ensembles de donnes fictives facilitant la personnalisation de contrle de donnes.

11.1 Quest-ce quune ressource


Les ressources ont pour objectif dtre rutilises, soit lors de la conception dune application, soit durant leur excution. Lorsque vous modifiez la valeur dune ressource au sein dExpression Blend ou de Visual Studio, toutes les occurrences dobjets utilisant cette ressource sont mises jour. Ce principe est la base du flux de production innovant et efficace propos par Silverlight. Cest un hritage direct du workflow apport par WPF, qui offre un modle encore plus abouti.

11.1.1 Dfinition et types de ressources


Au sein de Silverlight, on distingue trois types de ressources: les ressources logiques, celles de type mdia et les ressources graphiques. Les ressources logiques font rfrence aux objets qui nont pas vocation tre directement affichs par le moteur vectoriel. Ainsi, vous pourriez dfinir une ressource logique de type String rutilisable en plusieurs endroits dune mme application. Les ressources de type mdia sont des fichiers externes que vous pouvez incorporer au sein des projets Silverlight. Les fichiers image (jpg ou png) font partie de cette catgorie. Ils ne sont pas dcrits au sein du code XAML, mais directement rfrencs dans le projet via le fichier csproj.

Chapitre 11

Ressources graphiques

317

Pour finir, les ressources graphiques sont codes en XAML ou en C#, elles sont utilises par des objets destins tre affichs. Les styles et les modles de la classe Button, que nous avons crs au Chapitre7, font partie de cette dernire catgorie. Le Tableau11.1 fournit une liste non exhaustive des ressources classes par type.
Tableau11.1: Divers types de ressources classes par genre

Ressources logiques Double String Boolean Thickness,

Ressources mdias Images: jpg / png Vidos: .wmv Sons: .wma Polices de caractres: .ttf

Ressources graphiques Couleurs Pinceaux Styles Modles

Les ressources graphiques dfinies par le code XAML sont trs pratiques utiliser et maintenir; nous allons le dmontrer travers un cas simple dutilisation. Crez un nouveau projet nomm RessourcesIntro, placez ensuite plusieurs composants de type Border sur le conteneur Layout Root. Dfinissez pour chacun deux une couleur darrire-plan mauve (par exemple #FF937C9D). Slectionnez lun deux au hasard puis, dans le panneau Properties, cliquez sur licne carre droite du champ Opacity. Slectionnez loption Convert to New Resource (voir Figure11.1).
Figure11.1
Conversion dune valeur en ressource.

Une bote de dialogue apparat. Elle vous permet de configurer la cl de ressource ainsi que lendroit o la stocker. Modifiez simplement le nom de la cl de ressource en Border Opacity. Nommer les ressources permet, entre autres, de les identifier facilement par la suite. Veillez nommer vos ressources le plus explicitement possible car un projet peut en contenir un nombre trs important. Le but est de retrouver la ressource recherche au plus vite et de permettre aux diffrents intervenants du projet didentifier les ressources cres (voir Figure11.2). Ne changez pas les autres options, vous dcouvrirez leur intrt tout au long de ce chapitre. Une fois le nom de la cl modifi, validez en cliquant sur OK. Comme vous le constatez, les ressources sont accessibles par des cls (x:Key en XAML). Ce comportement est tout fait logique car elles sont stockes dans des listes particulires implmentant linterface IDictionnary. Ces listes sont constitues de couples cl/valeur et sont nommes dictionnaires. Accder aux valeurs dun dictionnaire est possible grce aux cls qui leurs sont associes.

318

Partie III

Conception dapplications riches

Figure11.2
Fentre de cration de ressource.

NOTE INFO

Ce principe sapplique parfaitement WPF, mais diffre lgrement pour Silverlight. Les ressources Storyboard en sont un exemple. Au Chapitre 6, nous les avons voques plusieurs reprises. Les animations sont des ressources qui ont la possibilit dtre directement accessibles via lattribut x:Name. Ainsi, lorsque vous crez une animation au sein dun projet Silverlight, celle-ci est bien contenue dans un dictionnaire de ressources propre au User Control principal, mais elle est accessible par son nom dexemplaire. Cela permet au dveloppeur de les cibler directement via C#, comme il le ferait avec une instance dobjet standard. Dans lenvironnement WPF, grer les animations se rvle lgrement plus complexe pour les dbutants car ils doivent utiliser la cl afin de rcuprer linstance quils transtypent en tant que Story board. Au final, la manire daccder aux animations dans Silverlight est plus pratique, mais se rvle limite. En effet, il est impossible de dclencher un mme Storyboard sur plusieurs objets la fois, ce qui nest pas le cas pour WPF.

Les dictionnaires de ressources sont des instances de la classe Dictionary spcifiques car les cls sont forcment de type String. Voici le code XAML de notre projet:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib" x:Class="RessourcesIntro.MainPage" Width="640" Height="480"> <UserControl.Resources> <System:Double x:Key="BorderOpacity">1</System:Double> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <Border Height="115" HorizontalAlignment="Left" Margin="49,36,0,0" VerticalAlignment="Top" Width="118" Opacity="{StaticResource BorderOpacity}" Background="#FF937C9D" BorderBrush="Black" BorderThickness="1"/> <Border Margin="223,203,294,180" Background="#FF937C9D" BorderBrush="Black" BorderThickness="1"/> <Border Height="138" HorizontalAlignment="Right" Margin="0,66,64,0" VerticalAlignment="Top" Width="134" Background="#FF937C9D" BorderBrush="Black" BorderThickness="1"/> </Grid> </UserControl>

Chapitre 11

Ressources graphiques

319

Comme vous le constatez, la valeur de lopacit a t dfinie au sein dune ressource de type double. La proprit Opacity du premier contrle Border se contente de rfrencer la cl. Faites en sorte que chaque instance de la classe Border rfrence une valeur dopacit pointant vers la ressource BorderOpacity. Pour cela, vous pouvez coder en XAML ou utiliser linterface de Blend, ce dernier moyen reste le plus simple. Slectionnez les deux autres objets Border, et dans le panneau Properties, cliquez sur licne carre situe droite du champ Opacity. Slectionnez ensuite loption Local Resource, puis cliquez sur BorderOpacity (voir Figure11.3).
Figure11.3
Affectation dune ressource une proprit dobjet via Blend.

Dsormais, toutes les instances de Border partagent la mme opacit en faisant rfrence la ressource BorderOpacity. Modifier leur opacit revient changer la valeur de la ressource. cette fin, vous pouvez utiliser le panneau Resources. Ouvrez-le et dpliez UserControl. De cette manire, vous accdez toutes les ressources dfinies pour MainPage.xaml. Une fois larborescence du UserControl dplie, la ressource apparat en dessous. Changez sa valeur en passant le champ BorderOpacity 0.4. Vous constatez que lopacit de chaque Border est mise jour dynamiquement. Vous pouvez procder de la mme manire avec la proprit BorderThickness ; il est bien pratique dhomogniser lpaisseur des bords des instances de Border au sein dune application.

11.1.2 Les dictionnaires de ressources


Malgr les apparences du code XAML gnr par Blend, toutes les ressources qui ne sont pas de type multimdia (image, vido,) sont stockes au sein de dictionnaires de ressources. Nous expliquerons ce principe dans cette section.

11.1.2.1 Stockage et porte des ressources


Ces dictionnaires de ressources, dclars par de simples balises XAML, peuvent tre dfinis plusieurs niveaux, ce qui dtermine directement leur porte dutilisation. Comme tous les objets de type FrameworkElement possdent la proprit Resources type ResourceDictionnary, ils ont la capacit davoir leur propre dictionnaire de ressources. Voici les diffrents lieux de stockage possibles:

Au sein de lapplication elle-mme, soit dans le fichier App.xaml. Dans ce cas, la ressource sera disponible dans toutes les pages du projet. Ce type de stockage peut apparatre limit. Diffrents projets, au sein dune mme solution, nauront pas accs aux ressources que les uns ou les autres possdent. Voici le code XAML gnr dans Blend par dfaut:

320

Partie III

Conception dapplications riches

<Application.Resources> <CornerRadius x:Key="CornerRadius1">0</CornerRadius> </Application.Resources>

ATTENTION

Ne confondez pas projet et solution. Lorsque vous crez un nouveau projet via le menu New Project, vous gnrez en fait une solution qui contient un projet du mme nom. Vous pouvez toutefois ajouter autant de projets la solution que vous le souhaitez. Le fichier App.xaml est propre chacun des projets de type Application Silverlight, contenus au sein dune solution. Stocker les ressources dans le fichier App.xaml dun projet limitera leur porte ce projet, ce qui est souvent suffisant.

la racine dune page de lapplication, par exemple au sein du fichier MainPage.xaml. Cest loption propose par dfaut, au sein de linterface de Blend, lors de la cration dune ressource. Tous les objets de la page auront accs aux ressources de cette dernire. Les objets prsents dans une autre page de lapplication ny auront pas droit sauf dans certains cas spcifiques. Lcriture XAML est quivalente celle des ressources dapplication, mais User Control remplace Application:
<UserControl.Resources> <System:Double x:Key="BorderOpacity">1</System:Double> </UserControl.Resources>

Directement dans la balise dun contrle. Un conteneur Grid possderait ainsi une balise enfant <Grid.Resources> qui contiendrait les ressources uniquement disponibles ses enfants. Par dfaut, linterface de Blend ne propose pas de paramtrer ce type de stockage. Cela nest pas forcment pratique sauf cas exceptionnels. Dans un fichier externalis et indpendant. Lorsque lon parle de dictionnaires de ressources, on voque gnralement un dictionnaire de ressources externalis. Au Chapitre10, consacr SketchFlow, les styles taient centraliss dans un fichier unique nomm Sketch Styles. xaml, celui-ci contenait des ressources au sein de la balise racine <ResourceDictionary>. Ce mode de stockage est sans doute le plus souple. Ses principaux avantages sont de faciliter la collaboration, le partage, la maintenance et laccs aux ressources. Ds que vous concevez en ayant pour objectif la rutilisation et loptimisation des flux de production, la cration de dictionnaires de ressources externaliss se rvle idale. Ils peuvent tre rfrencs par tous les fichiers XAML qui ont alors accs leur contenu. Ils sont par dfaut rfrencs par App. xaml et bnficient ainsi de la porte du projet. Ces dictionnaires ne souffrent donc pas des limitations qui existent pour les ressources directement contenues dans les fichiers App.xaml ou MainPage.xaml. Ils sont partageables entre plusieurs pages, projets et solutions. Il nest toutefois pas toujours intressant dexternaliser systmatiquement les ressources. Cest notamment le cas lorsque vous souhaitez fournir un composant embarquant ses propres ressources. De plus, la gestion des accs peut parfois devenir dlicate.

Vous pouvez consulter la Figure11.4 illustrant diffrentes portes dutilisation.

Chapitre 11

Ressources graphiques

321

Figure11.4
Porte dutilisation des dictionnaires de ressources.
Solution : RessourceIntro.sIn Projet : RessourceIntro.csproj Grid <Grid.Resources> </Grid.Resources> MainPage.xaml <UserControl.Resources> </UserControl.Resources> Canvas <Canvas.Resources> </Canvas.Resources> Page2.xaml Button MainPage.xaml Grid Projet : Projet2.csproj

Button Rectangle CheckBox

Dictionnaire de ressources rfrenc par App.xaml

Dictionnaire de ressources rfrenc uniquement par Page2.xaml

Importation du dictionnaire de ressources rfrenc par App.xaml

Dictionnaire de ressources rfrenc par une grille

Dictionnaire de ressources en ligne charg via la mthode statique XamlReader.Load():

11.1.2.2 Dclaration XAML


Revenons sur le code XAML gnr par Blend lorsque vous stockez les ressources dans une page de lapplication (UserControl):
<UserControl.Resources> <System:Double x:Key="BorderOpacity">1</System:Double> </UserControl.Resources>

Cette criture est en fait une version simplifie de lcriture dun dictionnaire de ressources. Cidessous, vous pouvez lire un code XAML plus verbeux et prcis, mais quivalent en terme de rsultat:
<UserControl.Resources> <ResourceDictionary> <System:Double x:Key="BorderOpacity">0.4</System:Double> </ResourceDictionary> </UserControl.Resources>

Lutilisation de la classe ResourceDictionary est souvent implicite car Blend adopte par dfaut lcriture simplifie. Toutefois, lorsque vous rfrencerez des dictionnaires externes, vous obtiendrez une dclaration XAML complte ainsi quune nouvelle balise <ResourceDictionary.

322

Partie III

Conception dapplications riches

MergedDictionaries>. Celle-ci permet de rfrencer des dictionnaires supplmentaires via la proprit Source de la classe ResourceDictionary:
<UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="BobStyles.xaml"> <ResourceDictionary Source="PatrickStyles.xaml"> </ResourceDictionary.MergedDictionaries> <System:Double x:Key="BorderOpacity">0.4</System:Double> </ResourceDictionary> </UserControl.Resources>

NOTE INFO

Il est possible de charger des dictionnaires de ressources de manire dynamique, cela peut-tre trs lgant et efficace dans le cas dapplications multiclients. Vous pourriez crer un ou plusieurs dictionnaires de ressources par client et les charger la vole, selon le client connect lapplication et sa charte graphique. Cela peut galement rendre un designer plus autonome. Il pourrait modifier un dictionnaire de ressources sur son poste de travail puis remplacer celui prsent sur le serveur web. De cette manire, le visuel de lapplication serait mis jour sans avoir besoin de la recompiler. Cela est ralisable grce la mthode statique Load de la classe XamlReader. Cette mthode est la version manage de la mthode JavaScript createFromXaml disponible depuis la version1 de Silverlight.

11.1.2.3 Externaliser les ressources


Le stockage de ressources dans un fichier spar est une mthodologie recherche par les designers et les dveloppeurs. Il suffit de modifier les ressources contenues dans le fichier, puis de recompiler lapplication pour quelle soit mise jour. Dans ces conditions chaque intervenant y gagne: vous instaurez une sparation des tches tout en respectant le travail de toutes les parties impliques. Le graphiste naura pas accs au code logique, et le dveloppeur ne se proccupera pas de savoir ce qui a chang graphiquement entre deux versions de lapplication. Au final, il sera possible de mettre en place une relle communication intermtiers de manire douce et progressive. Comme nous lavons vu (voir section11.1.1), la cration dun dictionnaire de ressources peut se faire lorsque vous gnrez une nouvelle ressource (en cochant loption adquate). Il est galement possible de produire un dictionnaire de ressources vide, puis de lui ajouter des ressources au fur et mesure de la production. Le panneau Resources dExpression Blend est dune grande aide pour ce genre de tches. Ouvrez-le et cliquez sur licne situe en haut droite ( ). Une bote de dialogue apparat, vous demandant de saisir le nom du dictionnaire crer (voir Figure11.5). Comme les ressources stockes seront de type double, autant lappeler DoubleRD.xaml.
NOTE INFO

Le nommage des dictionnaires est un point capital car il donne du sens et structure le projet. brve chance, un bon nommage facilite la comprhension du projet pour chacun des acteurs. Nous aborderons les bonnes pratiques de stockage et dorganisation des ressources tout au long des exercices de ce chapitre.

Chapitre 11

Ressources graphiques

323

Figure11.5
Cration dun nouveau dictionnaire de ressources.

Lorsque le dictionnaire est cr, le fichier App.xaml est modifi par dfaut. En son sein, un lien logique, dcrit en XAML, pointe dsormais vers ladresse du fichier DoubleRD.xaml. Il est possible de gnrer ou de supprimer ce type de lien via linterface de Blend. Cela permet notamment de ddier des dictionnaires de ressources certaines pages de lapplication et pas dautres. Pour cela, chargez la page principale MainPage.xaml dans la fentre de cration (si ce nest pas dj fait). Ensuite, au sein du panneau Resources, dpliez App.xaml, cliquez-droit sur le lien nomm LinkTo : DoubleRD.xaml et slectionnez loption delete. Une fentre apparat vous indiquant quil est possible que certaines ressources ne soient plus correctement rfrences. Ce nest pas grave puisque notre dictionnaire est vide ; validez le choix. Vous dtruisez de cette manire le lien pointant vers le dictionnaire externe sans supprimer le fichier lui-mme. Nous allons maintenant ajouter un lien dans la page principale ciblant le dictionnaire. Cliquez-droit sur le UserControl principal, puis choisissez loption Link to Resource Dictionary et le dictionnaire DoubleRD.xaml (voir Figure11.6).
Figure11.6
Crer un lien vers un dictionnaire de ressources.

Dsormais, le dictionnaire est directement rfrenc par MainPage.xaml et ses ressources ne seront plus accessibles aux autres pages de lapplication. Nous allons insrer une ressource dans ce dictionnaire en quelques clics de souris. Au sein de larbre visuel de MainPage.xaml, crez une instance dEllipse, puis cliquez sur licne carre situe droite du champ Opacity. Choisissez loption Convert to New Resource. Dans la bote de dialogue affiche, entrez EllipseOpacity comme cl de ressource, slectionnez ensuite loption Resource Dictionary, vrifiez que le dictionnaire choisi dans la liste est bien DoubleRD.xaml, puis cliquez sur OK (voir Figure11.7).

324

Partie III

Conception dapplications riches

Figure11.7
Crer un lien vers un dictionnaire de ressources.

Dans la section suivante, vous apprendrez appliquer des ressources via linterface de Blend et le langage XAML, mais galement de manire dynamique en C#.

11.1.3 Appliquer des ressources


Maintenant que nous avons vu comment stocker les ressources, nous allons apprendre diffrentes faons de les affecter aux proprits dobjets. La premire manire de procder consiste cliquer sur licne carre situe ct dun champ, slectionner loption Local Resource, puis de choisir la ressource dans la liste prsente. Dans tous les cas, Blend filtre les ressources accessibles en fonction du type de la proprit. Ainsi, il est impossible, via linterface de Blend, dappliquer une ressource de couleur une proprit dopacit car cette dernire naccepte que les valeurs de type double. Dans Blend, la deuxime mthode consiste ouvrir le panneau Resources, dplier lun des conteneurs de ressources, puis glisser-dposer la ressource de votre choix sur un objet. Une liste apparat directement au sein de la fentre de cration. Il suffit de choisir lune des proprits proposes dans la liste pour lui affecter la ressource (voir Figure11.8).
Figure11.8
Affectation dune ressource par glisserdposer sur un Border.

Comme vous le constatez, Blend vous propose une liste de proprits compatibles avec le type de la ressource dpose. La proprit Tag tant type Object, celle-ci peut recevoir tout type de valeur. Le type Thickness est utilisable dans de nombreuses proprits dont les marges intrieures et extrieures (respectivement Padding et Margin). Contrairement aux autres types de ressources, les modles peuvent galement tre appliqus via un clic-droit sur lobjet. Nous utiliserons cette mthode partir de la section11.4.
NOTE INFO

Dans tous les cas et au sein dExpression Blend, lorsquune ressource est applique une proprit dobjet graphique (UIElement), la proprit est entoure dun liser vert visible dans le panneau Properties. Ce repre visuel est utile pour identifier les proprits lies.

Chapitre 11

Ressources graphiques

325

Dune toute autre manire, modifier le code dclaratif XAML est pratique lorsque vous avez besoin daffecter rapidement une ressource plusieurs objets la fois. En XAML, vous dfinissez le plus souvent des valeurs en dur, par exemple Opacity="0.4". Il est toutefois possible dassigner des cls de ressources, des liaisons de donnes ou de modles, ou encore la valeur null (via {x:Null}). Ces valeurs ne peuvent pas tre directement crites entre guillemets car elles sont en fait des expressions qui doivent tre values la compilation ou lexcution (mis part pour null qui est une valeur particulire). Leur notation se diffrencie par des accolades, vous obtiendrez par exemple:
<UserControl.Resources> <ResourceDictionary> <System:Double x:Key="BorderOpacity">0.4</System:Double> </ResourceDictionary> </UserControl.Resources> <Border x:Name="MonBorder" Opacity="{StaticResource BorderOpacity}">

NOTE INFO

Le mot-cl StaticResource indique lutilisation dune ressource de type statique. Cela signifie que la ressource est dfinie la compilation une bonne fois pour toutes. Le mot-cl Dynamic Resource nexiste pas encore du ct de Silverlight. Il est uniquement prsent du ct WPF. Il permet la proprit dtre mise jour, durant lexcution, chaque fois que la valeur de la ressource est modifie de lextrieur.

Il est important de noter que le nud dclarant un dictionnaire de ressources doit toujours tre le premier des nuds enfants dun document XAML. La lecture des nuds XAML est toujours faite dans lordre des enfants. Si un objet rfrence une ressource statique qui nest dclare quaprs lui-mme, linterprteur XAML lvera une erreur (voir Figure11.9).
Figure11.9
Erreur leve lorsquune ressource est dclare aprs un nud enfant lutilisant.

Thoriquement, ce type de problmatique ne devrait pas survenir sous Expresion Blend car les dictionnaires de ressources sont toujours dclars en premier. Il peut toutefois tre utile de connatre ce type de comportement. Appliquer une ressource via C# est assez simple. Il vous faut tout dabord rcuprer la ressource en ciblant le dictionnaire qui la contient. Lcriture sera lgrement diffrente selon que le dictionnaire est dclar dans lapplication, une page ou une instance de FrameworkElement:
//Accs la ressource dans le dictionnaire au sein de lapplication double MonBorderOpacity=(double)App.Current.Resources["BorderOpacity"];

326

Partie III

Conception dapplications riches

//Dans la page principale de type MainPage double MonBorderOpacity =(double)this.Resources["BorderOpacity"]; //Au sein de la grille principale LayoutRoot double MonBorderOpacity =(double)LayoutRoot.Resources["BorderOpacity"];

Les valeurs stockes dans le dictionnaire sont toujours types object afin de garantir un maximum de souplesse. Il vous faudra donc convertir le type de manire explicite pour rcuprer une valeur utilisable:
foreach (UIElement uie in LayoutRoot.Children) { uie.Opacity = MonBorderOpacity; }

Les dictionnaires de ressources externaliss sont le plus souvent rfrencs par lapplication via le fichier App.xaml. Dans ce cas, il faut les considrer comme faisant partie du dictionnaire contenu par App.Current.Resources. Vous pourriez toutefois crer une rfrence un dictionnaire externalis au sein de nimporte quelle page ou de nimporte quel composant. Ces dictionnaires sont simplement fusionns avec ceux qui les rfrencent. Voici un exemple de code XAML dcrivant ce type de cas de figure:
<UserControl <UserControl.Resources> <ResourceDictionary> <System:Double x:Key="BorderOpacity">0.4</System:Double> </ResourceDictionary> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <Grid.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="ResourceDictionary1.xaml"/> </ResourceDictionary.MergedDictionaries> <System:Double x:Key="BorderHeight">135</System:Double> </ResourceDictionary> </Grid.Resources> <Border Height="{StaticResource BorderHeight}" Opacity="{StaticResource BorderOpacity}" /> <Border Height="{StaticResource BorderHeight}" Opacity="{StaticResource BorderOpacity}" /> <Border Height="138" BorderThickness="{StaticResource BorderThickness}" Opacity="{StaticResource BorderOpacity}" CornerRadius="{StaticResource CornerRadius1}" /> </Grid> </UserControl>

Dans la situation dcrite ci-dessus, la rfrence dun dictionnaire externe est dclare dans le dictionnaire de la grille LayoutRoot. Ainsi, pour accder une ressource contenue dans ce dernier, il suffit de cibler la cl approprie via la proprit Resources de cette grille:
Thickness monBorderThickness = (Thickness)LayoutRoot. Resources["BorderThickness"];

Chapitre 11

Ressources graphiques

327

Nous avons abord les principes majeurs inhrents lutilisation des ressources. Dans les prochaines sections, nous mettrons en pratique les connaissances acquises pour manipuler des ressources graphiques.

11.2 Les pinceaux


Les pinceaux reprsentent les ressources graphiques par excellence. Ce sont des instances dobjets hritant de la classe abstraite Brush. Ils sont la base de tout visuel car les proprits de remplissage comme BackgroundColor, BorderBrush, Fill, Stroke (Shape), propres aux objets graphiques, nacceptent que ce type dinstances. Dans cette section, vous apprendrez utilisez et organiser vos pinceaux de manire efficace. Afin de travailler dans des conditions relles, nous allons intgrer partiellement un lecteur multimdia. Les Figures 11.10 et 11.11 en donnent un aperu.
Figure11.10
Lcran daccueil du lecteur multimdia.

Figure11.11
La liste de lecture complte.

Le lecteur multimdia possde trois tats visuels et lutilisateur reste dans une seule page lorsquil utilise le lecteur. Le premier tat reprsente un cran daccueil compos dune mire de bienvenue. Le deuxime est constitu dune liste de lecture proposant diffrents types de fichiers multimdias lisibles par Silverlight. Lorsque lun de ceux-ci est slectionn, le troisime tat visuel apparat. Dans ce mode daffichage, la liste des mdias est replie gauche, ne laissant ainsi apparatre que

328

Partie III

Conception dapplications riches

le titre et le type de chaque fichier. Dans lespace libr au centre et droite, un lecteur multimdia jouera ou affichera la vido, le son ou limage slectionns. Avant de continuer, il est ncessaire de tlcharger les fichiers de travail ainsi que le projet LecteurMultiMedia_Base compress au format zip. Les fichiers sont disponibles dans larchive Assets.zip et le projet dans LecteurMultiMedia_Base.zip du dossier chap11. Ce dernier contient le visuel de base du lecteur multimdia, partir duquel nous raliserons les exercices qui suivent. Une fois les deux fichiers rcuprs et dcompresss sur votre disque dur, ouvrez le projet avec Expression Blend.

11.2.1 Couleurs et pinceaux


Les ressources de couleurs et les pinceaux de dgrads reprsentent lune des bases fondamentales du flux de production Silverlight. Grce eux, il est facile de relooker tout un site en trs peu de temps. Nous verrons comment crer et maintenir ces ressources.

11.2.1.1 Les ressources de couleurs


Lorsque vous concevez une application sous Expression Blend, lune des premires tapes consiste sauvegarder les couleurs de base dfinies par la charte graphique. Comme vous les utiliserez tout au long du projet, le mieux est de les centraliser au sein dun dictionnaire de ressources externalis. Dans le panneau Projects, crez un nouveau rpertoire nomm RD et slectionnez-le. Ce rpertoire contiendra tous les dictionnaires de ressources utiliss dans lapplication. Ajoutez-y un nouveau dictionnaire de ressources nomm Couleurs. Vous avez la possibilit dutiliser le panneau Resources (rfrez-vous alors la section11.1). Une autre manire plus directe consiste cliquer-droit sur le rpertoire RD, puis choisir loption Add New Item (voir Figure11.12).
Figure11.12
Menu affich au clic-droit sur le rpertoire RD.

Dans la bote de dialogue apparaissant, choisissez Resource Dictionary et spcifiez Couleurs. xaml comme nom de fichier. Cliquez ensuite sur OK pour valider. Nous allons dsormais crer chaque ressource de couleur dont nous avons besoin. Les couleurs ncessaires sont prsentes au Tableau11.2.

Chapitre 11

Ressources graphiques

329

Tableau11.2: Liste des couleurs sauvegarder comme ressource

Couleurs Gris transparent Gris clair Gris fonc Rose fonc Vert Yellow Orange Cyan

Noms de ressource x:Key PanelBackground ControlsBackground PlayerBackground VideoTheme LayoutModeTheme SoundTheme TimeCodeTheme BitmapTheme

Valeurs hexadcimales #CD9E9E9E #FFDCDBD8 #FF444444 #FFC70963 #FF7AC909 #FFFFC800 #FFFF5900 #FF08AFC8

Pour crer une ressource de couleur, il suffit de slectionner un objet puis de cliquer sur lune de ses proprits de remplissage. Vous pouvez rfrencer la valeur de la proprit sous forme de ressource de couleur unie. Par exemple, vous pouvez slectionner la grille principale LayoutRoot, puis sa proprit Background. Spcifiez ensuite la couleur souhaite. Il suffit de cliquer sur licne reprsentant une double flche situe gauche de la valeur hexadcimale (voir Figure11.13).
Figure11.13
Rfrencer une couleur unie sous forme de ressource de couleur.

Dans la bote de dialogue Create Color Resource, dfinissez PlayerBackground comme cl de ressource, puis enregistrez la cl dans le dictionnaire Couleurs.xaml que nous avons cr prcdemment. cette fin, choisissez la dernire option de stockage. Vous venez de crer votre premire ressource de couleur. Le code XAML gnr est le suivant:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Color x:Key="PlayerBackground">#FF444444</Color> </ResourceDictionary>

Lcriture est relativement simple: une instance de la classe Color est stocke dans le dictionnaire. Elle accepte par dfaut une valeur32 bits (4 octets) dcrivant quatre couches, alpha, rouge, vert et bleu, exprimes en hexadcimal. Par exemple, lorsquune couleur est compltement opaque,

330

Partie III

Conception dapplications riches

elle dbute par le couple FF qui indique la valeur hexadcimale maximale de la couche de transparence. Il est galement possible de fournir une proprit statique de la classe Colors. Vous pourriez ainsi crire:
<Color x:Key="PlayerBackground">Cyan</Color>

Finalement, il est encore plus rapide de dupliquer le nud XAML dj prsent pour gnrer les ressources de couleurs listes au Tableau11.2. Voici le code XAML gnr une fois cette tape passe:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Color x:Key="PlayerBackground">#FF444444</Color> <Color x:Key="PanelBackground">#CD9E9E9E</Color> <Color x:Key="ControlsBackground">#FFDCDBD8</Color> <Color x:Key="VideoTheme">#FFC70963</Color> <Color x:Key="LayoutModeTheme">#FF7AC909</Color> <Color x:Key="SoundTheme">#FFFFC800</Color> <Color x:Key="BitmapTheme">#FF08AFC8</Color> <Color x:Key="TimecodeTheme">#FFFF5900</Color> </ResourceDictionary>

Ouvrez maintenant le panneau Resources et dpliez le dictionnaire Couleurs.xaml, vous y trouverez toutes les couleurs que vous avez dfinies sous forme visuelle (voir Figure11.14).
Figure11.14
Accder aux ressources de couleurs.

Maintenant que les ressources de couleurs sont cres, nous pouvons facilement les appliquer aux objets prsents dans larbre visuel. Au sein de larbre visuel, dans la grille nomme Panneau Liste, slectionnez le trac Panneau. Dans le panneau Brushes, slectionnez sa couleur de remplissage, puis longlet Color Resources. Choisissez la ressource de couleur PanelBackground pour laffecter en tant que remplissage (voir Figure11.15).

Chapitre 11

Ressources graphiques

331

Figure11.15
Appliquer une ressource de couleur via le panneau des proprits.

Il est galement possible de glisser-dposer une ressource de couleur directement sur un objet, puis de choisir la proprit sur laquelle vous souhaitez lapposer. Comme nous lavons voqu au dbut de ce chapitre, lavantage principal des ressources est de mettre jour tous les objets graphiques qui y font rfrence lorsquelles sont modifies. Vous pouvez mettre jour une ressource de couleur de deux manires diffrentes: soit via le panneau Resources, soit directement dans longlet Color Resources du panneau Properties. Dans ces deux cas il suffira de cliquer sur la case de couleur pour modifier son remplissage. Comme vous lavez peut-tre remarqu, la couleur de remplissage a lgrement chang lorsque nous avons appliqu la ressource. Si vous souhaitez moins de transparence sur cette couleur, il suffit de modifier la ressource via le premier couple hexadcimal ciblant lopacit (voir Figure11.16).
Figure11.16
Modifier une ressource de couleur.

Comme vous le constatez, modifier la ressource change les objets lutilisant. Cachez les grilles nommes PanneauListe et PseudoListe afin de faire apparatre lcran daccueil. Affectez-lui la mme ressource et faites de mme avec tous les objets utilisant la mme couleur au sein du projet.

11.2.1.2 Les pinceaux de couleurs


Les pinceaux de couleurs sont des ressources diffrentes en cela quelles contiennent galement des options de remplissage. Elles hritent de la classe abstraite Brush. On en trouve trois catgories: les pinceaux de couleur unie de type SolidColorBrush, ceux de dgrad linaire Linear GradientBrush et les pinceaux de dgrad radial RadialGradientBrush. Les premiers sont uti-

332

Partie III

Conception dapplications riches

liss quand vous dfinissez une couleur unie, par exemple #FFFF5900, ou lorsque vous affectez une ressource de couleur simple. Voici lcriture XAML correspondante aux deux affectations:
<Path x:Name="FondAccueil" Stretch="Fill" StrokeThickness="1" > <Path.Fill> <SolidColorBrush Color="{StaticResource PanelBackground}"/> </Path.Fill> </Path> <TextBlock x:Name="Title" > <TextBlock.Foreground> <SolidColorBrush Color="#FFFFC800"/> </TextBlock.Foreground> </TextBlock>

Comme vous le constatez, les proprits de remplissage acceptent des instances de type Brush. Le langage XAML accepte toutefois des raccourcis dcriture impossibles du ct C#, ainsi on pourra crire:
<Rectangle Height="35 Width="53" Fill="#FF000000" />

Alors quaffecter une ressource ou une couleur en C# devra toujours passer par laffectation dune instance de Brush. Dans le cas dune affectation de ressource de couleur cela donnera:
//Lorsquon rcupre une ressource, on cre un pinceau de couleur unie SolidColorBrush scb = new SolidColorBrush(); //on rcupre une ressource quon transtype en tant quinstance de Color //puis on laffecte la proprit Color du pinceau scb.Color = (Color)App.Current.Resources["PanelBackground"]; //Pour finir on applique le pinceau la proprit Fill //dun exemplaire de Shape Panneau.Fill = scb;

Nous pourrions tout aussi bien affecter le pinceau la proprit Background dune instance de Control. Pour affecter une couleur hexadcimale directement, crivez:
//Lorsquon affecte une valeur brute, on cre un pinceau de couleur unie SolidColorBrush scb = new SolidColorBrush(); //on utilise la mthode FromArgb de la classe Color scb.Color = Color.FromArgb(0xFF,0xFF,0x59,0x00); //On peut galement utiliser une proprit statique de la classe Colors scb.Color = Colors.Orange; Panneau.Fill = scb;

Ds lors, il peut tre intressant pour le dveloppeur que le graphiste cre des ressources de pinceaux car elles sont faciles affecter et conservent en mmoire des proprits de remplissage personnalises via leurs proprits Transform et RelativeTransform. Lintrt dun tel scnario pour les instances de SolidColorBrush est moins grand car la couleur est unie. Toutefois, pour les pinceaux de dgrad, le potentiel doptimisation est assez lev. Afin de gnrer une ressource pinceau, quel que soit son type, il suffit de cliquer sur licne carre situe droite dun champ de remplissage, puis de choisir loption Convert to New Resource Slectionnez le TextBlock nomm Title, en bas gauche de linterface. Affectez-lui un dgrad linaire, par dfaut du noir

Chapitre 11

Ressources graphiques

333

au blanc. Nous allons crer une nouvelle ressource de type pinceau. Pour cela, le mieux est de la stocker, soit dans un dictionnaire prvu cet effet, soit dans celui qui stocke dj les couleurs.
ATTENTION
Si vous crez deux dictionnaires de ressources et que les ressources de lun font rfrence celles contenues dans le second, il est alors ncessaire de crer une liaison. Ainsi, si vous dcidez de crer un dictionnaire de pinceaux et que celui-ci utilise des ressources de couleurs unies dfinies dans un autre dictionnaire de ressources, il faudra les relier via le panneau Resources.

Attention, avant toute action, slectionnez le rpertoire RD au sein du panneau Projects. Crez un nouveau dictionnaire nomm BobifysBrushes.xaml afin dy ajouter le pinceau de dgrad linaire. Vous pouvez maintenant convertir le dgrad en ressource pinceau (voir Figure11.17).
Figure11.17
Gnrer un pinceau de dgrad linaire.

Dans la bote de dialogue affiche, slectionnez le dictionnaire de ressources BobifysBrushes. xaml comme espace de stockage, puis nommez la ressource HotTitle. Voici le code XAML gnr lors de la cration du pinceau:
<LinearGradientBrush x:Key="HotTitle" EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="Black" Offset="0"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush>

Comme vous le constatez, le pinceau est lui-mme constitu de couleurs, vous pouvez facilement les remplacer par des ressources de couleurs. Lavantage de procder de cette manire est de pouvoir mettre jour le pinceau de dgrad via la modification des ressources de couleurs. cette fin, cliquez sur la ressource pour accder au slecteur de couleur. Slectionnez le premier point de couleur du dgrad et appliquez-lui la ressource "SoundTheme" via longlet Color resources. Rptez lopration pour le second point de couleur du dgrad et appliquez-lui la ressource "Timecode Theme" (voir Figure11.18).

334

Partie III

Conception dapplications riches

Figure11.18
Modifier le pinceau de dgrad.

Le pinceau de dgrad est mis jour au sein du dictionnaire de ressources, son code a lgrement chang car ses balises GradientStop rfrencent maintenant des ressources de couleurs:
<LinearGradientBrush x:Key="HotTitle" EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="{StaticResource TimecodeTheme}" Offset="0"/> <GradientStop Color="{StaticResource SoundTheme}" Offset="1"/> </LinearGradientBrush>

ce stade nous avons presque fini, si vous compilez vous risquez davoir des erreurs. Cest tout fait logique, le dictionnaire BobifysBrushes.xaml utilise des ressources de couleurs appartenant un autre dictionnaire. Celles-ci sont accessibles via linterface de Blend car les deux dictionnaires sont rfrencs par App.xaml. Toutefois, il faut crer une liaison au sein du dictionnaire de pinceaux pointant vers celui contenant les couleurs afin quil puisse les utiliser. Dans cette optique, utilisez linterface de Blend de la manire vue la section11.1.2.3 . Le code XAML gnr par Blend donne:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Couleurs.xaml"/> </ResourceDictionary.MergedDictionaries> <LinearGradientBrush x:Key="HotTitle" EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="{StaticResource TimecodeTheme}" Offset="0"/> <GradientStop Color="{StaticResource SoundTheme}" Offset="1"/> </LinearGradientBrush> </ResourceDictionary>

Vous remarquez quil ny a pas besoin de spcifier laccs au rpertoire RD comme ce que nous avons dans le fichier App.xaml:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="LecteurMultiMedia.App"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="RD/Couleurs.xaml"/>

Chapitre 11

Ressources graphiques

335

<ResourceDictionary Source="RD/BobifysBrushes.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>

Cest tout fait logique car les dictionnaires de ressources sont dans le mme rpertoire. Lavantage dutiliser linterface de Blend est que les accs seront rsolus automatiquement pour vous dans de nombreux cas. Recompilez le projet, cette fois lapplication est correctement affiche dans le navigateur. Revenons sur la traduction du code XAML exprimant le dgrad linaire. Les proprits Start Point et EndPoint dfinissent le dbut et la fin du dgrad sous forme de coordonnes relatives x et y. Ainsi la valeur0.5 signifie que leurs coordonnes sont situes 50% de la largeur totale de lobjet; la valeur1 de la proprit EndPoint indique que la fin du dgrad est situe 100% de la hauteur totale de lobjet (donc sur laxe y). Il est possible de modifier ces proprits simplement en dpliant longlet situ sous la barre des dgrads. Vous pouvez galement afficher les coordonnes absolues des points de dpart et darrive grce aux champs quil propose (voir Figure11.19).
Figure11.19
Les options de remplissage des dgrads.

Pour apprendre le fonctionnement des dgrads, le mieux est encore de modifier les proprits exposes dans longlet, sur des dgrads simples.
NOTE INFO

En tant que designer, il est possible que vous soyez tent dutiliser le manipulateur des dgrads dans la barre doutil ( ) afin de mettre jour le pinceau (voir Figure11.20). Cest une mauvaise ide: lorsque vous essayez de modifier le pinceau de dgrad ainsi, vous supprimez automatiquement son affectation au remplissage concern. Ce comportement est logique puisque la configuration du dgrad est dfinie dans le pinceau lui-mme. Blend considre que vous ne souhaitez plus utiliser le pinceau et gnre un nouveau dgrad partir du pinceau existant. Il est donc conseill de finir compltement le dgrad avant de le transformer en pinceau. Vous pouvez galement crer un nouveau dgrad et remplacer les balises au sein du pinceau par celles du nouveau dgrad. De cette manire, le pinceau est mis jour plus facilement.

336

Partie III

Conception dapplications riches

Figure11.20
Essai de modification du pinceau via loutil des dgrads.

Il pourrait tre utile de sauvegarder lun des dgrads grant le reflet lumineux de certains lments de linterface. Dans la grille nomme SliderTimeCode, slectionnez le deuxime enfant de type Path. Il possde un remplissage qui gnre un lger effet de rflexion. Dfinissez-le en tant que ressource de dgrad de la mme manire que prcdemment, nommez-le Reflection et stockez-le dans le dictionnaire ddi aux pinceaux. Le code gnr est lgrement diffrent car il sagit cette fois dun dgrad radial:
<RadialGradientBrush x:Key="Reflection" RadiusX="2.82514" RadiusY="4.23125" Center="0.504054,-2.13556" GradientOrigin="0.504054,-2.13556"> <RadialGradientBrush.RelativeTransform> <TransformGroup/> </RadialGradientBrush.RelativeTransform> <GradientStop Color="#00FFFFFF" Offset="0.495"/> <GradientStop Color="#7FFFFFFF" Offset="0.618605"/> <GradientStop Color="#00FFFFFF" Offset="0.627"/> </RadialGradientBrush>

Comme vous le constatez, quatre proprits sont utilises pour le dfinir : RadiusX, RadiusY, Center et GradientOrigin. Vous notez quil est galement possible daffecter des transformations relatives aux dgrads grce au nud RadialGradientBrush.RelativeTransform (galement valables pour les pinceaux dimages et de vidos). Au sein de Blend, vous y avez accs via le panneau Properties ou la barre doutils. Restez appuy sur loutil des dgrads situ dans la barre doutils des dgrads pour faire apparatre le modificateur de transformations relatives des dgrads ( ).

11.2.2 Les pinceaux dimages et de vidos


Les images ou les vidos sont, la plupart du temps, charges de manire dynamique pour crer un portfolio, un catalogue ou une webtv. Lutilisation de pinceaux dimages (ou de pinceaux vido) est spcifique certaines problmatiques de conception. Cela est particulirement utile lorsquune mme image doit tre affiche plusieurs fois ou que lutilisation dun trac vectoriel se rvle moins pratique dans le flux de production. Dans ce cas, limage nest quune seule fois en mmoire et son pinceau peut tre affich plusieurs fois sans affecter les performances de lapplication.

Chapitre 11

Ressources graphiques

337

Les tapes ncessaires la cration de pinceaux dimages ou de vidos sont similaires. Assez trangement, il est obligatoire dutiliser un composant de type Image ou MediaElement pour fabriquer ce type de pinceau. Voici la procdure de cration: 1. Vous devez commencer par importer une ressource mdia de type image ou vido compatible (png, jpg, wmv, etc.). Cette ressource sera par dfaut compile au sein du fichier xap dans la dll du mme nom. Cest pourquoi il faut viter quelle ne pse trop lourd. 2. Ensuite il faut la double-cliquer au sein du panneau Projects afin de la positionner et de lafficher via lutilisation dun composant adquat. Ainsi, le composant Media Element jouera une vido, le composant Image affichera quant lui les bitmaps. 3. La dernire tape consiste slectionner le composant gnr, puis choisir depuis le menu Tools > Make Brush Ressource > Make Image Brush Resource ou Make Video Brush Resource selon le type de pinceau que vous souhaitez crer. Via le panneau Projects, crez un nouveau rpertoire nomm bitmaps. Cliquez-le droit, puis slectionnez loption Add Existing Item Choisissez le rpertoire ImageBrushes, dans le dossier Assets que vous avez tlcharg et dcompress prcdemment. Slectionnez les trois images au format png places dans le rpertoire et importez-les. Double-cliquez-les afin de crer trois composants Image dans le conteneur LayoutRoot. Slectionnez le rpertoire RD, puis le composant Image correspondant licne de la note de musique, faites-en un pinceau dimage via le menu Tools. Choisissez de crer un nouveau dictionnaire de ressources ddi aux pinceaux dimages et de vidos. Nommez le dictionnaire VideosImagesBrushes.xaml et le pinceau IconMusic. Procdez de mme avec les deux autres instances dImage et stockez les pinceaux dans le nouveau dictionnaire. Supprimez ensuite les composants Image car ils nont plus aucune utilit. Voici le code XAML gnr:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ImageBrush x:Key="IconBitmap" ImageSource="bitmaps/Bitmap.png"/> <ImageBrush x:Key="IconMusic" ImageSource="bitmaps/Music.png"/> <ImageBrush x:Key="IconVideo" ImageSource="bitmaps/video.png"/> </ResourceDictionary>

Il est souvent ncessaire de rgler certains dtails pour que tout fonctionne correctement. Ouvrez le panneau Resources et dpliez le dictionnaire VideosImagesBrushes.xaml afin de voir si les images apparaissent bien. En ralit, un bogue de linterface de Blend peut tre assez droutant: notre dictionnaire est dans le rpertoire RD alors que les images sont dans le rpertoire bitmaps, le chemin daccs dcrit dans le XAML au-dessus est donc faux. Voici le code XAML modifier pour que les pinceaux dimages soient correctement affichs:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ImageBrush x:Key="IconBitmap" ImageSource="../bitmaps/Bitmap.png"/> <ImageBrush x:Key="IconMusic" ImageSource="../bitmaps/Music.png"/> <ImageBrush x:Key="IconVideo" ImageSource="../bitmaps/video.png"/> </ResourceDictionary>

338

Partie III

Conception dapplications riches

NOTE INFO

Comme vous le constatez, nous avons cr un nouveau dictionnaire ddi ce type de ressources. Plusieurs contraintes techniques propres au flux de production nous orientent dans cette direction. La plus importante est lie au fait que les pinceaux dimages font rfrence des objets physiques propres au projet. Si vous devez par la suite exporter les pinceaux dimages ou de vidos dans un autre projet, il vous faudra galement dupliquer le rpertoire physique contenant les images ou les vidos. Cette contrainte nexiste pas pour les dictionnaires de pinceaux de dgrads ou les ressources de couleurs qui sont autonomes par nature. Ces ressources sont en effet dcrites entirement en XAML, exporter le dictionnaire suffit. Dans ces conditions autant scinder ces deux types de pinceaux du point de vue de lorganisation. La deuxime raison est plus prosaque : nous aurions pu stocker les pinceaux dans la page principale, mais autant organiser les ressources sainement ds le dpart et faciliter la maintenance de lapplication.

Afin dappliquer les pinceaux, supprimez les enfants des composants Grid anonymes situs au sein des grilles respectivement nommes RadioMusic, RadioImage, RadioVideo. Via le mode ddition XAML transformez la grille en Rectangle. Cette tche est assez aise: il vous suffit de supprimer les proprits non supportes par le Rectangle. Voici le code XAML avant le changement envisag:
<Grid x:Name="RadioVideo" Height="53" HorizontalAlignment="Left" Margin="166,1,0,0" VerticalAlignment="Top" Width="49"> <TextBlock FontFamily="Tahoma" FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,-2" RenderTransformOrigin="0.5,0.5"><Run Text="Video" Foreground="#FFFFFFFF"/></TextBlock> <Grid HorizontalAlignment="Center" VerticalAlignment="Center" Width="28" Height="32" Margin="0,0,0,4"> <Path /> <Path > <Path.Fill> <LinearGradientBrush StartPoint="0.497509,0.0614041" EndPoint="0.497509,0.929826"> <GradientStop Color="#00FFFFFF" Offset="0"/> <GradientStop Color="#BFFFFFFF" Offset="1"/> </LinearGradientBrush> </Path.Fill> </Path> </Grid> </Grid>

Voici le code XAML aprs modification:


<Grid x:Name="RadioVideo" Height="53" HorizontalAlignment="Left" Margin="166,1,0,0" VerticalAlignment="Top" Width="49"> <TextBlock FontFamily="Tahoma" FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,-2" RenderTransformOrigin="0.5,0.5"><Run Text="Video" Foreground="#FFFFFFFF"/></TextBlock> <Rectangle HorizontalAlignment="Center" VerticalAlignment="Center" Width="48" Height="32" Margin="0,0,0,4" Fill="{StaticResource IconVideo}"/> </Grid>

Vous constatez que ce code est beaucoup plus sobre et surtout trs efficace en terme de flux de production. Un graphiste naura qu mettre jour les icnes via nimporte quel outil externe, tel

Chapitre 11

Ressources graphiques

339

que Photoshop. Il naura pas besoin de connatre Expression Blend pour mettre jour lapplication, il lui suffira simplement de recompiler pour prendre en compte les icnes modifies. Lune des pratiques dans ce domaine consiste ne pas importer directement les ressources de type mdia dans le projet Silverlight, mais plutt crer un lien pointant sur elles. Vous pouvez accder cette option via un simple clic-droit au sein du panneau Projects en slectionnant loption Link To Existing Item (voir Figure11.21).
Figure11.21
Ajouter une liaison pointant vers un fichier externe au projet.

Cette mthodologie est encore plus transparente pour le designer, mais donnera moins de souplesse car elle force ne pas dplacer ou rorganiser les ressources mdias lies trop souvent un projet.
NOTE INFO

Il est galement possible de crer un pinceau dimage en dur sans le dfinir comme ressource. Dans cette optique, il vous faudra utiliser le quatrime onglet, nomm Tile Brush au survol, situ au sein du panneau Brushes, puis choisir le mdia que vous souhaitez utiliser en tant que remplissage. Toutefois cette mthodologie est anecdotique et ne devrait pas tre privilgie.

Du ct C#, appliquer un pinceau dimage est trs facile, car le dveloppeur peut tout moment cibler la ressource cre par le graphiste. Ainsi au lieu davoir un code verbeux du type:
//1 - on cre un objet Uri qui pointe vers notre fichier image utiliser Uri adresseImage = new Uri("video.png",UriKind.Relative); //2 - on cre un objet de type BitmapImage en lui spcifiant //ladresse relative que nous venons de dfinir BitmapImage bi = new BitmapImage( adresseImage ); //3 - On cre un pinceau dimage ImageBrush ib = new ImageBrush(); //4 on spcifie limage source de ce pinceau ib.ImageSource = bi; //5 on affecte la proprit Fill dune instance de Shape monRectangle.Fill = ib;

On obtient quelque chose de beaucoup plus simple du point de vue dveloppement, mais galement dans la rpartition des tches de chaque ple mtier. Le dveloppeur na pas besoin de

340

Partie III

Conception dapplications riches

connatre lemplacement ou le nom de limage afficher. Il lui suffit de connatre le nom de la ressource. cette fin, le mieux est encore de se baser sur une nomenclature dfinie ds le dpart du projet en concertation avec lensemble des acteurs de la production:
//on rcupre la ressource quon transtype en ImageBrush ImageBrush ib = (ImageBrush)App.Current.Resources["IconVideo"]; //Dans ce cas, on applique le pinceau dimage la proprit Fill //dune instance de Shape monRectangle.Fill = ib;

la section11.3, nous dcouvrirons en quoi les pinceaux permettent en gnral dviter la prolifration excessive de styles et modles de composant.

11.3 Les polices de caractres


Contrairement aux technologies habituelles du Web reposant sur la mise en forme XHTML, Silverlight offre de nombreux avantages en matire de conception graphique. Lun deux est de pouvoir afficher des polices de caractres personnalises et de permettre des mises en forme assez avances. Laffichage tant gr par un moteur vectoriel, certaines bonnes pratiques de conception doivent tre connues pour bnficier dun affichage propre et performant.

11.3.1 Afficher et mettre en forme du texte


Au sein de Silverlight, deux mcanismes de mise en forme de texte cohabitent. Celui qui est le plus couramment utilis repose sur les composants TextBlock, TextBox et sa sous-classe Password Box. Tous ces contrles sont directement hrits de FrameworkElement. Ils nont donc pas de proprit Template permettant de modifier leur modle. Autrement dit, leur affichage est uniquement dtermin par le texte quils contiennent. Le composant TextBlock a pour unique but dafficher du texte non interactif. Il est trs simple dutilisation et possde des options de mise en forme assez similaires ce que vous trouverez dans nimporte quel diteur de texte. Les contrles TextBox et PasswordBox sont des champs de saisie utilisateur nayant pas pour objectif de proposer doptions de mises en forme avances. Le deuxime mcanisme de mise en forme consiste utiliser la classe Glyphs qui fournit une API bas niveau de formatage de texte. Celle-ci est rellement utile lorsque vous avez besoin dun contrle total et dynamique sur le texte affich dans Silverlight. Voici un exemple XAML simple de lcriture dune instance de Glyphs:
<Glyphs Height="100" Width="100" Fill="Red" FontRenderingEmSize="12" FontUri="Fonts/tahoma.ttf" UnicodeString="Hey" OriginX="10" OriginY="20" Indices=",85;,64;,67;6"/>

Nous nallons pas nous tendre sur lAPI bas niveau car cela sortirait du cadre de ce livre. Nous apprendrons donc utiliser le composant TextBlock qui rpond 80 % des cas dutilisation. Grce ce dernier, nous pouvons appliquer une mise en forme gnrale via ses proprits, qui sont accessibles dans la section Text du panneau Properties (voir Figure11.22).

Chapitre 11

Ressources graphiques

341

Figure11.22
Les proprits de mise en forme du composant TextBlock.

Voici une liste non exhaustive des proprits que vous pouvez configurer:

Le choix de la police de caractres (Arial, Verdana, Calibri, etc.). En pratique, lorsque vous choisissez une police diffrente de celle propose par dfaut, il vous faudra lembarquer dans90% des cas. Nous abordons plus en dtail lintgration de polices la section11.3.2. La taille de police exprime en pixels ou en points selon la configuration de linterface de Blend. Pour choisir lune de ces deux units, ouvrez le menu Tools> Options et dans longlet Units, choisissez Points ou Pixels. Notez que dans tous les cas, le XAML est format en tenant compte de valeurs exprimes en pixels. Afficher le texte en gras, italique ou soulign est ralis grce aux proprits respectives FontStyle, FontWeight et TextDecoration. Pour avoir un vrai gras, il faudra utiliser une police correspondante, dans le cas contraire il est simul. Cest exactement le mme principe avec litalique. Il est galement possible de modifier lespacement entre les caractres (linterlettrage) en utilisant la proprit FontStretch. La police nest toutefois pas modifie dynamiquement. Lorsque vous lutilisez, cette proprit fait rfrence une police correspondant lespacement spcifi (Condensed par exemple). Lorsque cette police nest pas disponible, modifier la valeur de cette proprit ne change rien et ne renvoie aucune erreur ou alerte. Vous pouvez aligner le texte droite, gauche ou au centre, via la proprit TextAlignment qui accepte une valeur de lnumration du mme nom. Malheureusement, il nest pas possible de justifier le texte car la valeur TextAlignment.Justify nexiste que dans WPF. Le retour la ligne automatique est gre grce la proprit TextWrapping et lnumration correspondante contenant les valeurs Wrap et NoWrap. Dfinir cette proprit NoWrap empchera tout retour la ligne automatique. Cela est visible lorsque la largeur du champ texte est dfinie en pixels et non en mode automatique. A contrario, si la proprit Text Wrapping est affecte de la valeur Wrap, que vous fixez la largeur du TextBlock en dur et que la hauteur est dfinie en mode Auto, alors le texte contenu ira automatiquement la ligne. La hauteur du champ sadaptera dynamiquement la quantit de texte afficher. Pour finir, il est possible de spcifier une hauteur de ligne via la proprit LineHeight.

Toutes ces capacits sont assez utiles, mais elles demeurent insuffisantes en ltat car elles sont propres TextBlock. A priori, cela nous oblige avoir autant de TextBlock que de mises en

342

Partie III

Conception dapplications riches

forme. Fort heureusement, les TextBlock ont la capacit de possder des lments enfants mis en forme et qui sont des instances de la classe Inline. Ainsi, TextBlock possde la proprit Inlines qui nest rien dautre quune collection dinstances de type Inline. La classe Inline est abstraite, elle sert de base deux classes concrtes en hritant: Run et LineBreak. Les instances de type Run possdent presque toutes les capacits dun TextBlock. Grce ces dernires, vous pouvez appliquer des mises en forme diffrentes au sein dun mme champ TextBlock. Ces balises sont gnres dans Blend lorsque vous double-cliquez dans un TextBlock, que vous slectionnez une portion spcifique du texte contenu, puis que vous dfinissez les options de mise en forme. Il est galement possible de le faire via le panneau des proprits en cliquant sur la proprit Inlines et en ajoutant chaque portion de texte manuellement. Les instances de LineBreak permettent, quant elles, de faire des retour la ligne. Voici le code XAML dun exemple de texte mis en forme (voir Figure11.23) via lutilisation de ces balises dans Blend:
<TextBlock Margin="70,87,192,86" TextWrapping="Wrap"> <Run FontFamily="Calibri" FontSize="16" FontWeight="Bold" Text="3DLightEngine Library preview"/> <LineBreak/><Run FontStyle="Italic" Foreground="Gray" Text=" Fri, Sep4th,2009"/> <LineBreak/><Run Foreground="BlueViolet" Text=" Posted by Eric Ambrosi01:09 PM"/> <LineBreak/><LineBreak/><Run FontWeight="Bold" TextDecorations="Underline" Text="us version"/> <LineBreak/><LineBreak/><Run FontFamily="Calibri" Text="Je mettrai bientt disposition une librairie ..."/> </TextBlock>

Figure11.23
Un TextBlock contenant plusieurs mises en forme.

Cette criture est simplifie, vous pourriez tout aussi bien affecter la proprit Inlines en XAML de cette manire:
<TextBlock Margin="70,87,192,86" TextWrapping="Wrap"> </TextBlock.Inlines> <Run FontFamily="Calibri" FontSize="16" FontWeight="Bold" Text="3DLightEngine Library preview"/> <LineBreak/><Run FontStyle="Italic" Foreground="Gray" Text="Fri, Sep4th,2009"/> <LineBreak/><Run Foreground="BlueViolet" Text=" Posted by Eric Ambrosi01:09 PM"/> <LineBreak/><LineBreak/><Run FontWeight="Bold" TextDecorations="Underline" Text="us version"/> <LineBreak/><LineBreak/><Run FontFamily="Calibri" Text="Je mettrai bientt disposition une librairie ..."/>

Chapitre 11

Ressources graphiques

343

</TextBlock.Inlines> </TextBlock>

NOTE INFO

Comme vous le constatez, deux proprits assez utiles ne sont pas fournies par la classe Run. La premire, LineHeight, concerne la hauteur des lignes, la seconde nomme TextAlignment, gre lalignement horizontal du texte. Ainsi le texte contenu dans un TextBlock aura en commun ces deux proprits que le texte soit, ou non, dcrit dans des balises Run. Il ny a pas vraiment de solution lgante cette problmatique. Lidal pour des mises en forme plus abouties est demployer la classe Glyphs, mais elle est moins facile utiliser au quotidien car dassez bas niveau.

Obtenir une mise en forme quivalente en C# est relativement simple. Il suffit de crer des instances de type Inline puis de les ajouter la collection Inlines qui est une proprit de Text Block:
Run r1 = new Run(); r1.FontFamily = new FontFamily("Calibri"); r1.FontSize =13; r1.FontWeight = FontWeights.Bold; r1.Text = "Ce texte est format via une balise Run hritant de la classe abstraite Inline."; Run r2 = new Run(); r2.FontFamily = new FontFamily("Consolas"); r2.Foreground = new SolidColorBrush(Colors.Orange); r2.FontSize =16; r2.FontWeight = FontWeights.Bold; r2.Text = "Ceci est une autre balise run avec une mise en forme diffrente."; //on ajoute la premire balise Run MiseEnFormeDynamique.Inlines.Add(r1); //on va la ligne en ajoutant une instance de LineBreak MiseEnFormeDynamique.Inlines.Add(new LineBreak()); //on ajoute une seconde balise Run MiseEnFormeDynamique.Inlines.Add(r2);

Vous trouverez dans le dossier chap11 la solution contenant ces exemples: MiseEnForme.zip. Le rsultat de cet exercice est visible la Figure11.24.
Figure11.24
Rsultat visuel de lexercice de mise en forme.

344

Partie III

Conception dapplications riches

11.3.2 Polices personnalises


Les polices de caractres occupent une position centrale dans la charte graphique et dfinissent en partie lidentit visuelle dune entreprise. Il est donc important de comprendre comment intgrer ces dernires de manire efficace.

11.3.2.1 Les polices par dfaut


Le lecteur Silverlight contient nativement un certain nombre de polices de caractres. Pour les identifier, rfrez-vous la liste des polices accessibles par dfaut au sein de tout composant TextBlock. Lorsque vous les utilisez, il nest pas ncessaire de les embarquer puisquelles le sont dj. Les polices intgres par dfaut possdent licne Silverlight droite de leur nom (voir Figure11.25).
Figure11.25
Les polices embarques par dfaut affichant le logo Silverlight.

Parmi celles qui sont intgres, on distingue Portable User Interface. Celle-ci nen est pas vraiment une proprement parler. Dans les faits, elle est constitue dun agglomrat de plusieurs polices de caractres. Pour les cultures occidentales, elle affiche lquivalent de la police Lucida Sans Unicode ou Lucida Grande. Elle permet en outre de supporter laffichage de texte pour dautres cultures travers le monde. Ainsi sur un systme dexploitation chinois ou russe, elle apparatra de manire diffrente. Toutes les autres polices intgres par dfaut engendreront un rendu identique quelle que soit la culture du systme dexploitation client. Il est peu frquent quune entreprise, une association ou une marque utilise lune de ces polices car elles sont trop standard et passepartout. Les cratifs choisissent souvent des polices moins connues permettant ainsi lutilisateur didentifier plus facilement une marque ou un produit.
NOTE INFO

Produire souvent du contenu visuel pour diffrentes marques, produits ou entreprises, a pour consquence dinstaller de nombreuses polices sur le systme dexploitation du concepteur ou des cratifs. Certaines des polices installes ne seront utiles que15 jours ou moins. Dans cette optique, le mieux est toujours dutiliser des gestionnaires de polices permettant de les activer ou de les dsactiver volont. De cette manire, vous viterez de polluer votre poste et vous pourrez mme organiser ces dernires de manire plus lgante que ne le fait le rpertoire Fonts. Le logiciel SuitCase de la socit Extensis est lexemple type dun gestionnaire de polices. Vous le trouverez ladresse: http://www.extensis.com/fr/products/suitcasefusion2/.

Chapitre 11

Ressources graphiques

345

11.3.2.2 Embarquer les polices


Vous avez sans doute remarqu les multiples messages dalerte dans le panneau Results. Ils indiquent que vous utilisez des polices qui ne sont pas embarques par dfaut dans le lecteur Silverlight (voir Figure11.26).
Figure11.26
Messages dalerte indiquant que des polices utilises ne sont pas embarques.

Si vous codez directement en XAML dans Expression Blend, la proprit FontFamily est souligne afin de vous alerter. Lorsque vous compilez, les polices ne sont pas affiches au sein de lapplication dans le navigateur. Plusieurs choix soffrent vous pour rsoudre cette problmatique:

Vous pouvez utiliser lune des polices intgres par dfaut. Dun point de vue exprience utilisateur, ce nest pas un trs bon choix. Il offre toutefois lavantage de ne pas augmenter le poids final du fichier compil. Il est galement possible de vectoriser un composant TextBlock. Cette solution est viable pour un nombre limit de champs texte utilisant une police spcifique. Cela nest valable que si ces derniers nont pas besoin dtre mis jour dynamiquement ou frquemment dans Blend. De cette manire, vous en faites des lments graphiques servant de dcors. Cette approche est dsavantageuse en termes de maintenance puisque vous ne pourrez plus changer leur contenu. Il faut toutefois la prendre en considration car cette mthode vous permet galement de profiter des avantages propres aux tracs vectoriels en matire de design. La troisime faon consiste embarquer manuellement la police. Cette opration peut tre ralise sous Visual Studio ou Blend, mais, le plus souvent, cest le designer interactif qui sen occupe puisquil joue le rle dintgrateur. De cette manire, la police sera compile au sein du fichier xap et accessible par les composants qui y feront rfrence. Une autre manire de procder consiste tlcharger dynamiquement une police de caractres prsente sur le serveur web. Nous tudierons cette voie la section11.5. La dernire solution, prsente depuis Silverlight3, consiste utiliser des polices systme. Il existe deux principes diffrents dans ce cas. Le premier consiste faire rfrence la police dans le XAML ou en C#, en affectant directement la proprit FontFamily. Dans ce cas, le nombre de polices systme accessibles est limit: Calibri, Consolas, Constantia, etc. (voir la documentation pour une liste complte). La deuxime possibilit est de charger dynamiquement nimporte quelle police du systme dexploitation. Toutefois, cette mthode nest possible quen JavaScript et non via le code manag C# ou VB. De plus, il est ncessaire dutiliser des mcanismes de mise en forme de texte de bas niveau reposant sur la classe Glyphs. Cette solution peut tre avantageuse mais ncessite beaucoup plus defforts. Dans tous les cas, si la police cible nest pas sur le systme client, elle sera remplace par la police Portable User Interface dans le premier cas. Dans le second cas, le texte ne sera pas affich. Ces solutions ne sont donc viables que dans des environnements matriss, dans un intranet dentreprise par exemple.

346

Partie III

Conception dapplications riches

Pour notre part, nous allons embarquer les polices au sein du fichier xap via Expression Blend, puis nous aborderons les options offertes par ce dernier. Dans le projet actuel, nous devons intgrer deux polices. La premire, Showcard Gothic, est utilise pour le logotype du lecteur multimdia. La seconde est Tahoma, qui concerne95% du texte affich dans lapplication.
NOTE INFO

La police Tahoma fait partie de la liste des polices que Silverlight peut charger dynamiquement lorsquelles sont installes sur le poste client. Pour cette dernire, nous pourrions donc dcider de nous reposer sur ce mcanisme et viter de lembarquer. Dans le cas o elle ne serait pas prsente sur le systme client, la police "Portable User Interface" la remplacerait. Ce choix de conception est votre discrtion. Tout dpendra de vos objectifs et contraintes de production, mais galement du type denvironnement et dutilisateur que vous ciblez. Limpact peut tre dsastreux si la typographie initialement prvue est trs diffrente de la police PortableUserInterface: taille, emptement, interlettrage, les caractristiques typographiques sont autant de paramtres qui diffrent dune police lautre. Le visuel global de votre application peut en tre trs fortement affect.

Dans le menu Tools, choisissez le menu Font Manager Une bote de dialogue souvre, cest en fait un gestionnaire de polices propre la solution Silverlight (voir Figure11.27).
Figure11.27
Le gestionnaire de polices.

travers ce gestionnaire, vous avez la capacit dembarquer une ou plusieurs polices ainsi que de lister les caractres intgrer pour chacune dentre elles. Nous allons aborder plusieurs points de vue diffrents, lobjectif final tant doptimiser au maximum le poids du fichier compil tout en gardant le visuel intact. Lune des manires daborder cette problmatique est illustre par lintgration de la police Showcard Gothic. Trouvez cette dernire en tapant les premires lettres de son nom dans le champ de recherche. Cliquez sur la case cocher ct de la police. Vous avez le choix entre embarquer la police dans sa totalit ou seulement une partie des caractres dont vous avez besoin. Comme les champs Text lutilisant sont des lments purement graphiques, il nest pas ncessaire de tout embarquer. Dcochez loption All glyphs. Seule loption de remplissage automatique Auto fill reste coche. Cette proprit est trs utile car elle permet de nembarquer que les caractres dont la prsence est dtecte la compilation. La diffrence entre les deux options est flagrante. Le poids du fichier xap est infrieur de40Ko dans le second cas, cela nest pas ngligeable sur Internet. Le remplissage automatique est une bonne option de ce point de vue. Vous ne pourrez toutefois pas

Chapitre 11

Ressources graphiques

347

crer de textes affects de cette police, lexcution, car vous prendriez le risque de ne pas pouvoir afficher certains caractres non embarqus la compilation.
NOTE INFO

Lorsque vous avez embarqu la police, vous avez sans doute remarqu une trs lgre pause de fonctionnement. Celle-ci est due au fait que Blend a ajout la police directement au sein du projet dans un rpertoire Fonts spcialement cr cet effet. Ce principe est trs avantageux, il vous permet de partager le projet sans risque derreurs la compilation. La personne qui vous donnerez le projet naura pas besoin dinstaller la police sur le systme puisque celle-ci fait partie du projet.

Ouvrez nouveau le gestionnaire de polices si ce nest pas fait. Cherchez la police Tahoma, vous devez maintenant vous poser une question. Devez-vous tout embarquer ou seulement certains caractres? Pour rpondre cette question, vous devez rpondre plusieurs autres:

Quelle est la zone internationale cible par votre application ? Par exemple, celle-ci est-elle faite pour le continent nord amricain, lEurope, les pays nordistes ou lensemble de ces contres? Si vous connaissez la rponse, vous savez quels caractres doivent tre embarqus en cas de saisie utilisateur dans lapplication. Vous pourrez ainsi prvoir les caractres auquel linternaute aura accs pour remplir un formulaire par exemple. Sil ny a pas de saisie utilisateur prvue, dans quelles langue(s) ou culture(s) les champs textes dynamiques sont-ils susceptibles dtre mis jour?

Nous allons essayer de fournir la rponse la mieux adapte. Laissez coch All glyphs, puis compilez le projet. Dans le rpertoire Debug, vous pouvez constater que le poids du fichier est denviron780 Ko, nous avons environ400 Ko de police embarque en trop. Cela est normal car la police Tahoma est trs complte et supporte de nombreux caractres diffrents, intgrer tous ses caractres est une erreur doptimisation. Nous navons besoin que dune fraction de ceux-ci. Partant du principe que notre application ne ciblera que les cultures occidentales, autant intgrer uniquement ceux que nous sommes susceptibles dafficher. Voici une liste de caractres que je garde sous la main et que jincrmente au besoin au fur et mesure des projets que je ralise:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ .,;:!?"&~#{}()-_`\/@[]=+-*%|0123456789$

Attention bien ajouter lespace normal car cest un caractre part entire. Vous pouvez vous inspirez de cette liste ou crer la vtre. Dans le gestionnaire de polices, dcocher loption All Glyphs, laissez loption Auto fill slectionne, mais ajoutez la liste des caractres ci-dessus dans le champ en bas nomm Include glyphs. Cliquez sur OK. Une fois encore la police a t ajoute au rpertoire Fonts (voir Figure11.28). Recompilez lapplication. Le fichier xap fait dsormais380 Ko, ce qui est beaucoup mieux. Le gain est denviron400 Ko ce qui est vraiment apprciable en terme de tlchargement. Lutilisateur passera moins de temps attendre laffichage de votre application. Vous remarquez quaucune alerte nest dsormais visible dans le panneau Results. Vous pouvez tlcharger le projet LecteurMultiMedia_BF.zip contenant les diffrents pinceaux ainsi que lintgration des polices.

348

Partie III

Conception dapplications riches

Figure11.28
Les polices importes dans le projet facilitent son partage.

11.4 Styles et modles de composants


Les styles et les modles sont des ressources avances et reprsentent le fer de lance du principe de rutilisation mis en exergue par Silverlight et WPF. Ils ont pour objectif damliorer le flux de production en facilitant la rutilisation du jeu de composants fourni sur les plateformes Silverlight et WPF. La cration de composants visuels personnaliss via lhritage, bien que possible, nest plus autant ncessaire quavec la bibliothque Winforms grce aux notions de styles et de modles de contrles introduits avec .Net3. Dans les prochaines sections, nous concevrons des composants personnaliss travers les exemples du Slider et de la ListBox. Ce faisant, nous apprendrons les bonnes pratiques et approfondirons nos connaissances des mthodologies de production. Comme bon nombre denvironnements de dveloppement, la grande majorit des interactions et des fonctionnalits est apporte par le jeu de composants propos par dfaut ou par des bibliothques comme Silverlight Toolkit. Chaque composant possde un rle propre et dlimit, ce qui lui permet dtre souvent rutilis au sein de plusieurs applications. Afin dapporter un maximum de souplesse de conception, la fonctionnalit et linteractivit supportes par un contrle (Slider par exemple) ne sont pas coupls fortement au design ou au style visuel de ce dernier. Rutiliser des composants existants sera toujours plus productif que les crer par vous-mme. Grce aux styles et modles, vous pourrez conserver les fonctionnalits des contrles tout en modifiant compltement leur aspect visuel.

11.4.1 Les styles


Un style est un groupe de proprits dfinies que lon peut affecter nimporte quel objet de type FrameworkElement. Ainsi, un objet de type Shape, Panel ou Control a la capacit de possder un style. Toutes ces classes possdent la proprit Style hrite de FrameworkElement, cette proprit recevra une instance de la classe Style. Voici lcriture XAML dun style ciblant la classe Rectangle:
<Style x:Key="RectangleStyle" TargetType="Rectangle"> <Setter Property="Width" Value="150" /> <Setter Property="Height" Value="100" /> <Setter Property="Fill" Value="Red" /> </Style>

Chapitre 11

Ressources graphiques

349

Comme vous le remarquez, un style ncessite plusieurs attributs pour fonctionner. Le premier est le nom de la cl de ressource, le second dfinit le type de lobjet qui pourra recevoir le style. La balise Style doit elle-mme contenir des balises enfants de type Setter qui permettront de cibler une proprit et dy associer une valeur. Voici laffectation en XAML du style dfini plus haut:
<Grid x:Name="LayoutRoot" Background="White"> <Rectangle Style="{StaticResource RectangleStyle}" /> </Grid

Lorsque vous appliquez un style un objet, les valeurs par dfaut des proprits de ce dernier sont automatiquement crases par celles contenues dans le style. Les attributs dobjet dfinis en brut dans la dclaration XAML ou C# de lobjet seront toutefois prioritaires celles dfinies par le style. Vous pourriez par exemple dcider quun style propre aux composants Rectangle affecte leur largeur (Width) de200 pixels. Toutefois la compilation, si un Rectangle affect du style possde dj sa proprit Width dfinie 300, alors celle-ci outrepassera celle du style:
<Grid x:Name="LayoutRoot" Background="White"> <!-- la proprit Width dfinie dans le rectangle crase celle rcupre par le style --> <Rectangle Style="{StaticResource RectangleStyle}" Width="300" /> <!-- la proprit Width dfinie dans le style dfinit la largeur par dfaut du Rectangle --> <Rectangle Style="{StaticResource RectangleStyle}" /> </Grid>

Crer un style en C# est une tche simple, mais apporte en gnral moins dintrt. Crer un style dans Expression Blend et le stocker au sein dun dictionnaire de ressources a plus de sens car ce dernier reste accessible au designer qui peut le modifier directement de manire sensible via linter face de Blend. Voici toutefois un exemple de style gnr et appliqu en C#:
//on cre un nouveau style Style s = new Style( typeof(Ellipse) ); //on cre une instance de Setter //Le premier paramtre indique la proprit cible de lobjet //Le second paramtre dfinit la valeur de la proprit cible Setter setter = new Setter(Ellipse.FillProperty, new SolidColorBrush (Colors.Blue)); //on ajoute un lment de type Setter la collection Setters s.Setters.Add(setter); //il nest pas obligatoire dajouter le style au dictionnaire //de ressources via la ligne ci-dessous //Resources.Add("EllipseStyle", s); //on affecte le style gnr la proprit Style monEllipse.Style = s; //monEllipse.Style = Resources["EllipseStyle"] as Style;

Depuis Silverlight3, il est possible de baser des styles partir dautres dj existant. cette fin vous pouvez utiliser la proprit BasedOn. Elle vous permet de cibler le style hrit. Voici un exemple simple illustrant cette mthode:
<UserControl.Resources> <Style x:Key="RectangleStyle" TargetType="Rectangle">

350

Partie III

Conception dapplications riches

<Setter Property="Width" Value="150" /> <Setter Property="Height" Value="100" /> <Setter Property="Fill" Value="Red" /> </Style> <Style x:Key="RoundSquareStyle" BasedOn="{StaticResource RectangleStyle}" TargetType="Rectangle"> <Setter Property="Width" Value="100" /> <Setter Property="RadiusX" Value="10" /> <Setter Property="RadiusY" Value="10" /> </Style> </UserControl.Resources>

Cela est ralisable uniquement ct XAML. Ce type dcriture permet dviter de recopier un code fastidieux ou de dupliquer des styles entiers lorsque vous souhaitez les dcliner. Il est possible dajouter ou dcraser des balises Setter.

11.4.2 Affectation dynamique


Dans lidal, le style est cr dans linterface de Blend, mais il peut tre affect dynamiquement, via C# ou VB, plusieurs instances de FrameworkElement la fois. De cette manire, vous profitez du meilleur des deux mondes, le graphisme et le ressenti utilisateur apports par les cratifs, coupls la fonctionnalit et lautomatisation des tches fournies par le dveloppeur. Nous allons le dmontrer en crant un style via linterface de Blend du point de vue dun designer interactif, puis nous affecterons dynamiquement ce style des objets de la liste daffichage. Dans un projet de votre choix, crez un StackPanel centr horizontalement et align vers le haut. Instanciez dans ce conteneur cinq exemplaires de Button et affectez leur proprit Content des valeurs respectives: Accueil, Innovation, Technologie, Services, Portfolio. Slectionnez le premier et dans le menu Object, slectionnez Edit Style > Create Empty Dans la fentre qui apparat, nommez le style et stockez-le dans un dictionnaire de ressources externe. Linterface de Blend vous place en mode ddition de style. Passez en mode de cration mixte afin de voir le code XAML gnr par vos actions sur le panneau Proprits. Lide est de personnaliser entirement les proprits du bouton, voici un exemple de style gnr:
<Style x:Key="ButtonStyle1" TargetType="Button"> <Setter Property="Background"> <Setter.Value> <SolidColorBrush Color="#FF550024"/> </Setter.Value> </Setter> <Setter Property="BorderThickness" Value="0,0,2,2"/> <Setter Property="BorderBrush" Value="#FF743A3A"/> <Setter Property="Foreground" Value="#FF8E4C4C"/> <Setter Property="FontFamily" Value="Courier New"/> <Setter Property="FontSize" Value="18"/> <Setter Property="Cursor" Value="Hand"/> </Style>

Du ct dveloppeur, il suffit de lister tous les objets contenus dans le StackPanel, puis daffecter le style dynamiquement chacun deux mis part au premier qui le possde dj. Au sein de Blend, slectionnez la grille LayoutRoot, puis dans le panneau des vnements, dans le champ MouseLeftButtonUp, entrez ApplyStyle comme nom de mthode. Selon les paramtres de longlet Projects du menu Options cette action ouvre le fichier MainPage.xaml.cs dans Blend ou

Chapitre 11

Ressources graphiques

351

directement dans Visual Studio. Voici la mthode qui permet daffecter le style cr par le designer dans Blend, chaque bouton du StackPanel de manire dynamique:
private void ApplyStyle(object sender, MouseButtonEventArgs e) { foreach (UIElement uie in MenuHaut.Children) { Button b = uie as Button; if (b!= null && b.Content!= "Accueil") { b.Style = App.Current.Resources["ButtonStyle1"] as Style; } } }

Testez le projet. Lorsque vous relchez le bouton gauche de la souris nimporte o sur la grille LayoutRoot, le style est dynamiquement affect chaque instance de bouton prsent dans le StackPanel. Concrtement, chacun des acteurs de la production joue son rle sans influer ou interfrer dans le travail des autres. Le projet StyleAndTemplate_Base.zip est disponible dans le dossier chap11 des exemples du livre.

11.4.3 Organiser et nommer les ressources


Le code XAML ci-dessus est montr titre indicatif, le designer na pas forcment besoin de savoir ce qui a t gnr par la personnalisation des proprits du bouton. Toutefois, comme nous lavons prcis, pour que le dveloppeur et le designer interactif puissent collaborer, il est au moins ncessaire de saccorder sur une nomenclature des cls de ressource. Revenons un peu en arrire afin de mieux comprendre comment nommer et organiser nos dictionnaires de ressources, nous pourrons alors envisager une nomenclature des ressources. La Figure11.4 dcrit les capacits dorganisation des dictionnaires de ressources dun point de vue technique. Ce point de vue est important mais naborde pas les bonnes pratiques de dcoupage des ressources. Plusieurs facteurs importants se rvlent dcisifs lorsque vous souhaitez organiser vos ressources de manire optimise:

Vous pouvez tout dabord grer vos dictionnaires de ressources en les nommant selon les thmes visuels quils traitent. Par exemple, SketchStyles.xaml contenu dans les projets SketchFlow, est un dictionnaire de ressources ddi au style visuel croquis. Ainsi, nous pourrions crer un autre dictionnaire de ressources nomm GlossyStyles.xaml ou Seventies Styles.xaml. Il est galement possible de nommer les dictionnaires et de centraliser les ressources en fonction des fonctionnalits quils couvrent. Par exemple, si votre application possde un lecteur multimdia, vous pouvez fdrer les ressources dans un dictionnaire ddi au lecteur. Si vous travaillez pour des clients diffrents et que vous souhaitez industrialiser le dveloppement, il est peut-tre utile davoir des dictionnaires ddis chacun deux (Banque1 Brush. xaml et Banque2Brush.xaml). Ce modle dorganisation est assez intressant car il vous permet de simplifier en factorisant laffectation de dictionnaires. Les contraintes techniques propres aux ressources influent grandement sur les possibilits dorganisation. Par exemple, un Storyboard est une ressource mais il cible une instance de UIElement au sein dun arbre visuel. Il ne sera donc pas possible de lexternaliser dans un

352

Partie III

Conception dapplications riches

dictionnaire puisque la rfrence de linstance anime nexiste pas dans le dictionnaire. Les pinceaux dimages (ImageBrush) suivent un peu la mme logique dans le sens o les partager entre diffrents projets passera forcment par limportation des images quils ciblent. On peut donc se demander sil est lgitime de centraliser les pinceaux dimages (et de vidos) dans des dictionnaires externes. La rponse est oui dans la mesure o organiser les ressources dans des dictionnaires facilite la maintenance, la lecture du XAML ainsi que lvolutivit des applications. Toutefois, comme leur logique de partage est contraignante, il faudra viter de les insrer dans des dictionnaires de ressources contenant des pinceaux dont le visuel est uniquement dpendant du code dclaratif XAML (et non dune quelconque ressource de type mdia).

Dans le mme ordre dide, le type des ressources que vous organisez est prendre en compte. Vous pouvez dcider de scinder les diffrents types de ressources dans autant de dictionnaires externes. Les pinceaux dans un dictionnaire, les ressources de couleurs dans un autre, les styles et les modles encore dans un autre. Lavantage de procder ainsi est de conserver une organisation propre et facile maintenir. Changer les couleurs propres la charte graphique reviendra modifier les ressources de couleurs contenues dans le dictionnaire adquat. Comme le code XAML est relativement simple pour ce type de ressource, il est facile pour un graphiste ou un designer de changer les valeurs des couleurs sans altrer larchitecture ou le travail de conception dj ralis. Si vous mlangez les styles, les pinceaux et les couleurs, cela complexifiera leur accs et diminuera leur visibilit au sein du projet.

La Figure11.29 met en avant une organisation structure tenant compte de certaines de ces pistes de rflexion.
Figure11.29
Organisation des dictionnaires de ressources par client, type de ressource et fonctionnalit.
ProjetClient1.xaml MainPage.xaml UserControl.Resources Contient des ressources de type Storybard Page2.xaml Contient des ressources de type Storybard Module autonome Player.xaml Contient des ressources de type storybard. Possde un accs unique aux ressources de PlayerStylesTemplates.xaml Client1ImgVideoBrush.xaml Pinceaux d'images et de vidos Rfrencement de fichiers multimdias image1.jpg

App.xaml Liaisons vers diffrents dictionnaires de ressources

Client1Color.xaml Ressources de couleurs

video1.wmv

Liaison de dictionnaire

video2.jwmv

Client1StylesTemplates.xaml Styles et modles PlayerStylesTemplates.xaml Styles et modles

Client1Brushes.xaml Pinceaux de couleurs unies et dgrades

Hritage naturel selon la porte de stockage Liaison de dictionnaires de ressources Rfrencement de fichiers multimdias

Page de l'application

Dictionnaire de ressource

Ressource physique multimdia

Chapitre 11

Ressources graphiques

353

Les concepts dcrits ci-dessus influencent non seulement lorganisation des ressources, mais nous apportent galement des indices concernant la conception dune nomenclature. Par exemple, si vous deviez crer un style ayant pour thme visuel un effet vitr conu pour les boutons de soumission, vous pourriez le nommer SubmitGlassyButtonStyle. De cette manire, vous saurez en lisant ce nom que cette ressource est un style avec un rendu "verre" pour les boutons de soumission de formulaire. Le dveloppeur voit son travail facilit et na pas forcment besoin de sentretenir avec le designer sil doit lappliquer dynamiquement.

11.4.4 Les modles


Les modles de composants sont souvent apparents la notion de style. Ils sont reprsents par la classe ControlTemplate dont les instances peuvent tre affectes la proprit Template de tout objet hritant de Control. Ils permettent de remplacer larbre visuel et logique dfinit au sein des objets hritant de la classe Control. Par exemple, larbre visuel et logique dune barre de dfilement (ScrollBar) est entirement modifiable si vous affectez sa proprit Template une instance de ControlTemplate. premire vue, il peut vous sembler que les modles sont une version plus puissante des styles que nous venons dvoquer puisque la forme mme des composants peut tre rinvente. En ralit, les instances de Style et de ControlTemplate nagissent pas aux mmes niveaux. Leurs objectifs sont complmentaires, un modle est toujours affect la proprit Template dun Control. Par ailleurs, comme les styles sont des groupes de proprits dfinies, un style peut contenir une balise Setter dont le rle sera dappliquer une instance de ControlTemplate la proprit Template dun Control. Si crer un modle est relativement simple du ct XAML, il est peu pertinent de procder de cette manire. Que vous soyez dveloppeur ou non, et mme si cela est ralisable avec du temps et du caf, concevoir un modle en codant directement du XAML est contre-productif lorsque vous pouvez lviter. Cela savre fastidieux et peu rentable, notamment si vous souhaitez coder la main les tracs vectoriels (mme si vous utilisez une extension comme ReSharper). Dautre part, le modle influence fortement le visuel final dun composant (encore plus que les proprits dfinies au sein dun style) et contient souvent des transitions animes internes au contrle. Ainsi, coder les modles en XAML est souvent un non-sens, il est trs difficile de gnrer du visuel de manire sensible tant le code XAML est abstrait. Les cratifs procdent souvent par ttonnement pour arriver au visuel final dune interface, pour cela il faut ncessairement utiliser une interface telle quen proposent Illustrator, Expression Design et Expression Blend. Il va sans dire que crer un modle du dbut la fin en C# est encore plus aberrant lorsquon souhaite un design abouti. Voici lexemple dun style et dun modle de bouton, tous deux crs la main en XAML et affects une instance de bouton:
<Style x:Key="ButtonStyle2" TargetType="Button"> <Setter Property="Background"> <Setter.Value> <SolidColorBrush Color="#FF550024"/> </Setter.Value> </Setter> <Setter Property="BorderThickness" Value="0,0,2,2"/> <Setter Property="BorderBrush" Value="#FF743A3A"/> <Setter Property="Foreground" Value="#FFFFFFFF"/> <Setter Property="FontFamily" Value="Courier New"/>

354

Partie III

Conception dapplications riches

<Setter Property="FontSize" Value="18"/> <Setter Property="Cursor" Value="Hand"/> </Style> <ControlTemplate x:Key="RoundButton" TargetType="Button"> <Grid > <Ellipse Fill="BlueViolet" Width="100" Height="Auto"/> <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" /> </Grid> </ControlTemplate> <Button Content="Accueil" Margin="0,0,10,0"$ Style="{StaticResource ButtonStyle2}" Template="{StaticResource RoundButton}"/>

Lexemple ci-dessus est assez brut. Comme vous le constatez, les balises Template et Style nentretiennent aucun lien particulier. Cette structure ne correspond pas au code gnr sous Blend. Ce dernier possde une manire bien lui darticuler les styles et les modles. Dans la grande majorit des cas, lorsque vous crez un modle de composant dans Blend, celui-ci lencapsule automatiquement au sein dun style. Cest pour cette raison que, dans Expression Blend, la fentre de cration de modles a pour titre "Create Style Resource". Mme si ce comportement peut dconcerter au premier abord, il est efficace et permet dappliquer le modle indirectement travers laffectation du style. Voici le mme exemple revu et corrig afin de mettre en valeur ce concept:
<Style x:Key="ButtonStyle2" TargetType="Button"> <Setter Property="Background"> <Setter.Value> <SolidColorBrush Color="#FF550024"/> </Setter.Value> </Setter> <Setter Property="BorderThickness" Value="0,0,2,2"/> <Setter Property="BorderBrush" Value="#FF743A3A"/> <Setter Property="Foreground" Value="#FFFFFFFF"/> <Setter Property="FontFamily" Value="Courier New"/> <Setter Property="FontSize" Value="18"/> <Setter Property="Cursor" Value="Hand"/> <Setter Property="Template" > <Setter.Value> <ControlTemplate TargetType="Button"> <Grid> <Rectangle Fill="BlueViolet" RadiusX="8" RadiusY="8" /> <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>

Le XAML gnr peut paratre verbeux, mais il est au final assez simple et rapide assimiler. Il est possible damliorer ce concept en rfrenant une ressource modle dans plusieurs styles diffrents:
<ControlTemplate x:Key="RoundButton" TargetType="Button"> <Grid > <Ellipse Fill="BlueViolet" Width="100" Height="Auto"/>

Chapitre 11

Ressources graphiques

355

<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" /> </Grid> </ControlTemplate> <Style x:Key="ButtonStyle1" TargetType="Button"> <Setter Property="Background"> <Setter.Value> <SolidColorBrush Color="#FF550024"/> </Setter.Value> </Setter> <Setter Property="BorderThickness" Value="0,0,2,2"/> <Setter Property="Foreground" Value="#FFFFFFFF"/> <Setter Property="FontFamily" Value="Courier New"/> <Setter Property="FontSize" Value="18"/> <Setter Property="Template" Value="{StaticResource RoundButton}"/> </Style> <Style x:Key="ButtonStyle2" TargetType="Button"> <Setter Property="Background"> <Setter.Value> <SolidColorBrush Color="#FF240055"/> </Setter.Value> </Setter> <Setter Property="BorderThickness" Value="0,0,4,4"/> <Setter Property="Foreground" Value="#FFFFFFFF"/> <Setter Property="FontFamily" Value="Tahoma"/> <Setter Property="FontSize" Value="18"/> <Setter Property="Template" Value="{StaticResource RoundButton}"/> </Style>

ATTENTION

De manire gnrale, il faut privilgier les styles aux modles. Lapplication nen sera que plus facile maintenir et volutive. Tout ce que vous dfinissez au sein dun modle est propre lensemble des instances qui possdent le modle. La seule exception cette rgle est lorsque vous recourrez la liaison de modles (TemplateBinding). Au contraire, toutes les proprits dfinies au sein dun style restent par la suite modifiables et personnalisables.

Le projet StyleAndTemplate_ModeleSimple.zip est disponible dans le dossier chap11 des exemples du livre. Nous allons examiner deux cas concrets reposants sur le design dun Slider et dune ListBox. Ces derniers concentrent, eux seuls, une grande majorit des problmatiques communes la personnalisation de tous types de contrles.

11.5 Le modle Slider


La personnalisation dun Slider est trs diffrente de celle dun bouton (voir Chapitre7). Un bouton ne possde par dfaut aucun objet logique au sein de son arbre visuel. Autrement dit, rien dans le modle dun bouton nest crucial en terme de fonctionnalits. Le seul objet logique, contenu par dfaut dans tous les boutons, est le ContentPresenter. Il fournit au bouton la capacit dafficher du texte ou tout autre objet comme unique enfant. Il est toutefois facultatif car le bouton diffuse lvnement Click et ragit aux interactions utilisateur (MouseEnter, MouseLeave, etc.) sans lever derreurs lorsque le ContentPresenter est absent. Ce nest pas le cas du Slider: ce

356

Partie III

Conception dapplications riches

dernier contient plusieurs lments logiques ncessaires son fonctionnement. Dans cette section, vous apprendrez les mthodologies et les bonnes pratiques de la personnalisation de composant.

11.5.1 Principes et architecture


Lorsque vous crez un modle, deux manires de procder soffrent vous. Soit vous le concevez partir dun objet daffichage slectionn dans larbre visuel de lapplication, soit vous modifiez le modle dun composant fourni par dfaut au sein de la bibliothque Silverlight. Au Chapitre7, nous avons utilis la premire mthode. Ctait la meilleure option car la classe ButtonBase, et celles qui en dcoulent comme Button, ToggleButton ou RadioButton, ne contiennent aucun objet logique. A contrario, comme larchitecture du composant Slider est plus complexe, il est prfrable dans un premier temps de partir du modle fourni en standard. Pour cela, utilisez le projet StyleAndTemplate_ModeleSimple.sln ou crez un nouveau projet de test. Placez un exemplaire de Slider nimporte o dans la grille principale. Cliquez-droit dessus, slectionnez Edit Template > Edit a copy Dans la fentre de cration de styles, vous pouvez cliquer sur OK. Dans un premier temps, notre objectif est de comprendre larbre visuel dun Slider, il nest donc pas ncessaire dorganiser le modle dans un dictionnaire de ressources. Le modle du Slider est affich juste aprs cette tape (voir Figure11.30).
Figure11.30
Larbre visuel dun Slider.

Vous remarquez quun Slider contient deux grilles correspondant respectivement un mode daffichage horizontal et vertical. Pour identifier facilement les lments logiques dun contrle, Blend affiche, droite de ceux-ci, une icne reprsentant un morceau de puzzle surmont dune coche verte. La liste des parties ncessaires au fonctionnement dun contrle est gre par le panneau Parts situ en haut gauche de linterface. Lorsquun de ces lments logiques nest pas prsent dans larbre visuel, ce panneau affiche le morceau de puzzle sans coche verte. De cette manire, il est trs facile de savoir si toutes les parties logiques du composant sont correctement dfinies dans larbre visuel. De fait, lidentification automatique des lments logiques repose sur le nommage correct de ces derniers. Pour vous en convaincre, il suffit de supprimer le nom de la grille HorizontalTemplate, le panneau Parts vous indique ds lors que celui-ci manque en affichant licne puzzle sans coche verte. Vous navez pas besoin de connatre par cur le nom des parties logiques pour chaque composant. Si vous souhaitez redfinir la grille en tant que partie logique du Slider, il vous suffit de cliquer-droit sur celle-ci, de slectionner loption Make Into Part of Slider, puis de cliquer sur HorizontalTemplate (voir Figure11.31).

Chapitre 11

Ressources graphiques

357

Figure11.31
Larbre visuel dun Slider.

Ds lors, la grille est nouveau nomme HorizontalTemplate. Nous allons maintenant essayer de comprendre comment le modle Slider horizontal est structur. Tout dabord, lorsque la grille est slectionne, on remarque trois colonnes dont les deux premires sont en mode de redimensionnement automatique:
<Grid x:Name="HorizontalTemplate" Background="{TemplateBinding Background}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions>

Les deux colonnes sadaptent aux dimensions de leur contenu. La troisime colonne est en mode relatif et occupera par consquent le reste de lespace disponible. Dans les premire et dernire colonne se trouvent deux boutons de rptition (de type RepeatButton) transparents mais cliquables. Ils reprsentent des zones interactives qui permettent de dplacer le curseur de manire indirecte. Lorsque lutilisateur clique sur lun deux, la largeur du premier RepeatButton, HorizontalTrack Large Change RepeatButton, augmente ou diminue. Cela a pour consquence de dplacer le curseur dont la largeur est fixe en dur et de rduire ou daugmenter la place restante alloue la troisime colonne. Le curseur, dans la colonne du milieu est de type Thumb. Ce composant diffuse trois vnements correspondant ceux dune interaction de type glisser-dposer : Drag Started, DragDelta et DragCompleted. Lobjet vnementiel, de type DragDelta Event Args, rcupr par lcouteur de lvnement de DragDelta, contient deux proprits Horizontal Change et Vertical Change. Lorsque vous personnalisez un contrle, vous navez pas accs au code logique, nous pouvons toutefois prdire que ces valeurs servent modifier la largeur du premier RepeatButton dans les limites des dimensions du Slider. La modification de la largeur dcale automatiquement les deux autres colonnes. Nous pouvons maintenant crer un premier Slider en partant dune base simple sans trop de difficults. Vous devrez souvent choisir entre crer des styles personnaliss partir de ceux fournis, ou crer entirement larbre visuel de ces composants. Cette dernire mthode, bien

358

Partie III

Conception dapplications riches

quun peu plus prouvante au dbut, est une excellente manire dapprendre lagencement ainsi que limbrication de contrles.

11.5.2 Un Slider personnalis


Nous allons utiliser la seconde mthode voque plus haut en nous basant sur une arborescence simple situe dans MainPage.xaml. Nous produirons donc un modle de Slider partir de celle-ci. Il est ncessaire de dcompresser la solution LecteurMultiMedia_BaseModele.zip du dossier chap11. Vous trouverez dans larbre visuel plusieurs boutons (Button, ToggleButton, Hyperlink Button, RadioButton) dont les styles et modles sont contenus dans le dictionnaire de ressources nomm BobifysStyles.xaml. Ouvrez le panneau Resources afin de prendre connaissance des diffrents styles et modles prsents quil propose (voir Figure11.32).
Figure11.32
Le dictionnaire de ressources ddi aux styles et aux modles.

Ce dictionnaire contient une liaison ciblant un dictionnaire ddi aux pinceaux; il sera sans doute ncessaire den ajouter une autre pointant vers le dictionnaire contenant les ressources de couleurs. Tout ce qui est fait dans ce projet est une synthse des prcdents chapitres, nous ny reviendrons donc pas. Le Slider aura pour but de filtrer les vidos et les sons en fonction dune dure maximum, le composant ListBox affichera la liste des mdias en remplacement de la grille fictive PseudoListe (cette dernire nest quune maquette). Slectionnez la grille nomme SliderTimeCode. Elle nous servira de base pour crer un Slider personnalis. Dfinissez-lui trois colonnes, dont les deux premires doivent tre en mode de redi mensionnement automatique et la dernire en mode relatif. Positionnez ensuite deux instances de RepeatButton dans la premire et la dernire colonne avec une opacit fixe 0. Le premier RepeatButton doit possder une largeur exprime en pixels gale 0, le second doit tre en mode de redimensionnement automatique pour sadapter dynamiquement la troisime colonne. Faites en sorte que le futur composant Thumb, qui correspond la grille contenant le curseur et ltiquette, soit dans la colonne du milieu. Transformez cette grille en contrle de type Thumb via le menu Tools, puis Make Control Nommez le style gnr BobifyTimeThumbStyle. Une fois dans le mode ddition du modle, dfinissez une largeur de12,5 pixels pour la grille principale de ce composant. Slectionnez ensuite les deux premiers tracs ainsi que le TextBlock et appliquez-leur une marge ngative droite de 50 pixels. Cette opration est importante car elle rduit lespace utilis par le Thumb dans notre futur Slider, tout en conservant laffichage de ltiquette.

Chapitre 11

Ressources graphiques

359

Si nous ne procdions pas ainsi, le curseur ne pourrait pas se dplacer sur la totalit du Slider car il serait bloqu par la largeur de ltiquette (voir Figure11.33).
Figure11.33
Rglage des marges pour les tracs du composant Thumb.

Une fois cette opration ralise, revenez au niveau de lapplication. Vrifiez bien que les colonnes en largeur automatique ne possdent pas une valeur minimale en pixels. cette fin, il suffit de cliquer ct de licne de redimensionnement Auto, pour les slectionner et afficher leurs proprits. Oublier cette tape contraindrait les dplacements du curseur. Slectionnez la grille contenant les lments du Slider, faites-en un nouveau style via le menu Make Control Nommez-le Bobify TimeFilterSliderStyle. Une fois dans le modle, vrifiez que la largeur de la grille est en mode Auto. Cliquez-droit dessus et dfinissez-la en tant que partie logique Horizontal Template, celle-ci est ds lors renomme. Le premier enfant de la grille correspond un trac et ne fait pas partie des enfants logiques obligatoires. Il est toutefois ncessaire de vrifier que sa largeur est en mode dtirement automatique (afin quelle sadapte la grille dynamiquement). Ce trac doit tre tal sur les trois colonnes, veillez ce que sa proprit ColumnSpan soit gale 3. Slectionnez ensuite chacun des composants restants dans larbre visuel et donnez-leur un rle logique adquat (voir Figure11.34).
Figure11.34
Association des objets de larbre visuel en tant que partie logique du contrle Slider.

Si tout sest correctement droul, le Slider fonctionne parfaitement. Revenez au niveau de lapplication, dfinissez une valeur minimale de0 et une maximale de600. Cela reprsentera le temps minimal et maximal exprim en secondes. Lorsque lutilisateur dplacera le curseur, il filtrera les vidos ou les sons dont le temps sera suprieur la valeur choisie. Ltiquette a pour but dafficher cette dure mise jour lors de dplacements du curseur. Vous pouvez encore amliorer le rendu en ajoutant une barre de couleur (Rectangle) superpose au trac dans la premire colonne (voir Figure11.35).
Figure11.35
Arbre visuel finalis du modle Slider.

360

Partie III

Conception dapplications riches

Il est galement possible danimer les diffrents lments durant le survol du Slider ou du Thumb. cette fin, le mieux est de crer des liaisons de modles entre les proprits de remplissage des tracs prsents dans larbre visuel du Thumb et les proprits Background et BorderBrush de celui-ci (voir Figure11.36).
Figure11.36
Liaison de modles du Thumb.

De cette manire, il est possible danimer les couleurs du Thumb via ltat MouseOver du Slider. Le Slider est maintenant presque termin, il nous reste trouver un moyen efficace de lier la valeur affiche par le TextBlock contenu dans le Thumb, et la valeur du Slider. Le projet est dans larchive LecteurMultiMedia_SliderModele.zip du dossier chap11.

11.6 Les liaisons


Au sein de Silverlight, deux familles de liaisons cohabitent: les liaisons de modles et les liaisons de donnes. La premire correspond la notation XAML TemplateBinding. Elle ne fait pas rfrence une classe proprement dite, mais une expression spcifique, uniquement disponible au sein dun modle de composant. Elle nest utile que dans le cadre de la personnalisation de composants et a t conue en grande partie lintention des designers. La seconde, un sur-ensemble plus vaste, dote des mmes capacits que la premire, offre toutefois beaucoup plus de capacits. Celle-ci est exprime par la classe concrte Binding. Vous pouvez considrer que la notation TemplateBinding est une utilisation spcifique de la classe Binding facilitant et simplifiant lcriture XAML.

11.6.1 Crer une liaison


Reprenez le projet lecteur multimdia l o vous laviez laiss, puis accdez au modle Thumb contenu dans le Slider. Nous allons crer une suite de liaisons de modles partant de la proprit Text du TextBlock contenu dans le Thumb jusqu la proprit Value du Slider. Lorsque cette dernire sera modifie, le composant TextBlock affichera la dure au format mm:ss.ms. Le problme consiste savoir sur quelle proprit du Thumb nous pouvons crer la liaison. La proprit Tag est idale dans ce cas de figure puisqutant type Object, elle est capable de recevoir nimporte quel type de valeur. Il est ensuite possible de lier la proprit Tag du Thumb la proprit Value du Slider (voir Figure11.37).

Chapitre 11

Ressources graphiques

361

Dans la Figure11.37, il faut comprendre que la proprit Text du TextBlock contenu dans le Thumb est lie (TemplateBinding) lattribut Tag de celui-ci; puisque la proprit Tag du Thumb est lie lattribut Value du Slider. Autrement dit, lorsque la proprit Value du Slider sera mise jour par lutilisateur, elle affectera la proprit Tag du Thumb qui impactera son tour la valeur Text du TextBlock (contenu dans le modle du Thumb). Crez les trois liaisons de modle dcrites ci-dessus.
Figure11.37
Schma de la liaison de modles en cascade.
Composant Slider

Value

Tag

Proprit Thumb Liaison de modle

Tag

TextBock

Text

NOTE INFO

Vous constatez que le texte est affich dans une autre couleur correspondant la proprit Fore ground du Thumb. Ce comportement est assez logique, le contrle Thumb ne contient par dfaut aucun TextBlock ou ContentPresenter dans son modle, il possde cependant la proprit Foreground hrite de la classe Control. Celle-ci correspond une couleur de texte et ne cible, initialement, aucun contrle. Toutefois, ds quune liaison de modles est mise en place pour la proprit Text, le champ texte est dtect lintrieur du modle et sa proprit Foreground est lie lattribut Foreground du Thumb. Vous navez pas besoin de dfinir cette liaison.

Compilez et dplacez le curseur du contrle Thumb, il affiche une valeur de type Double appelant en interne sa mthode ToString afin que le champ TextBlock puisse lafficher. Cela met en valeur la ncessit de convertir les secondes au format mm:ss.ms. cette fin, nous devons crer une liaison de donnes ainsi quune classe de conversion. Cette classe doit implmenter linterface IValueConverter et dfinir les mthodes qui y sont dcrites. Ouvrez le projet dans Visual Studio cet environnement est bien plus adapt au dveloppement C# quExpression Blend. Pour raliser cette opration, nous avons deux choix:

Le premier consiste utiliser notre classe de conversion lintrieur de la dfinition du modle donc dans notre dictionnaire de ressources. Cest le choix le plus logique et correct en terme darchitecture. Cela devrait fonctionner sans problme. Toutefois, il arrive parfois que linterface de Blend lve une erreur pour des raisons daccs et dinitialisation. Ce type derreurs est appel Design Time Errors. Celles-ci sont souvent dues lclatement des ressources logiques et graphiques dans des dictionnaires de ressources ainsi qu une interprtation limite du code logique par Blend. Nous aborderons ce principe la fin de cette section.

362

Partie III

Conception dapplications riches

Le second choix possde lavantage dafficher correctement la donne convertie dans Expression Blend sans que ce dernier ne lve derreurs. Lobjectif est dutiliser la liaison de modles standard vers une proprit du contrle, par exemple la proprit Tag dans le cas de notre Slider. Il est ensuite ncessaire de lier la proprit Tag une autre du mme contrle, Value dans notre exemple, en dfinissant une liaison de donnes (Binding). De cette manire, nous dfinissons une conversion au niveau de lapplication, ce qui limite grandement les risques derreur dinterprtation du code logique sous Blend (voir Figure11.38).
Composant Value Convertisseur Proprit Thumb Liaison de modle Slider Tag

Figure11.38
Schma de la liaison de modles en cascade avec conversion des valeurs.

Tag

Liaison de donnes

TextBock

Classe implmentant IValueConverter

Text

Nous allons aborder cette solution en premier. Comme vous le constatez la Figure11.37, il est possible de lier des proprits du mme objet ou dobjets diffrents situs dans le mme arbre visuel. Gnrez une liaison de modles pointant vers la proprit Tag du Slider en lieu et place de la proprit Value initialement cible. Cliquez ensuite sur licne carre situe droite de la proprit Tag du Slider et slectionnez le menu Data Binding pour dfinir une liaison de donnes. Une bote de dialogue apparat, elle vous permet de crer une liaison dUIElement UIElement tant que les proprits lies acceptent des types quivalents. Cliquez sur le second onglet nomm Element Property. La partie gauche de la fentre liste les objets prsents dans larbre visuel de lapplication. Conservez le Slider slectionn. La partie droite montre les proprits du Slider, choisissez Value (voir Figure11.39). Lorsque vous compilez, vous obtenez le mme comportement quauparavant tout en ayant ajout une liaison. Nous allons maintenant coder notre classe de conversion. Celle-ci doit implmenter linterface IValueConverter. Dans Visual Studio, crez un rpertoire nomm Utils si celui-ci nest pas prsent. Cliquez-droit sur ce rpertoire, puis ajoutez une classe nomme Double2Ti meCodeConverter.cs. Supprimez tous les espaces de nom gnrs par dfaut mis part System, puis ajoutez System.Windows.Data. Gnrez ensuite le code implmentant les mthodes dcrites par linterface (voir Figure11.40).

Chapitre 11

Ressources graphiques

363

Figure11.39
Liaison de modles et de donne avec conversion des valeurs.

Figure11.40
Implmentation des mthodes de linterface IValueConverter.

Une fois cette tape passe, vous obtenez le code ci-dessous:


using System; using System.Windows.Data; namespace LecteurMultiMedia.Utils { public class Double2TimeCodeConverter: IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } }

Les deux mthodes ont exactement le mme objectif: convertir un type ou une valeur en un autre type ou valeur. La premire, nomme Convert, correspond au sens dfinit par dfaut lorsque vous crez une liaison de donnes. La seconde, ConvertBack, permet de grer une liaison double sens quil faut prciser en XAML. Si nous dfinissions un champ de saisie TextBox au lieu dun champ texte classique de type TextBlock, lutilisateur sera alors en mesure de saisir une valeur dans le TextBox. La proprit Text de ce dernier peut alors tre convertie dynamiquement en Double et

364

Partie III

Conception dapplications riches

affecte la proprit Value si la mthode est correctement implmente. Dans cet exemple, il nest pas trs pertinent davoir ce type dinteraction, nous nallons donc pas nous attarder sur la mthode ConvertBack. Modifiez la mthode Convert comme ci-dessous:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { TimeSpan ts = new TimeSpan(); if (value is double) ts = TimeSpan.FromSeconds((double)value); return ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + ts.Milliseconds.ToString("000"); }

Maintenant que nous avons cr le code adquat, il faut rfrencer la classe de conversion en tant que ressource logique. Le mieux serait de la stocker dans un dictionnaire de ressources ddi. Crez-en un via Blend dans le rpertoire RD. Le code ci-dessous dcrit la manire dont vous pouvez dclarer des ressources logiques et rfrencer lespace de noms Utils:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Utils="clr-namespace:LecteurMultiMedia.Utils" > <Utils:Double2TimeCodeConverter x:Key="D2TCConverter" /> </ResourceDictionary>

NOTE INFO

Comme ce dictionnaire est rfrenc par App.xaml, la classe de conversion est utilisable nimporte o dans lapplication. Vous devrez toutefois prter attention au fait quune seule instance de celleci sera utilise systmatiquement. Il faudra donc faire attention ne pas employer de champs ou de proprits de manire inconsquente. Dans lexemple ci-dessus, la variable de type TimeSpan est locale la mthode, de ce fait, celle-ci possde une rfrence unique chaque appel de la mthode Convert. Il tait important de ne pas utiliser de proprit ou de champ priv car nous pourrions avoir plusieurs instances de Slider diffrents utilisant la mme opration de conversion.

Nous allons maintenant modifier la liaison de donnes afin dutiliser le convertisseur. Cliquez nouveau sur licne carre situe droite de la proprit Tag du Slider, puis choisissez le menu Data Binding Dpliez la zone des options situe en bas de la fentre affiche, choisissez D2TC Converter comme classe de conversion (voir Figure11.41).

Chapitre 11

Ressources graphiques

365

Figure11.41
Slection de la ressource D2TCConverter.

Le code XAML correspondant la liaison de donnes a volu:


<Slider Tag="{Binding Value, Converter={StaticResource D2TCConverter}, ElementName=slider, Mode=OneWay }" />

Vous constatez que, mis part le membre indiquant dventuels paramtres de conversion, le XAML reflte fidlement les options de liaison dcrites dans la fentre. Nous pourrions encore amliorer la conversion en passant un paramtre sous forme de chane de caractres par exemple:
<Slider Tag="{Binding Value, Converter={StaticResource D2TCConverter}, ElementName=slider, ConverterParameter=00:00.000, Mode=OneWay }" />

Du ct C#, il nous faudrait modifier la classe de cette manire:


public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { TimeSpan ts = new TimeSpan(); if (value is double) ts = TimeSpan.FromMilliseconds((double)value*1000); string p = parameter as string; if (p == "00:00.000") { return ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00") + "." + ts.Milliseconds.ToString("000"); } return ts.Minutes.ToString("00") + ":" + ts.Seconds.ToString("00"); }

366

Partie III

Conception dapplications riches

Si aucun paramtre nest prcis, alors on affiche les minutes et secondes, dans le cas contraire et si la chane de caractres fournie correspond "00:00.000", alors on montre galement les millisecondes. Revenons maintenant sur la premire solution consistant utiliser la classe de conversion dans le modle du Slider (voir Figure11.42). Comme nous lavons dit au dbut de cette section, la liaison de modles nest quune liaison de donnes spcifique. Il est possible de crer une liaison de donnes en prcisant une source relative pointant vers la classe du modle personnalis. De cette manire, nous reproduisons le comportement dune liaison de modles:
Tag=" { Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Converter={StaticResource D2TCConverter }, Mode=OneWay }"

Cette liaison, bien que fonctionnelle lexcution, nest toutefois pas correctement interprte par Expression Blend. Le panneau Results affiche un message indiquant un code XAML invalide. Ce type derreurs est appel Design Time Errors. Ces erreurs peuvent tre handicapantes pour les designers. Dans certains cas, le composant est mal affich dans Blend, dans dautres la totalit de lapplication ne sera pas affiche en mode cration. Ceci est essentiellement d au fait que le style est dfini au sein dun dictionnaire de ressources.
Figure11.42
Schma avec utilisation de la classe Double2 Time Code Converter dans le style.
Composant Value Slider

Proprit Thumb Liaison de modle

Convertisseur

Tag

Liaison de donnes

TextBock

Classe implmentant IValueConverter

Text

NOTE INFO

Crer une liaison de donnes en C# est assez simple, cela peut tre intressant lorsque vous dveloppez votre propre framework. Admettons deux instances de Rectangle. Lorsque lon met jour la largeur du premier rectangle, cela modifie dynamiquement la largeur du second. Le code ci-dessous montre comment faire:

Chapitre 11

Ressources graphiques

367

Random rnd = new Random(); public MainPage() { InitializeComponent(); //on cre une nouvelle instance de Binding Binding b = new Binding(); //on dfinit le type de liaison b.Mode = BindingMode.OneWay; //on prcise le nom du DependencyObject source b.ElementName = rectangleSource.Name; //on dclare le chemin daccs la proprit source b.Path = new PropertyPath("Width"); //on affecte la liaison la proprit Width du rectangle cible rectangleCible.SetBinding(Rectangle.WidthProperty, b); MouseLeftButtonDown += new MouseButtonEventHandler(MainPage_MouseLeftButtonDown); } void MainPage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //lorsque lon clique sur LayoutRoot //on met jour la proprit source, //ce qui modifie la proprit cible rectangleSource.Width = (double)rnd.Next(100,400); }

Le projet LecteurMultiMedia_SliderLiaisonModele.zip est disponible dans le dossier chap11 des exemples.

11.6.2 Les donnes fictives


Nous allons maintenant simuler laffichage de donnes externes au sein dExpression Blend. Nous utiliserons cette fin une instance de ListBox que nous personnaliserons la section11.7. Lorsque vous modifiez le style dun contrle, il est ncessaire davoir le retour visuel des styles et des modles en cours de modification. Bien videmment, les contrles standard, tels que la ScrollBar, sont assez faciles tester puisque ce sont des lments visuels dont les enfants ne sont pas gnrs dynamiquement lexcution. Ce nest pas le cas des lments dune liste qui ne sont thoriquement visibles que lorsque les donnes sont charges et affectes la ListBox. Les ingnieurs de Microsoft ont pens cette ventualit et ont cr cette fin la notion de donnes fictives. Lide est simple: les designers ont la capacit de crer des collections de donnes types aux valeurs alatoires. Une fois cres, ils ont la possibilit de les affecter une ListBox ou nimporte quel autre contrle dont le rle est dexposer des donnes. Procder ainsi permet aux designers de personnaliser les composants de donnes de manire autonome, sans solliciter le dveloppeur. Lorsque les donnes relles sont prtes, il suffit de modifier une ligne de code pour les affecter en lieu et place des donnes fictives. Ouvrez le projet Lecteur-

368

Partie III

Conception dapplications riches

Multimedia" dans sa dernire version. Nous allons commencer par crer un jeu de donnes fictives via le panneau Data. Cliquez sur la premire icne situe en haut gauche ( ) de ce panneau, puis slectionnez le menu Define New Sample Data (voir Figure11.43).
Figure11.43
Dfinir une collection de donnes fictives.

Dans la fentre de cration qui saffiche, choisissez de dfinir cette source pour lensemble du projet et nommez-la ListMedia. Vous pouvez dcider dafficher cette source de donne lexcution ou uniquement dans linterface de Blend. Laissez cette option inchange et cliquez sur OK. Blend a automatiquement gnr un rpertoire ddi au stockage de ces donnes, celles-ci sont galement affiches dans le panneau Data (voir Figure11.44). Afin que les donnes fictives soient accessibles au sein de lensemble du projet, Blend a modifi le fichier App.xaml en ajoutant une ressource de type SampleDataSource:
<ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="RD/BobifysLogicalResources.xaml"/> <ResourceDictionary Source="RD/Couleurs.xaml"/> <ResourceDictionary Source="RD/BobifysBrushes.xaml"/> <ResourceDictionary Source="RD/VideosImagesBrushes.xaml"/> <ResourceDictionary Source="RD/BobifysStyles.xaml"/> </ResourceDictionary.MergedDictionaries> <SampleData:ListMedia x:Key="ListMedia" d:IsDataSource="True"/> </ResourceDictionary>

Figure11.44
Le rpertoire gnr et laffichage du modle de donnes dans le panneau Data.

La proprit IsDataSource nest l que pour prciser si le panneau Data doit afficher ou non cette source de donne. Au sein du panneau Data, deux proprits sont cres par dfaut. Nous allons les personnaliser et en ajouter dautres afin de simuler une relle source de donnes. Cliquez sur licne plus, situe droite de "Collection" afin dajouter autant de proprits quil est ncessaire (voir Figure11.45).

Chapitre 11

Ressources graphiques

369

Figure11.45
Les proprits dfinissant un modle de collection.

lexception des proprits duree, idType (Number), type (Image), la majorit sera des chanes de caractres String. Lquipe des ingnieurs Expression a pouss la conception relativement loin puisquil est possible de configurer le format de donne reprsent par un champ. Ainsi le champ auteur contiendra des noms de personnes fictives (voir Figure11.46).
Figure11.46
Spcifier un format de donnes.

Vous pouvez vous rfrer au Tableau11.3 pour configurer les champs que vous avez crs.
Tableau11.3 : Liste des couleurs sauvegarder comme ressource

Nom des champ auteur couleur

Type de valeur String String

Format et spcificits de la valeur Name Color bitmap: #FF08AFC8 vido: #FFC70963 son: #FFFFC800

date

String

Date

370

Partie III

Conception dapplications riches

Tableau11.3 : Liste des couleurs sauvegarder comme ressource (suite)

Nom des champ description

Type de valeur String

Format et spcificits de la valeur Lorem Ipsum Nombre de mots40 Longueur max12

duree idType

Number Number

Nombre 3 chiffres (inutile pour les mdias) Nombre entre1 et3 bitmap:1 vido:2 son:3

titre

String

Lorem Ipsum Nombre de mots max4 Longueur max12

type

Image

Prciser le chemin daccs vers le rpertoire bitmaps du projet. Les images choisies alatoirement par Blend dterminent le type de mdia. Website Url

url

String

La configuration des donnes fictives nest pas encore termine, vous pouvez modifier la main les valeurs que vous souhaitez en cliquant sur licne de modification de donnes ( ) situe droite de Collection. Dans le tableau qui saffiche, appuyez-vous sur les images bitmap du champ Type afin de dfinir les champs idType et Color dont les valeurs doivent tre en accord avec le type de mdia. La dure exprime en secondes est galement inutile pour les mdias de type image, autant passer sa valeur 0 dans ce cas (voir Figure11.47).
Figure11.47
Modifier directement les donnes fictives.

Chapitre 11

Ressources graphiques

371

Vous pouvez galement modifier les titres si vous souhaitez obtenir un contenu raliste. Une fois la configuration termine, cliquez sur OK. La collection est prte tre affecte une instance de ListBox. Si vous tes designer, dvelopper en C# peut vous sembler compliqu ou ne faisant pas partie de votre primtre de travail. Ce nest pas un problme puisque Blend vous permet de raliser cette opration sans une ligne de code logique. Vrifiez que les grilles nommes Pseudo Liste et PseudoScrollBar sont caches en cliquant sur licne de lil situe droite des grilles dans larbre visuel. Ensuite, depuis le panneau Data, glissez la collection dans la grille nomme PanneauListe. Blend gnre automatiquement un composant ListBox dont la proprit Items Source est lie notre collection de donnes fictives. Dfinissez ses marges afin quil occupe lespace laiss vacant par la grille cache PseudoListe.:
<Slider x:Name="slider" /> <ToggleButton x:Name="DisplayModeToggleButton" Cursor="Hand"/> <ListBox Margin="2,69,14,4"ItemTemplate="{StaticResource ItemTemplate1}" ItemsSource="{Binding Collection}"/> <ToggleButton x:Name="ExpanderToggleButton" />

Nous avons parcouru la moiti du chemin. Si tout sest correctement droul, vous devriez obtenir un visuel correspondant la Figure11.48
Figure11.48
Modifier les donnes fictives directement.

Le projet LecteurMultiMedia_SampleData.zip est dans le dossier chap11 des exemples de ce livre.

11.6.3 Le contexte de donnes


Dans lexercice prcdent, nous avons dfini, sans nous en rendre compte, un contexte de donnes. Cette notion est importante en terme darchitecture, nous allons donc ltudier dans cette section. Crez un projet temporaire de test, puis dposez cte cte sur LayoutRoot une instance de conteneur Grid et un exemplaire de StackPanel. La grille contiendra une liste; le StackPanel affichera le dtail de llment slectionn dans la liste. Comme nous lavons vu, lorsque vous dposez une collection en provenance du panneau Data, vous gnrez par dfaut une instance de ListBox exposant la totalit des champs dcrits par la collection pour chaque lment de la liste. Il est toutefois possible de ne glisser-dposer quun ou plusieurs champs au choix via lutilisation des touches Maj ou Ctrl. Dans ce cas, vous instanciez une liste naffichant que le ou les champs qui ont t dposs sur le conteneur. Crez une collection de donnes fictives, puis choisissez lune

372

Partie III

Conception dapplications riches

ou lautre de ces mthodes pour dposer un exemplaire de ListBox dans la grille. Voici le code XAML gnr par Blend:
<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource ListMedia}}" > <Grid HorizontalAlignment="Left" Margin="54,25,0,206" Width="205"> <ListBox x:Name="listBox" Margin="0,0,5,0" ItemTemplate="{StaticResource ItemTemplate1}" ItemsSource="{Binding Collection}" SelectedIndex="-1"/> </Grid> <StackPanel />

Comme no