Vous êtes sur la page 1sur 640

DANS LA MME COLLECTION

Propulsez votre site avec


WORDPRESS
Julien Chichignoud
ISBN : 979-10-90085-73-2
Des applications ultra
rapides avec NODE.JS
Mathieu Nebra
ISBN : 979-10-90085-59-6
Structurez vos donnes
avec XML
Ludovic Roland
ISBN : 979-10-90085-56-5
v
Quallez-vous apprendre ?
Les lments de bases
La Document Type Definition (DTD)
Les schmas XML
LAPI DOM
LAPI XPath
Les espaces de noms
La mise en forme avec CSS XML
STRUCTUREZ VOS DONNES AVEC
Ludovic Roland
27
ISBN : 979-10-90085-56-5
7 9 1 0 9 0 0 8 5 5 6 5 9
Structurez vos donnes avec XML
Vous souhaitez structurer les donnes manipules ou changes par vos programmes ou vos
applications mobiles ? Ce livre est fait pour vous ! Conu pour les dbutants, il vous apprendra
pas pas matriser le XML.
propos de lauteur
Ludovic Roland
Dveloppeur Android et Windows Phone, Ludovic voit le XML comme un
moyen eficace de structurer les donnes changer entre un serveur et les
nouveaux appareils que sont les smartphones et tablettes. Il dcide alors
de partager ses connaissances en rdigeant un cours sur OpenClassrooms.
Lesprit dOpenClassrooms
Des cours clairs et ludiques, conus pour tous
Une communaut de professionnels et de passionns prts vous aider sur nos forums
Des ressources disponibles partout, tout le temps : sur le web, en PDF, en eBook
X
M
L
Ludovic Roland
Prenez en main BOOTSTRAP
Maurice Chavelli
ISBN : 979-10-90085-62-6
Apprenez programmer en
ADA
Vincent Jarc
ISBN : 979-10-90085-58-9
Programmez en
ACTIONSCRIPT 3
Guillaume Chau & Guillaume Lapayre
ISBN : 979-10-90085-64-0

A
C
T
I
O
N
S
C
R
I
P
T
3
Guillaum
e Chau
Guillaum
e Lapayre
Quallez-vous apprendre ?
Les bases dActionscript
La programmation oriente objet
La cration de dessins vectoriels
La manipulation dimages
Les animations et interpolations
Linteraction avec lutilisateur
La cration de mini jeux ACTIONSCRIPT 3
PROGRAMMEZ EN
Guillaume Chau et Guillaume Lapayre
32
ISBN : 979-10-90085-55-8
7 9 1 0 9 0 0 8 5 5 5 8 9
Programmez en ACTIONSCRIPT 3
Vous avez toujours voulu raliser des animations Flash sans jamais vraiment savoir comment
faire ? Ce livre est fait pour vous ! Conu pour les dbutants, il vous apprendra pas pas
Actionscript 3, le langage de programmation de Flash.
propos de lauteur
Guillaume Chau
Etudiant ingnieur, passionn par les nouvelles technologies et le Web, il a
remport le premier prix de InnovGame 2011, grce un jeu de stratgie
ralis laide de Actionscript 3.0 et du Flex SDK.
Guillaume Lapayre
Diplm dune cole dingnieurs gnralistes et dun master en acoustique
et vibrations, Guillaume Lapayre est toujours en qute de connaissances
dans de nouveaux domaines. Cest ainsi quaprs avoir fait ses premiers pas
avec divers langages tels que le C, le C++, le Java ou lActionscript, il dcide
de partager ses connaissances sur OpenClassrooms.
Lesprit dOpenClassrooms
Des cours clairs et ludiques, conus pour tous
Une communaut de professionnels et de passionns prts vous aider sur nos forums
Des ressources disponibles partout, tout le temps : sur le web, en PDF, en eBook
Rejoignez la communaut
OpenClassrooms :
www.openclassrooms.com
www.facebook.com/openclassrooms
@OpenClassrooms
Devenez Premium !
Apprenez votre rythme
grce lofre Premium
OpenClassrooms :
tlchargez des eBooks,
des vidos des cours et
faites-vous certifier.
Devenez Premium !
Devenez Premium
Tlchargez
les eBooks
Accdez
aux certifcations
Tlchargez
les vidos en HD
www.openclassrooms.com/premium
WINDOWS PHONE 8
CREZ DES APPLICATIONS EN C# POUR
Nicolas Hilaire
Sauf mention contraire, le contenu de cet ouvrage est publi sous la licence : Creative Commons
BY-NC-SA 2.0 La copie de cet ouvrage est autorise sous rserve du respect des conditions de la licence
Texte complet de la licence disponible sur : http: //creativecommons.org/licenses/by-nc-sa/2.0/fr/
Mentions lgales
Conception couverture : Sophie Bai
Illustrations chapitres : Fan Jiyong, Alexandra Persil et Sophie Bai
OpenClassrooms 2014 - ISBN : 979-10-90085-63-3
Avant-propos
L
a rvolution de la mobilit est en marche. Nous connaissons tous liPhone qui
a su conqurir un grand nombre dutilisateurs, ainsi que les tlphones Android
dont le nombre ne cesse de crotre. . . Ces tlphones intelligents (ou smartphones)
deviennent omniprsents dans nos usages quotidiens. Microsoft se devait de monter dans
le TGV de la mobilit ! Sont donc apparus, peu aprs ses deux grands concurrents,
les tlphones Windows. Avec un peu plus de retard sur eux, Microsoft attaque ce
march avec plus de maturit quApple, qui a fonc en tant que pionnier, et nous
propose son systme dexploitation : Windows Phone. Cest une bonne nouvelle !
Cest aujourdhui un nouveau march avec plein dapplications potentielles raliser
grce vos talents de dveloppeur. Vous souhaitez raliser des applications mobiles
pour Windows Phone 8 avec le langage C#? Ce livre est fait pour vous ! Conu pour
les dbutants, il vous apprendra pas pas tout ce quil faut pour vous lancer dans
le dveloppement XAML/C# pour Windows Phone 8. Sachez que vous pouvez suivre
beaucoup de chapitres de ce cours sans possder forcment de Windows Phone, ce
qui est idal lorsque lon souhaite simplement dcouvrir le sujet. Le seul prrequis
sera de matriser un tant soit peu le C#. Pour ceux qui auraient besoin dune piqre
de rappel, vous pouvez consulter mon cours C# sur le site OpenClassrooms - http:
//fr.openclassrooms.com/informatique/cours/apprenez-a-developper-en-c.
Quallez-vous apprendre en lisant ce livre ?
Il est possible de raliser deux grands types dapplication Windows Phone :
Des applications dites de gestion : cest a que vous allez apprendre dans ce
livre.
Des jeux graphiques avec DirectX ou XNA : a, on ne sen proccupera pas ici.
Il est aussi possible de dvelopper des applications pour Windows Phone en VB.NET
et en F#, ainsi quen C++. Je ne traiterai ici que de C#.
Dans ce cours, vous allez apprendre dvelopper des applications de gestion avec
Silverlight pour Windows Phone, qui est utilis dans les versions 7 de Windows Phone,
mais galement des applications XAML/C#, langage utilis pour dvelopper des
applications pour Windows Phone 8. Vous allez dcouvrir pas pas les points suivants :
1. La thorie et les bases :la premire partie va vous permettre de dcouvrir le
i
CHAPITRE 0. AVANT-PROPOS
XAML, lment indispensable pour pouvoir dvelopper pour Windows Phone. Il
sagit du langage permettant de raliser la partie graphique de nos applications.
2. Un mobile orient donnes : une application, cest avant tout de la mise en
forme de donnes. Nous allons voir comment manipuler ces donnes dans cette
partie et nous allons apprendre bien architecturer nos applications.
3. Une bibliothque de contrles :en plus du XAML, vous avez accs plein
de contrles ddis aux Windows Phone. De la carte du monde, au panorama,
en passant par le navigateur web, vous dcouvrirez des contrles optimiss pour
enrichir vos applications.
4. Un tlphone ouvert vers lextrieur : dans cette partie, vous verrez com-
ment faire pour interagir avec votre smartphone grce ses dirents capteurs
ou des gestes. Le GPS et lacclromtre nauront plus de secrets pour vous
mais vous verrez galement comment envoyer des notications ou communiquer
avec Facebook.
Avant de commencer, je dois quand mme vous signaler que le dveloppement pour
Windows Phone peut rendre accroc ! Vous allez avoir envie de crer des applications
sans jamais vous arrter ! Si vous tes prts assumer cette probable dpendance, cest
que vous tes bons pour continuer. Alors, cest parti !
Comment lire ce livre ?
Suivez lordre des chapitres
Lisez ce livre comme on lit un roman : il a t conu comme tel. Contrairement
beaucoup de livres techniques o il est courant de lire en diagonale et de sauter certains
chapitres, ici il est trs fortement recommand de suivre lordre du cours, moins que
vous ne soyez dj un peu expriments (et trs sr de vous).
Pratiquez en mme temps
Pratiquez rgulirement. Nattendez pas davoir ni la lecture de ce livre pour faire
vos propres essais ; nhsitez pas modier les codes donns en exemples, an de
bien cerner le comportement de chaque instruction. Plus vous vous exercerez, et plus
lapprentissage sera rapide et ecace.
Remerciements
Je souhaite remercier un certain nombre de personnes qui, de prs ou de loin, ont
contribu la naissance de cet ouvrage :
ma femme Delphine, qui me soutient au quotidien et more chaque jour une
raison davancer dans la vie ses cts et mon ls Timo, mme sil ntait
encore quun rve lors de la rdaction de cet ouvrage,
ii
REMERCIEMENTS
Anna, Jonathan, Jessica, Marine, Mathieu, Pierre, et toute lquipe dOpen-
Classrooms,
tous les relecteurs et particulirement Rudy Huyn, qui ma donn dexcellents
conseils.
iii
CHAPITRE 0. AVANT-PROPOS
iv
Table des matires
Avant-propos i
Quallez-vous apprendre en lisant ce livre ? . . . . . . . . . . . . . . . . . . . . i
Comment lire ce livre ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii
Suivez lordre des chapitres . . . . . . . . . . . . . . . . . . . . . . . . . ii
Pratiquez en mme temps . . . . . . . . . . . . . . . . . . . . . . . . . . ii
Remerciements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii
I La thorie et les bases 1
1 Windows Phone, un nouveau priphrique 3
Historique, la mobilit chez Microsoft . . . . . . . . . . . . . . . . . . . . . . 4
Le renouveau : Windows Phone 7 . . . . . . . . . . . . . . . . . . . . . . . . . 4
Windows Phone 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Lesprit Modern UI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Le Windows Phone Store . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2 Les outils de dveloppements 9
Prrequis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Installer Visual Studio Express pour Windows Phone . . . . . . . . . . . . . . 11
Lmulateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
XAML et code behind . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Blend pour le design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
v
TABLE DES MATIRES
3 Notre premire application 29
Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Linterface en XAML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Le code-behind en C# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Le contrle Grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Le contrle StackPanel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Le contrle TextBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Le contrle TextBlock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Les vnements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Le bouton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Et Silverlight dans tout a ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4 Les contrles 47
Gnralits sur les contrles . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Utiliser le designer pour ajouter un CheckBox . . . . . . . . . . . . . . . . . . 49
Utiliser Expression Blend pour ajouter un ToggleButton . . . . . . . . . . . . 52
5 Le clavier virtuel 55
Acher le clavier virtuel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Intercepter les touches du clavier virtuel . . . . . . . . . . . . . . . . . . . . . 56
Les dirents types de clavier . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6 Les conteneurs et le placement 61
StackPanel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
ScrollViewer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Canvas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Alignement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Marges et espacement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
7 Ajouter du style 77
Acher des images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Les ressources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Les styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Les thmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
vi
TABLE DES MATIRES
Changer lapparence de son contrle . . . . . . . . . . . . . . . . . . . . . . . 92
8 TP1 : Cration du jeu du plus ou du moins 95
Instructions pour raliser le TP . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
9 Dessiner avec le XAML 101
Dessin 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Pinceaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Les transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
10 Crer des animations 113
Principes gnraux des animations . . . . . . . . . . . . . . . . . . . . . . . . 114
Cration dune animation simple (XAML) . . . . . . . . . . . . . . . . . . . . 114
Cration dune animation complexe (Blend) . . . . . . . . . . . . . . . . . . . 119
Projections 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
II Un mobile orient donnes 129
11 Une application plusieurs pages, la navigation 131
Naviguer entre les pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Grer le bouton de retour arrire . . . . . . . . . . . . . . . . . . . . . . . . . 139
Ajouter une image daccueil (splash screen) . . . . . . . . . . . . . . . . . . . 142
Le tombstonning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
12 TP 2 : Crer une animation de transition entre les pages 155
Instructions pour raliser le TP . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
13 Les proprits de dpendances et proprits attaches 161
Les proprits de dpendances . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Les proprits attaches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
14 O est mon application? 165
Le .XAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Achage dimages en ressources . . . . . . . . . . . . . . . . . . . . . . . . . 167
vii
TABLE DES MATIRES
Accder au ux des ressources . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
15 ListBox 169
Un contrle majeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Grer les modles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Slection dun lment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
16 La manipulation des donnes (DataBinding & Converters) 181
Principe du Databinding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Le binding des donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Binding et mode design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Utiliser lObservableCollection . . . . . . . . . . . . . . . . . . . . . . . . . . 201
Les converters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
17 MVVM 211
Principe du patron de conception . . . . . . . . . . . . . . . . . . . . . . . . . 212
Premire mise en place de MVVM . . . . . . . . . . . . . . . . . . . . . . . . 214
Les commandes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Les frameworks la rescousse : MVVM-Light . . . . . . . . . . . . . . . . . . 225
Dautres frameworks MVVM . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Faut-il utiliser systmatiquement MVVM? . . . . . . . . . . . . . . . . . . . 245
18 Gestion des tats visuels 247
Les tats dun contrle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
Modier un tat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Changer dtat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
Crer un nouvel tat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
19 Le traitement des donnes 263
HttpRequest & WebClient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
Linq-To-Json . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
La bibliothque de Syndication . . . . . . . . . . . . . . . . . . . . . . . . . . 277
Asynchronisme avanc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Le rpertoire local . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
viii
TABLE DES MATIRES
III Une bibliothque de contrles 289
20 Panorama et Pivot 291
Panorama . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
Pivot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
21 Navigateur web 307
Naviguer sur une page web . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
Evnements de navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
Navigation interne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Communiquer entre XAML et HTML . . . . . . . . . . . . . . . . . . . . . . 311
22 TP : Cration dun lecteur de ux RSS simple 321
Instructions pour raliser le TP . . . . . . . . . . . . . . . . . . . . . . . . . . 322
Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
23 Grer lorientation 341
Les direntes orientations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
Dtecter les changements dorientation . . . . . . . . . . . . . . . . . . . . . . 345
Stratgies de gestion dorientation . . . . . . . . . . . . . . . . . . . . . . . . 347
24 Grer les multiples rsolutions 361
Les direntes rsolutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Grer plusieurs rsolutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Les images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
Limage de lcran daccueil . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
25 Lapplication Bar 367
Prsentation et utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
Appliquer le Databinding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
Mode plein cran . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
26 Le toolkit Windows Phone 381
Prsentation et installation du toolkit Windows Phone . . . . . . . . . . . . . 382
PerformanceProgressBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
ListPicker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
ix
TABLE DES MATIRES
WrapPanel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
LongListSelector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
Avantages & limites du toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . 401
Les autres toolkits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
27 Le contrle de cartes (Map) 405
Prsentation et utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
Interactions avec le contrle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
Epingler des points dintrt . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
Acher un itinraire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
28 TP : Une application mto 429
Instructions pour raliser le TP . . . . . . . . . . . . . . . . . . . . . . . . . . 430
Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
IV Un tlphone ouvert vers lextrieur 447
29 La gestuelle 449
Le simple toucher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Les dirents touchers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Gestuelle avance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
Le toolkit la rescousse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
30 Lacclromtre 455
Utiliser lacclromtre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
Utiliser lacclromtre avec lmulateur . . . . . . . . . . . . . . . . . . . . . 457
Exploiter lacclromtre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
Les autres capteurs facultatifs . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
La motion API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
31 TP : Jeux de hasard (Grattage et secouage) 467
Instructions pour raliser le TP . . . . . . . . . . . . . . . . . . . . . . . . . . 468
Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470
Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479
32 La golocalisation 481
x
TABLE DES MATIRES
Dterminer sa position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
Utiliser la golocalisation dans lmulateur . . . . . . . . . . . . . . . . . . . . 486
Utiliser la golocalisation avec le contrle Map . . . . . . . . . . . . . . . . . 488
33 Les Tasks du tlphone 489
Les choosers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
Les launchers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493
Etat de lapplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497
34 Les tuiles 499
Que sont les tuiles ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500
Des tuiles pour tous les gots . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
Personnaliser les tuiles par dfaut . . . . . . . . . . . . . . . . . . . . . . . . . 504
Crer des tuiles secondaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
Modier et supprimer une tuile . . . . . . . . . . . . . . . . . . . . . . . . . . 515
35 Les notications 517
Le principe darchitecture des notications . . . . . . . . . . . . . . . . . . . . 518
Le principe de cration du serveur de notication . . . . . . . . . . . . . . . . 519
Les dirents messages de notications . . . . . . . . . . . . . . . . . . . . . . 520
Cration du client Windows Phone recevant la notication . . . . . . . . . . . 522
36 TP : Amliorer lapplication mto avec golocalisation et tuiles 531
Instructions pour raliser le TP . . . . . . . . . . . . . . . . . . . . . . . . . . 532
Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532
Aller plus loin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537
37 Une application uide = une application propre ! 541
Un thread, cest quoi ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542
Le thread dinterface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542
Utiliser un thread darrire-plan . . . . . . . . . . . . . . . . . . . . . . . . . . 544
Utiliser le Dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
Utiliser un BackgroundWorker . . . . . . . . . . . . . . . . . . . . . . . . . . 546
Enchaner les threads dans un pool . . . . . . . . . . . . . . . . . . . . . . . . 550
Le DispatcherTimer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552
Thread de composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554
xi
TABLE DES MATIRES
Les outils pour amliorer lapplication . . . . . . . . . . . . . . . . . . . . . . 555
38 Utiliser des tches Background Agent 557
Crer un Background Agent pour une tche priodique . . . . . . . . . . . . . 558
Crer une tche aux ressources intensives . . . . . . . . . . . . . . . . . . . . 564
Remarques gnrales sur les tches . . . . . . . . . . . . . . . . . . . . . . . . 564
Envoyer une notication avec un agent darrire-plan . . . . . . . . . . . . . . 565
39 Utiliser Facebook dans une application mobile 569
Crer une application Facebook . . . . . . . . . . . . . . . . . . . . . . . . . . 570
Simplier les connexions Facebook avec lAPI . . . . . . . . . . . . . . . . . 570
Scuriser laccs Facebook avec OAuth . . . . . . . . . . . . . . . . . . . . . 572
Se connecter Facebook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573
Exploiter le graphe social avec le SDK . . . . . . . . . . . . . . . . . . . . . . 580
Rcuprer des informations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 580
Obtenir la liste de ses amis . . . . . . . . . . . . . . . . . . . . . . . . . . . . 582
Publier un post sur son mur Facebook . . . . . . . . . . . . . . . . . . . . . . 585
Utiliser les tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590
40 Publier son application 593
Crer un compte dveloppeur . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
Inscrire un tlphone de dveloppeur . . . . . . . . . . . . . . . . . . . . . . . 600
Proposer une version dessai de votre application . . . . . . . . . . . . . . . . 605
Certier son application avec le Store Test Kit . . . . . . . . . . . . . . . . . 606
Publier son application sur le Windows Phone Store . . . . . . . . . . . . . . 612
xii
Premire partie
La thorie et les bases
1
Chapitre 1
Windows Phone, un nouveau
priphrique
Dicult :
Windows Phone est la nouvelle plateforme pour tlphones mobiles de Microsoft. Elle
permet de raliser des applications pour les smartphones quips du systme dexploitation
Windows Phone. Apparues dans un premier temps sous sa version 7, Windows Phone en
est actuellement sa version 8.
Microsoft arrive en rupture avec son nouveau systme dexploitation pour smartphone an
de concurrencer les deux gants que sont Apple et Google.
3
CHAPITRE 1. WINDOWS PHONE, UN NOUVEAU PRIPHRIQUE
Historique, la mobilit chez Microsoft
Cela fait longtemps que Microsoft dispose de matriels mobiles. On a eu dans un
premier temps les priphriques quips de Windows CE; ce systme dexploitation
tait une variation de Windows destine aux systmes embarqus. Il a notamment t
beaucoup utilis dans les PC de poche (Pocket PC). Cette version de Windows tait
optimise pour les appareils possdant peu despace de stockage.
Est arrive ensuite la gamme de Windows Mobile. Ce systme dexploitation tait
utilis sur des smartphones, PDA ou PC de poche. Il est arriv pour concurrencer les
Blackberry et permettait de recevoir ses emails, dutiliser la suite bureautique, etc. Ces
mobiles ressemblaient beaucoup au Windows que lon connait, avec son fameux menu
dmarrer. On utilisait en gnral un stylet la place de la souris.
Avec les nouvelles interfaces tactiles, on a vu apparatre Apple et son fameux iPhone
venu pour rvolutionner la faon dont on se servait jusqu prsent des appareils mo-
biles. Ce qui a donn un srieux coup de vieux Windows Mobile, comme le montre
la gure 1.1. . .
Figure 1.1 Un Windows CE et un IPhone
Le renouveau : Windows Phone 7
Microsoft a, son tour, chang radicalement son systme dexploitation an de prendre
ce virage de la mobilit en proposant Windows Phone, dont la premire version est la
version 7, sortie en octobre 2010. Il ne sagit pas dune volution de Windows Mobile,
part au niveau de la numrotation des versions (dans la mesure o Windows Mobile
sest arrt avec la version 6.5). Windows Phone 7 a t redvelopp de zro et arrive
avec un nouveau look, nomm dans un premier temps Mtro , plus pur, fortement
ractif et intuitif, et valorisant linformation structure. Microsoft se positionne ainsi en
rupture avec ses systmes dexploitation prcdents et propose des concepts dirents
pour son nouvel OS, comme la navigation exclusive au doigt par exemple. Il se veut
plutt grand public quuniquement destin aux entreprises.
Pour tre autoris utiliser le systme dexploitation Windows Phone 7 (voir gure
1.2), un smartphone doit respecter un minimum de spcications. Ces spcications
garantissent quune application aura un minimum de puissance, vitant davoir des
4
WINDOWS PHONE 8
applications trop lentes. Lcran doit tre multipoint dau moins 3.5 pouces, cest-
-dire quil doit pouvoir ragir plusieurs pressions simultanes et permettant une
rsolution de 480x800. Les tlphones doivent galement tre munis obligatoire-
ment de quelques quipements, comme le fait davoir un GPS, davoir une camra,
un acclromtre, etc . . . Chaque tlphone possdera galement trois boutons faisant
partie intgrante de son chssis. Le premier bouton permettra de revenir en arrire, le
second daccder au menu et le dernier de faire des recherches.
Figure 1.2 Windows Phone 7
Windows Phone 8
Cest tout dernirement, avec la sortie de Windows 8, que le systme dexploitation
Windows Phone a chang de version pour passer galement la version 8. Lobjectif
de Microsoft est dunier au maximum le cur de Windows 8 et de Windows Phone 8,
permettant de faire facilement des passerelles entre eux. Windows 8 tant un systme
dexploitation cr avant tout pour des tablettes, il paraissait logique que Windows 8 et
Windows Phone 8 partagent beaucoup de fonctionnalits. Windows 8 sest largement
inspir de Windows Phone pour crer son style, Modern UI, et cest dsormais au tour
de Windows Phone de subir une volution majeure Windows Phone 8, prsent dans
la gure 1.3 an de se rapprocher de son grand frre, Windows 8.
Beaucoup de choses sont partages entre les deux systmes, cest ce quon appelle le
Shared Windows Core . Ainsi, il deviendra trs facile de crer des applications pour
Windows Phone 8 qui ne ncessiteront que trs peu dadaptation pour fonctionner sur
Windows 8. Cest une des grandes forces de Windows Phone 8.
Notez que les applications Windows Phone 7 fonctionnent galement sur Win-
dows Phone 8, cest une bonne chose si vous possdiez dj des applications
Windows Phone 7 et que celles-ci nont pas t portes pour WP8.
5
CHAPITRE 1. WINDOWS PHONE, UN NOUVEAU PRIPHRIQUE
Windows Phone 8 est galement plus performant grce au support du code natif. Il est
ainsi possible de dvelopper des jeux en C++, utilisant DirectX.
Windows Phone 8 apporte en plus des nouvelles rsolutions dcran : WVGA (800x480
pixels), WXVGA (1280x768), et True 720p (1280x720), avec une adaptation auto-
matique de chacune.
Figure 1.3 Windows Phone 8
Lesprit Modern UI
Anciennement appel Mtro , Modern UI est le nom donn par Microsoft son
langage de design. Plutt que dadapter linterface des anciens Windows Mobile, pour
Windows Phone 7 il a t dcid de repartir sur un tout nouveau design.
Le nom Mtro a t inspir par les achages qui se trouvent eectivement dans les
stations de mtro et qui guident ecacement les voyageurs jusqu leurs destinations.
Les achages sont clairs, prcis, souvent minimalistes et sans oritures, par exemple
une che et un gros 5 pour indiquer que cest par l quon va trouver le mtro numro
5. . . Voil quoi doivent ressembler les interfaces pour Windows Phone. Elles doivent
valoriser linformation et la uidit plutt que les interfaces lourdes et charges. Le but
est de faire en sorte que lutilisateur trouve le plus rapidement possible linformation
dont il a besoin et dviter les images ou animations superues qui pourraient le ralentir.
Dans cette optique, les applications doivent tre uides et rpondre rapidement aux
actions de lutilisateur, ou du moins lui indiquer que son action a t prise en compte.
Ras le bol des applications Windows ou autre o on ne sait mme plus si on a cliqu
sur un bouton car rien ne se passe !
Courant 2012, Mtro a chang de nom pour devenir Modern UI. Les appli-
cations Windows 8 et Windows Phone 8 doivent chacune suivre les normes
dictes par les principes de Modern UI .
6
LESPRIT MODERN UI
Modern UI se veut donc simple, pur et moderne. Les fonctionnalits sont spares en
Hubs qui sont des espaces regroupant des informations de plusieurs sources de donnes.
Ainsi, il existe plusieurs Hubs (voir gure 1.4), comme le Hub contacts o lon
retrouvera les contacts du tlphone mais aussi les contacts Facebook, Twitter, . . . Nous
avons aussi le Hub Photos , Musique et vidos , Jeux , Microsoft Oce ,
Windows Phone Store ou encore le hub Entreprise qui permettra daccder aux
applications mtiers via un portail que les entreprises peuvent personnaliser.
Figure 1.4 Ecran daccueil de lmulateur o lon voit laccs aux Hubs et aux
applications
Une fois rentr dans un Hub, nous avons accs plusieurs informations disposes sous
la forme dun panorama. Nous verrons un peu plus loin ce quest le panorama mais
je peux dj vous dire quil permet dacher des crans de manire cyclique avec un
dlement latral. Ainsi, dans le Hub de contact, on arrive dans un premier temps sur
la liste de tous les contacts. Lcran de panorama que lon peut faire glisser avec le
doigt nous permet dobtenir sur lcran suivant la liste des dernires activits de nos
contacts, puis la liste des contacts rcents, etc. Et cest pareil pour les autres Hub, le
but est davoir un point dentre qui centralise toutes les informations relatives un
point dintrt.
Cest avec tous ces principes en tte que vous devrez dvelopper votre application.
Nhsitez pas observer comment sont faites les autres, on trouve souvent de bonnes
sources dinspirations permettant de voir ce qui fait la qualit du design dune appli-
7
CHAPITRE 1. WINDOWS PHONE, UN NOUVEAU PRIPHRIQUE
cation.
Le Windows Phone Store
Les applications que nous crons sont ensuite tlchargeables sur la place de march
Windows Phone, appele encore Windows Phone Store. Elles peuvent tre gratuites
ou payantes, permettant ainsi son crateur de gnrer des revenus. Sur le store, on
trouvera galement des musiques et des vidos.
Comme nous lavons dj dit en introduction, nous allons apprendre dvelopper pour
Windows Phone sans forcment possder un Windows Phone. Cest un point important,
mme sil sera trs utile den possder un, vous pouvez tout fait dbuter sans.
Par contre, pour publier une application sur le Windows Phone Store, il fau-
dra possder un compte dveloppeur. Celui-ci est factur 19$ par an, ce qui
correspond 14.
Voil, vous savez tout sur Windows Phone, il est temps dapprendre raliser de
superbes applications !
En rsum
Windows Phone est le nouveau systme dexploitation de Microsoft pour Smart-
phone.
Il arrive avec une nouvelle philosophie de design des applications : Modern UI.
Les applications ralises sont tlchargeables via le magasin en ligne (store) de
Microsoft.
8
Chapitre 2
Les outils de dveloppements
Dicult :
a a lair super a, de pouvoir dvelopper des applications pour les tlphones ! Cest trs
la mode et ces mini-ordinateurs nous rservent plein de surprises. Voyons donc ce quil
nous faut pour nous lancer dans le monde merveilleux du dveloppement pour Windows
Phone.
Nous allons apprendre dvelopper pour Windows Phone quips de la version 8, qui
est la dernire version lheure o jcris ces lignes. Vous serez galement capables de
crer des applications pour Windows Phone 7.5 et 7.8. Mme si la version 8 semble trs
allchante, les versions 7 ne sont pas oublier trop rapidement. En eet, tous les utilisateurs
nont pas encore achet de Windows Phone 8 et seraient srement dus de manquer votre
application rvolutionnaire. De plus, Windows Phone 8 sera galement capable de faire
tourner des applications 7.X. Un march ne pas oublier. . .
9
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
Prrequis
Avant toute chose, je vais vous donner les lments qui vont vous permettre de choisir
entre lenvironnement de dveloppement ddi au dveloppement dapplications pour
Windows Phone 7.5 et celui ddi au dveloppement dapplications pour Windows
Phone 7.5 et 8.
Pourquoi choisir entre un environnement qui fait tout et un environnement
qui ne fait que la moiti des choses ?
Bonne question. . . ! En eet, qui peut le plus peut bien sr le moins. Mais bien que
les environnements de dveloppement soient gratuits, vous nallez peut-tre pas avoir
envie de changer de machine de dveloppement pour autant.
Voici le matriel requis pour dvelopper pour Windows Phone 7.5 :
La premire chose est de possder Windows Vista SP2, ou bien Win-
dows 7 ou encore Windows 8, qui sont les seules congurations supportes
permettant de dvelopper pour Windows Phone 7.5.
Il est galement grandement conseill de possder une carte graphique com-
patible avec DirectX 10 an de pouvoir utiliser correctement lmulateur. Je
reviendrai plus tard sur ce quest lmulateur.
La plupart des PC est aujourdhui quipe de cette conguration. Ce qui est trs
pratique pour se lancer et dcouvrir le dveloppement pour Windows Phone. Par contre,
pour pouvoir dvelopper pour Windows Phone 8, cest un peu plus dlicat :
Il vous faut avant tout Windows 8 en version 64 bits, rien dautre. La ver-
sion conseille est dailleurs la version PRO ou la version Entreprise qui vont
permettre dutiliser lmulateur.
Pour faire tourner lmulateur, il faut que votre processeur supporte la tech-
nologie SLAT (qui permet de faire de la virtualisation) et quelle soit ac-
tive dans le bios ; ce qui est le cas gnralement des PC rcent ( par-
tir de 2011). Il faut galement installer le systme de virtualisation de Mi-
crosoft, Hyper-V - http://fr.wikipedia.org/wiki/Hyper-V, qui est dispo-
nible avec les versions PRO ou Entreprise de Windows 8. Si vous ntes pas
certain que votre processeur supporte cette technologie, vous pouvez le v-
rier avec cette procdure - http://msdn.microsoft.com/fr-fr/library/
windowsphone/develop/ff626524(v=vs.105).aspx (en anglais) ou alors,
tentez linstallation et il vous dira une fois que tout est ni sil y a un pro-
blme ou pas.
Il vous faut aussi une bonne une carte graphique compatible avec DirectX
10 ainsi que 4 Go de mmoire.
Ces contraintes matrielles peuvent rendre dicile daccs le dveloppement pour Win-
dows Phone 8 quelquun qui souhaite simplement sinitier ou dcouvrir cette techno-
logie. Si cest votre cas et que vous ne possdez pas ce matriel, alors je vous conseille
dinstaller lenvironnement de dveloppement pour Windows Phone 7.5, qui vous per-
10
INSTALLER VISUAL STUDIO EXPRESS POUR WINDOWS PHONE
mettra de suivre 95% du cours. Jindiquerai au cours de ce cours ce qui est rserv
exclusivement Windows Phone 8. Sinon, si votre matriel le permet, installez sans
hsiter ce quil faut pour dvelopper pour Windows Phone 8.
Si vous possdez un tlphone quip de Windows Phone 8, que vous disposez
dun abonnement de dveloppeur et que vous ne souhaitez pas vous servir de
lmulateur, il est possible de nutiliser que la version normale de Windows 8.
Ces lments expliqus, voici la suite des prrequis :
Bien sr, vous aurez intrt possder un smartphone quip de Windows
Phone : il est primordial de tester son application sur un tlphone avant de
songer la rendre disponible sur le Windows Phone Store.
Enn le dernier prrequis est de savoir parler le C#.
Le C# est le langage de dveloppement phare de Microsoft et permet la
cration dapplications informatiques de toutes sortes. Il est indispensable de
connaitre un peu le langage de programmation C# an de pouvoir dve-
lopper des applications pour smartphones quips de Windows Phone. Son
tude nest pas traite dans ce cours, mais vous pouvez retrouver un cours
C# complet sur le site OpenClassrooms - http://msdn.microsoft.com/
fr-fr/library/windowsphone/develop/ff626524(v=vs.105).aspx
.
Pour rsumer ce quest le C#, il sagit dun langage orient objet apparu en mme
temps que le framework .NET qui na cess dvoluer depuis 2001. Il permet dutili-
ser les briques du framework .NET pour raliser des applications de toutes sortes et
notamment des applications pour Windows Phone. Cest le ciment et les outils qui
permettent dassembler les briques de nos applications.
Installer Visual Studio Express pour Windows Phone
Puisquon est partis dans le btiment, il nous faut un chef de chantier qui va nous
permettre dorchestrer nos dveloppements. Cest ce quon appelle lIDE, pour Inte-
grated Development Environment, ce qui signie Environnement de dveloppement
intgr . Cet outil de dveloppement est un logiciel qui va nous permettre de crer des
applications et qui va nous fournir les outils pour orchestrer nos dveloppements. La
gamme de Microsoft est riche en outils professionnels de qualit pour le dveloppement,
notamment grce Visual Studio.
Pour apprendre et commencer dcouvrir lenvironnement de dveloppement, Micro-
soft propose gratuitement Visual Studio dans sa version express. Cest une version
allge de lenvironnement de dveloppement qui permet de faire plein de choses, mais
avec moins doutils que dans les versions payantes. Rassurez-vous, ces versions gratuites
sont trs fournies et permettent de faire tout ce dont on a besoin pour apprendre
dvelopper sur Windows Phone et suivre ce cours !
11
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
Pour raliser des applications denvergure, il pourra cependant tre judicieux din-
vestir dans loutil complet et ainsi bncier de fonctionnalits complmentaires qui
permettent damliorer, de faciliter et dindustrialiser les dveloppements.
Pour dvelopper pour Windows Phone gratuitement, nous allons avoir besoin de Mi-
crosoft Visual Studio Express pour Windows Phone. Pour le tlcharger, rendez-vous
sur : http://dev.windowsphone.com. Il est important de noter que les images de ce
site changent rgulirement, donc ne vous tonnez pas si celles que vous trouvez en
ligne dirent lgrement de celles que je vais maintenant vous prsenter !
Si vous possdez la version payante de Visual Studio, rendez-vous galement
sur : http://dev.windowsphone.com pour tlcharger les outils compl-
mentaires et notamment le SDK permettant le dveloppement sur Windows
Phone.
Attention, le site est en anglais, mais ne vous inquitez pas, je vais vous guider. Cliquez
ensuite sur Get SDK qui va nous permettre de tlcharger les outils gratuits (voir la
gure 2.1).
Figure 2.1 Obtenir le SDK depuis la page daccueil du dev center
On arrive sur une nouvelle page o il est indiqu que lon doit tlcharger le Windows
Phone SDK . SDK signie Software Development Kit que lon peut traduire par :
Kit de dveloppement logiciel. Ce sont tous les outils dont on va avoir besoin pour
dvelopper dans une technologie particulire, ici en loccurrence pour Windows Phone.
On nous propose de tlcharger soit la version 8.0 du SDK qui va nous permettre de
dvelopper pour Windows Phone 7.5 et 8.0, soit la version 7.1 du SDK qui nous per-
mettra de dvelopper uniquement pour Windows Phone 7.5. La version 7.11 du SDK
est une mise jour de la version 7.1 permettant de dvelopper sous Windows 8. Tl-
chargez la version qui vous convient en cliquant sur le bouton Download correspondant
(voir la gure 2.2).
12
INSTALLER VISUAL STUDIO EXPRESS POUR WINDOWS PHONE
Notez ici que je tlcharge et installe la version 8.0 du SDK, les actions sont
sensiblement les mmes pour la version 7.1 du SDK.
Figure 2.2 Tlcharger le SDK
On arrive sur une nouvelle page o nous allons enn pouvoir passer en franais (voir
la gure 2.3).
Une nouvelle page se charge et nous allons pouvoir tlcharger linstalleur qui va nous
installer tout ce quil nous faut. Comme sa taille le suggre, il ne sagit que dun petit
excutable qui aura besoin de se connecter internet pour tlcharger tout ce dont il
a besoin (voir la gure 2.4).
Donc, dmarrez le tlchargement et enchanez tout de suite sur linstallation, tant que
vous tes connects internet (voir la gure 2.5).
Linstallation est plutt classique et commence par lacceptation du contrat de licence
(voir les gures 2.6 et 2.7).
Pour le SDK 7.1, il y a un cran supplmentaire pour choisir dinstaller les outils
maintenant (voir la gure 2.8).
Linstallation est globalement plutt longue, surtout sur un PC fraichement install.
Jespre que vous russirez contenir votre impatience ! Enn, nous arrivons la n
de linstallation et vous pouvez dmarrer Visual Studio.
13
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
Figure 2.3 Obtenir le SDK en franais
Figure 2.4 Tlcharger linstalleur
14
INSTALLER VISUAL STUDIO EXPRESS POUR WINDOWS PHONE
Figure 2.5 Logo du SDK pour Windows Phone 8
Figure 2.6 Lacceptation du contrat de licence pour le SDK 7.1
15
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
Figure 2.7 Lacceptation du contrat de licence pour le SDK 8.0
16
INSTALLER VISUAL STUDIO EXPRESS POUR WINDOWS PHONE
Figure 2.8 Insaller les outils avec le SDK 7.1
Remarquez que si vous avez install le SDK 8.0, vous aurez la version 2012
de Visual Studio Express pour Windows Phone alors que si vous avez install
la version 7.1 du SDK, vous aurez la version 2010 de Visual Studio Express
pour Windows Phone.
Vous pouvez galement dmarrer Visual Studio Express pour Windows Phone partir
du Menu Dmarrer. Si vous possdez une version payante de Visual Studio, vous pouvez
prsent le lancer.
Pour la suite du cours, je me baserai sur la version gratuite de Visual Studio
2012 Express que nous venons dinstaller, mais tout ceci sera valable avec
la version 2010 ou avec les versions payantes de Visual Studio. Les captures
seront sans doute direntes, mais je suppose que vous vous y retrouverez !
son ouverture, vous pouvez constater que nous arrivons sur la page de dmarrage
(voir la gure 2.9).
Nous allons donc crer un nouveau projet en cliquant sur le lien (comme indiqu sur
la capture dcran), ou plus classiquement par le menu Fichier > Nouveau projet.
ce moment-l, Visual Studio Express 2012 pour Windows Phone (que jappellerai
dsormais Visual Studio pour conomiser mes doigts et les touches de mon clavier)
nous ouvre sa page de choix du modle du projet (voir la gure 2.10).
Nous allons choisir de crer une Application Windows Phone, qui est la version la plus
17
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
Figure 2.9 Page de dmarrage de Visual Studio permettant de crer un nouveau
projet
Figure 2.10 Modle de projet pour crer une application Windows Phone
18
INSTALLER VISUAL STUDIO EXPRESS POUR WINDOWS PHONE
basique du projet permettant de raliser une application pour Windows Phone avec le
XAML. Remarquons que le choix du langage est possible entre Visual Basic, Visual
C++ et Visual C#. Nous choisissons videmment le C# car cest le langage que nous
matrisons. Jen prote pour nommer mon projet HelloWorld . . . (ici, personne ne
se doute quel type dapplication nous allons faire trs bientt).
Enn, aprs avoir valid la cration du projet, il nous demande la version cibler (voir
la gure 2.11).
Figure 2.11 Choix de la version du SDK utiliser
Choisissez 8.0 pour dvelopper pour Windows Phone 8 ou 7.1 pour dvelopper
pour Windows Phone 7.5. Rappelez-vous quune application 7.5 sera excutable sur les
tlphones quips de Windows Phone 8 (cest lavantage) mais ne pourra pas utiliser
les nouveauts de Windows Phone 8 (cest linconvnient).
Visual Studio gnre son projet, les chiers qui le composent et souvre sur la page
suivante (voir la gure 2.12).
Figure 2.12 Linterface de Visual Studio, ainsi que la liste droulante permettant de
choisir lmulateur
Nous allons revenir sur cet cran trs bientt. Ce quil est important de remarquer
cest que si nous dmarrons lapplication telle quelle, elle va se compiler et sexcuter
dans lmulateur Windows Phone. Vous le voyez dans le petit encadr en haut de Visual
Studio, cest la cible du dploiement. Il est possible de dployer soit sur lmulateur, soit
directement sur un tlphone reli au poste de travail. Il ne reste plus qu rellement
excuter notre application. . .
19
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
Il ne sera pas possible de dployer notre application sur le tlphone sans
une manipulation pralable que nous dcouvrirons dans le dernier chapitre. Si
vous navez pas les prrequis matriels pour installer lmulateur et que vous
possdez un Windows Phone, vous pouvez dores et dj vous reporter ce
chapitre an de pouvoir continuer suivre le cours.
Lmulateur
Attention, si vous avez install le SDK 8.0, vous allez avoir besoin galement dinstaller
le logiciel gestion de la virtualisation : Hyper-v. Celui-ci nest disponible quavec les
versions PRO ou Entreprise de Windows 8 et uniquement si votre processeur supporte
la technologie SLAT. Allez dans le panneau de conguration, programmes, et choisissez
dactiver des fonctionnalits Windows (voir la gure 2.13).
Figure 2.13 Panneau de conguration pour permettre linstallation dHyper-V
Puis, installez hyper-V en cochant la case correspondante (voir la gure 2.14).
Excutons donc notre application en appuyant sur

F5 qui nous permet de dmarrer


lapplication en utilisant le dbogueur.
20
LMULATEUR
Figure 2.14 Cocher pour installer Hyper-V
Vous aurez peut-tre la fentre dlvation des privilges (voir gure 2.15)
qui permet de congurer lmulateur. En ce cas, cliquez sur Ressayer.
Figure 2.15 Dmarrage de lmulateur avec lvation de privilge
Nous constatons que lmulateur se lance, il ressemble un tlphone Windows Phone. . .
On les reconnait dun coup dil car ils ont les trois boutons en bas du tlphone, la
che (ou retour arrire), le bouton daccs au menu et la loupe pour faire des recherches
(voir la gure 2.16).
Lmulateur possde galement des boutons en haut droite qui permettent (de haut
en bas) de :
Fermer lmulateur
Minimiser lmulateur
21
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
Figure 2.16 Emulateur Windows Phone 8
Faire pivoter de 90 vers la gauche lmulateur
Faire pivoter de 90 vers la droite lmulateur
Adapter la rsolution
Zoomer/dzoomer sur lmulateur
Ouvrir les outils supplmentaires
Ces boutons sont prsents dans la gure 2.17.
Remarquons galement que des chires sachent sur le ct droit de lmulateur. Ce
sont des informations sur les performances de lapplication, nous y reviendrons en n
de cours. Enn, vous pouvez fermer lapplication en arrtant le dbogueur en cliquant
sur le carr (voir la gure 2.18).
XAML et code behind
Revenons un peu sur cette page que nous a ach Visual Studio. Nous pouvons voir
que le milieu ressemble lmulateur et que le ct droit ressemble un chier XML.
Vous ne connaissez pas les chiers XML? Si vous voulez en savoir plus, nhsitez pas
faire un petit tour sur internet, cest un format trs utilis dans linformatique ! Pour
faire court, le chier XML est un langage de balise, un peu comme le HTML, o lon
dcrit de linformation. Les balises sont des valeurs entoures de < et > qui dcrivent
la smantique de la donne. Par exemple :
22
XAML ET CODE BEHIND
Figure 2.17 Boutons permettant de faire des actions sur lmulateur
Figure 2.18 Bouton pour arrter le dbogage dans Visual Studio
23
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
1 <prenom >Nicolas </prenom >
La balise <prenom> est ce quon appelle une balise ouvrante, cela signie que ce qui se
trouve aprs (en loccurrence la chane Nicolas ) fait partie de cette balise jusqu
ce que lon rencontre la balise fermante </prenom> qui est comme la balise ouvrante
lexception du / prcdant le nom de la balise. Le XML est un chier facile lire par
nous autres humains. On en dduit assez facilement que le chier contient la chane
Nicolas et quil sagit smantiquement dun prnom. Une balise peut contenir des
attributs permettant de donner des informations sur la donne. Les attributs sont
entours de guillemets et et font partis de la balise. Par exemple :
1 <client nom="Nicolas" age="30"></client >
Ici, la balise client possde un attribut nom ayant la valeur Nicolas et un attribut
age ayant la valeur 30 . Encore une fois, cest trs facile lire pour un humain.
Il est possible que la balise nait pas de valeur, comme cest le cas dans lexemple ci-
dessus. On peut dans ce cas-l remplacer la balise ouvrante et la balise fermante par
cet quivalent :
1 <client nom="Nicolas" age="30"/>
Enn, et nous allons terminer notre aperu rapide du XML avec un dernier point. Il
est important de noter que le XML peut imbriquer ses balises et quil ne peut possder
quun seul lment racine, ce qui nous permet davoir une hirarchie de donnes. Par
exemple nous pourrons avoir :
1 <listesDesClient >
2 <client type="Particulier">
3 <nom >Nicolas </nom >
4 <age >30 </age >
5 </client >
6 <client type="Professionel">
7 <nom >Jrmie </nom >
8 <age >40 </age >
9 </client >
10 </listesDesClient >
On voit tout de suite que le chier dcrit une liste de deux clients. Nous en avons un
qui est un particulier, qui sappelle Nicolas et qui a 30 ans alors que lautre est un
professionnel, prnomm Jrmie et qui a 40 ans.
quoi cela nous sert-il ? comprendre ce fameux chier de droite. Cest le chier
XAML (prononcez Zammel ). Le XAML est un langage qui permet de dcrire des
interfaces et en loccurrence ici le code XAML ( droite dans Visual Studio) dcrit
linterface que nous retrouvons au milieu. Cette zone est la prvisualisation du rendu
du code crit dans la partie droite. On appelle la zone du milieu, le concepteur (ou
plus souvent le designer en anglais). En fait, le chier XAML contient des balises qui
dcrivent ce qui doit sacher sur lcran du tlphone. Nous allons y revenir.
Nous allons donc devoir apprendre un nouveau langage pour pouvoir crer des appli-
cations sur Windows Phone : le XAML. Ne vous inquitez pas, il est assez facile
24
BLEND POUR LE DESIGN
apprendre et des outils vont nous permettre de simplier notre apprentissage.
Ok pour le XAML si tu dis que ce nest pas trop compliqu, mais le C# dans
tout a ?
Eh bien il arrive dans le chier du mme nom que le chier XAML et il est sux par
.cs. Nous le retrouvons si nous cliquons sur le petit triangle ct du chier XAML
qui permet de dplier les chiers (voir la gure 2.19).
Figure 2.19 Le XAML et son code-behind
Il est juste en dessous, on lappelle le code behind. Le code behind est le code C#
qui est associ lcran qui va sacher partir du code XAML. Il permet de grer
toute la logique associe au XAML. Si vous ouvrez ce chier C#, vous pouvez voir
quelques instructions dj cres en mme temps que le XAML. Nous allons galement
y revenir.
Dans la suite de ce cours, les extraits de code XAML seront indiqus par le
site OpenClassrooms comme du XML. Cest seulement pour les besoins de la
coloration syntaxique, mais rassurez-vous, il sagira bien de XAML.
Blend pour le design
An de faciliter la ralisation de jolis crans destination du tlphone, nous pouvons
modier le XAML. Cest un point que nous verrons plus en dtail un peu plus loin.
Il est possible de le modier directement la main lorsquon connat la syntaxe, mais
nous avons aussi notre disposition un outil ddi au design qui le fait tout seul :
Blend.
Microsoft Expression Blend est un outil professionnel de conception dinterfaces
25
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
utilisateur de Microsoft. Une version gratuite pour Windows Phone a t installe
en mme temps que Visual Studio Express 2012 pour Windows Phone et permet de
travailler sur le design de nos crans XAML. Nous verrons comment il fonctionne mais
nous ne nous attarderons pas trop sur son fonctionnement car il mriterait un cours
entier.
Ce qui est intressant cest quil est possible de travailler en mme temps sur le mme
projet dans Visual Studio et dans Blend, les modications se rpercutant de lun
lautre. Faisons un clic droit sur le chier XAML et choisissons de louvrir dans Ex-
pression Blend (voir la gure 2.20).
Figure 2.20 Dmarrage de Blend depuis Visual Studio
Blend souvre alors et ache nouveau le rendu de notre cran (voir la gure 2.21).
Figure 2.21 Interface de Blend
On peut voir galement une grosse bote outils qui va nous permettre de styler notre
application. Nous y reviendrons.
26
BLEND POUR LE DESIGN
En rsum
Pour dvelopper pour Windows Phone, nous avons besoin de Visual Studio et
du kit de dveloppement pour Windows Phone.
Il existe une version totalement gratuite de Visual Studio permettant de raliser
des applications sous Windows Phone.
Un mulateur accompagne Visual Studio pour tester ses applications en mode
dveloppement.
Blend est loutil de design permettant de styler son application, dont une version
gratuite est fournie avec le kit de dveloppement pour Windows Phone.
27
CHAPITRE 2. LES OUTILS DE DVELOPPEMENTS
28
Chapitre 3
Notre premire application
Dicult :
Nous avons dsormais tous les outils quil faut pour commencer apprendre raliser des
applications pour Windows Phone. Nous avons pu voir que ces outils fonctionnent et nous
avons pu constater un dbut de rsultat grce lmulateur. Mais pour bien comprendre et
assimiler toutes les notions, nous avons besoin de plus de concret, de manipuler des lments
et de voir quest-ce qui exactement agit sur quoi. Aussi, il est temps de voir comment raliser
une premire application avec le classique Hello World ! Cette premire application va
nous servir de base pour commencer dcouvrir ce quil faut pour raliser des applications
pour Windows Phone.
29
CHAPITRE 3. NOTRE PREMIRE APPLICATION
Hello World
Revenons donc sur notre cran o nous avons le designer et le XAML. Positionnons-
nous sur le code XAML et ajoutons des lments sans trop comprendre ce que nous
allons faire an de raliser notre Hello World . Nous reviendrons ensuite sur ce que
nous avons fait pour expliquer le tout en dtail.
Pour commencer, on va modier la ligne suivante :
1 <TextBlock Text="nom de la page" Margin="9,-7,0,0" Style="{
StaticResource PhoneTextTitle1Style}"/>
et crire ceci :
1 <TextBlock Text="Hello World" Margin="9,-7,0,0" Style="{
StaticResource PhoneTextTitle1Style}"/>
Nous changeons donc la valeur de lattribut Text de la balise <TextBlock>.
Jemploie ici du vocabulaire XML, mais ne le retenez pas car ce nest pas
exactement de a quil sagit. Nous y reviendrons.
Ensuite, juste aprs :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0">
Donc, lintrieur de cette balise <Grid>, rajoutez :
1 <StackPanel >
2 <TextBlock Text="Saisir votre nom" HorizontalAlignment="
Center" />
3 <TextBox x:Name="Nom" />
4 <Button Content="Valider" Tap="Button_Tap_1" />
5 <TextBlock x:Name="Resultat" Foreground="Red" />
6 </StackPanel >
Remarquez que lorsque vous avez saisi la ligne :
1 <Button Content="Valider" Tap="Button_Tap_1" />
au moment de taper : Tap="", Visual Studio Express vous a propos de gnrer un
nouveau gestionnaire dvnement (voir la gure 3.1).
Vous pouvez le gnrer en appuyant sur

Entre , cela nous fera gagner du temps plus


tard. Sinon, ce nest pas grave. Vous pouvez constater que le designer sest mis jour
pour faire apparatre nos modications (voir la gure 3.2).
Ouvrez maintenant le chier de code behind et modiez la mthode Button_Tap_1
pour avoir :
1 private void Button_Tap_1(object sender , System.Windows.Input.
GestureEventArgs e)
30
HELLO WORLD
Figure 3.1 Gnration du gestionnaire dvnement depuis le XAML
Figure 3.2 Le rendu du XAML dans la fentre du concepteur
31
CHAPITRE 3. NOTRE PREMIRE APPLICATION
2 {
3 Resultat.Text = "Bonjour " + Nom.Text;
4 }
Nous pouvons ds prsent dmarrer notre application en appuyant sur

F5 . Lmu-
lateur se lance et nous voyons apparatre les nouvelles informations sur lcran (voir la
gure 3.3).
Figure 3.3 Rendu de lapplication dans lmulateur
La souris va ici permettre de simuler le toucher avec le doigt lorsque nous cliquons.
Cliquons donc dans la zone de texte et nous voyons apparatre un clavier virtuel
lintrieur de notre application (voir la gure 3.4).
Ce clavier virtuel sappelle le SIP (pour Soft Input Panel ) et apparait automatique-
ment quand on en a besoin, notamment dans les zones de saisie, nous y reviendrons.
Saisissons une valeur dans la zone de texte et cliquons sur le bouton Valider. Nous
voyons apparatre le rsultat en rouge avec un magnique message construit (voir la
gure 3.5).
Et voil, notre Hello World est termin ! Chouette non ? Pour quitter lapplication, le
plus simple est darrter le dbogueur de Visual Studio en cliquant sur le carr Stop.
32
HELLO WORLD
Figure 3.4 Le clavier virtuel dans lmulateur
Figure 3.5 Achage de lHello World dans lmulateur
33
CHAPITRE 3. NOTRE PREMIRE APPLICATION
Linterface en XAML
Alors, taper des choses sans rien comprendre, a va un moment. . . mais l, il est temps
de savoir ce que nous avons fait !
Nous avons dans un premier temps fait des choses dans le XAML. Pour rappel, le
XAML sert dcrire le contenu de ce que nous allons voir lcran. En fait, un chier
XAML correspond une page. Une application peut tre dcoupe en plusieurs pages,
nous y reviendrons plus tard. Ce que nous avons vu sur lmulateur est lachage de
la page MainPage.
Donc, nous avons utilis le XAML pour dcrire le contenu de la page. Il est globalement
assez explicite mais ce quil faut comprendre cest que nous avons ajout des contrles
du framework .NET dans la page. Un contrle est une classe C# complte qui sait
sacher, se positionner, traiter des vnements de lutilisateur (comme le clic sur le
bouton), etc. Ces contrles ont des proprits et peuvent tre ajouts dans le XAML.
Par exemple, prenons la ligne suivante :
1 <TextBlock Text="Saisir votre nom" HorizontalAlignment="Center"
/>
Nous demandons dajouter dans la page le contrle TextBlock - http://msdn.
microsoft.com/fr-fr/library/ms617591(v=vs.95).aspx. Le contrle TextBlock
correspond une zone de texte non modiable. Nous positionnons sa proprit Text
la chane de caractres Saisir votre nom . Ce contrle sera align au centre grce
la proprit HorizontalAlignment positionne Center. En fait, jai dit que nous
lajoutons dans la page, mais pour tre plus prcis, nous lajoutons dans le contrle
StackPanel qui est lui-mme contenu dans le contrle Grid, qui est contenu dans la
page. Nous verrons plus loin ce que sont ces contrles.
Ce que nous avons appel balise plus tt est en fait un contrle, et ce que
nous avons appel attribut correspond une proprit de ce contrle.
Derrire, automatiquement, cette ligne de XAML entrane la dclaration et linstancia-
tion dun objet de type TextBlock avec les aectations de proprits adquates. Puis
ce contrle est ajout dans le contrle StackPanel. Tout ceci nous est masqu. Grce
au XAML nous avons simplement dcrit linterface de la page et cest Visual Studio
qui sest occup de le transformer en C#. Parfait ! Moins on en fait et mieux on se
porte. . . et surtout il y a moins de risque derreurs.
Et cest pareil pour tous les autres contrles de la page, le TextBlock qui est une zone
de texte non modiable, le TextBox qui est une zone de texte modiable dclenchant
lachage du clavier virtuel, le bouton, etc.
Vous laurez peut-tre devin, mais cest pareil pour la page. Elle est dclare tout en
haut du chier XAML :
1 <phone:PhoneApplicationPage
2 x:Class="HelloWorld.MainPage"
34
LINTERFACE EN XAML
3 xmlns="http :// schemas.microsoft.com/winfx/2006/xaml/
presentation"
4 xmlns:x="http :// schemas.microsoft.com/winfx/2006/xaml"
5 xmlns:phone="clr -namespace:Microsoft.Phone.Controls;
assembly=Microsoft.Phone"
6 xmlns:shell="clr -namespace:Microsoft.Phone.Shell;assembly=
Microsoft.Phone"
7 xmlns:d="http :// schemas.microsoft.com/expression/blend/2008
"
8 xmlns:mc="http :// schemas.openxmlformats.org/markup -
compatibility/2006"
9 FontFamily="{StaticResource PhoneFontFamilyNormal}"
10 FontSize="{StaticResource PhoneFontSizeNormal}"
11 Foreground="{StaticResource PhoneForegroundBrush}"
12 SupportedOrientations="Portrait" Orientation="Portrait"
13 mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
14 shell:SystemTray.IsVisible="True">
Cest dailleurs le conteneur de base du chier XAML, celui qui contient tous les autres
contrles. La page est en fait reprsente par la classe PhoneApplicationPage qui
est aussi un objet du framework .NET. Plus prcisment, notre page est une classe
gnre qui drive de lobjet PhoneApplicationPage. Il sagit de la class MainPage
situe dans lespace de nom HelloWorld, cest ce que lon voit dans la proprit :
1 x:Class="HelloWorld.MainPage"
On peut sen rendre compte galement dans le code behind de la page o Visual Studio
a gnr une classe partielle du mme nom que le chier XAML et qui drive de
PhoneApplicationPage :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 // Constructeur
4 public MainPage ()
5 {
6 InitializeComponent ();
7 }
8
9 private void Button_Tap_1(object sender , System.Windows.
Input.GestureEventArgs e)
10 {
11 Resultat.Text = "Bonjour " + Nom.Text;
12 }
13 }
Pourquoi partielle ? Parce quil existe un autre chier dans votre projet. Ce chier est
cach mais on peut lacher en cliquant sur le bouton en haut de lexplorateur de
solution (voir la gure 3.6).
Et nous pouvons voir notamment un rpertoire obj contenant un rpertoire debug
contenant le chier MainPage.g.i.cs. Si vous louvrez, vous pouvez trouver le code
35
CHAPITRE 3. NOTRE PREMIRE APPLICATION
Figure 3.6 Achage des chiers cachs dans lexplorateur de solutions
suivant :
1 public partial class MainPage : Microsoft.Phone.Controls.
PhoneApplicationPage
2 {
3 internal System.Windows.Controls.Grid LayoutRoot;
4 internal System.Windows.Controls.StackPanel TitlePanel;
5 internal System.Windows.Controls.Grid ContentPanel;
6 internal System.Windows.Controls.TextBox Nom;
7 internal System.Windows.Controls.TextBlock Resultat;
8
9 private bool _contentLoaded;
10
11 /// <summary >
12 /// InitializeComponent
13 /// </summary >
14 [System.Diagnostics.DebuggerNonUserCodeAttribute ()]
15 public void InitializeComponent ()
16 {
17 if (_contentLoaded)
18 {
19 return;
20 }
21 _contentLoaded = true;
22 System.Windows.Application.LoadComponent(this , new
System.Uri("/HelloWorld;component/MainPage.xaml",
36
LE CODE-BEHIND EN C#
System.UriKind.Relative));
23 this.LayoutRoot = (( System.Windows.Controls.Grid)(this.
FindName("LayoutRoot")));
24 this.TitlePanel = (( System.Windows.Controls.StackPanel)
(this.FindName("TitlePanel")));
25 this.ContentPanel = (( System.Windows.Controls.Grid)(
this.FindName("ContentPanel")));
26 this.Nom = (( System.Windows.Controls.TextBox)(this.
FindName("Nom")));
27 this.Resultat = (( System.Windows.Controls.TextBlock)(
this.FindName("Resultat")));
28 }
29 }
Il sagit dune classe qui est gnre lorsquon modie le chier XAML. Ne modiez
pas ce chier car il sera re-gnr tout le temps. On peut voir quil sagit dune classe
MainPage, du mme nom que la proprit x:Class de tout lheure, qui soccupe de
charger le chier XAML et qui cre des variables partir des contrles quil trouvera
dedans. Nous voyons notamment quil a cr les deux variables suivantes :
1 internal System.Windows.Controls.TextBox Nom;
2 internal System.Windows.Controls.TextBlock Resultat;
Le nom de ces variables correspond aux proprits x:Name des deux contrles que nous
avons cr :
1 <TextBox x:Name="Nom" />
2 <TextBlock x:Name="Resultat" Foreground="Red" />
Ces variables sont initialises aprs quil ait charg tout le XAML en faisant une re-
cherche partir du nom du contrle. Cela veut dire que nous disposons dune variable
qui permet daccder au contrle de la page, par exemple la variable Nom du type
TextBox. Je vais y revenir. Nous avons donc :
Un chier MainPage.xaml qui contient la description des contrles
Un chier gnr qui contient une classe partielle qui drive de
PhoneApplicationPage et qui charge ce XAML et qui rend accessible nos
contrles via des variables
Un chier de code behind qui contient la mme classe partielle o nous pourrons
crire la logique de notre code
Remarquez quil existe galement le chier MainPage.g.cs qui correspond au chier
gnr aprs la compilation. Nous ne nous occuperons plus de ces chiers gnrs, ils ne
servent plus rien. Nous les avons regards pour comprendre comment cela fonctionne.
Le code-behind en C#
Revenons sur le code behind, donc sur le chier MainPage.xaml.cs, nous avons :
1 public partial class MainPage : PhoneApplicationPage
37
CHAPITRE 3. NOTRE PREMIRE APPLICATION
2 {
3 // Constructeur
4 public MainPage ()
5 {
6 InitializeComponent ();
7 }
8
9 private void Button_Tap_1(object sender , System.Windows.
Input.GestureEventArgs e)
10 {
11 Resultat.Text = "Bonjour " + Nom.Text;
12 }
13 }
On retrouve bien notre classe partielle qui hrite des fonctionnalits de la classe
PhoneApplicationPage. Regardez lintrieur de la mthode Button_Tap_1, nous
utilisons les fameuses variables que nous navons pas dclar nous-mme mais qui ont
t gnres. . . Ce sont ces variables qui nous permettent de manipuler nos contrles
et en loccurrence ici, qui nous permettent de modier la valeur de la zone de texte
non modiable en concatnant la chane Bonjour la valeur de la zone de texte
modiable, accessible via sa proprit Text.
Vous aurez compris ici que ce sont les proprits Text des TextBlock et TextBox qui
nous permettent daccder au contenu qui est ach sur la page. Il existe plein dautres
proprits pour ces contrles comme la proprit Foreground qui permet de modier
la couleur du contrle, sauf quici nous lavions positionn grce au XAML :
1 <TextBlock x:Name="Resultat" Foreground="Red" />
Chose que nous aurions galement pu faire depuis le code behind :
1 private void Button_Tap_1(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 Resultat.Foreground = new SolidColorBrush(Colors.Red);
4 Resultat.Text = "Bonjour " + Nom.Text;
5 }
Sachez quand mme que dune manire gnrale, on aura tendance essayer de mettre
le plus de chose possible dans le XAML plutt que dans le code behind. La proprit
Foreground ici a tout intrt tre dclare dans le XAML.
Le contrle Grid
Je vais y revenir plus loin un peu plus loin, mais pour que vous ne soyez pas compl-
tement perdu dans notre Hello World, il faut savoir que la Grid est un conteneur.
38
LE CONTRLE STACKPANEL
<mode bilingue = on>Vous aurez compris que la Grid est en fait une
grille. . .<mode bilingue = o >
Aprs cet eort de traduction intense, nous pouvons dire que la grille sert contenir
et agencer dautres contrles. Dans notre cas, le code suivant :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
8 <TextBlock Text="MON APPLICATION" Style="{
StaticResource PhoneTextNormalStyle}" Margin="12,0"
/>
9 <TextBlock Text="Hello World" Margin="9,-7,0,0" Style="
{StaticResource PhoneTextTitle1Style}"/>
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0"
>
13 <StackPanel >
14 <TextBlock Text="Saisir votre nom"
HorizontalAlignment="Center" />
15 <TextBox x:Name="Nom" />
16 <Button Content="Valider" Tap="Button_Tap_1" />
17 <TextBlock x:Name="Resultat" Foreground="Red" />
18 </StackPanel >
19 </Grid >
20 </Grid >
Dni une grille qui contient deux lignes. La premire contient un contrle StackPanel,
nous allons en parler juste aprs. La seconde ligne contient une nouvelle grille sans ligne
ni colonne, qui est galement compose dun StackPanel. Nous aurons loccasion den
parler plus longuement plus tard donc je marrte l pour linstant sur la grille.
Le contrle StackPanel
Ici cest pareil, le contrle StackPanel est galement un conteneur. Je vais y revenir un
peu plus loin galement mais il permet ici daligner les contrles les uns en dessous des
autres. Par exemple, celui que nous avons rajout contient un TextBlock, un TextBox,
un bouton et un autre TextBlock :
1 <StackPanel >
2 <TextBlock Text="Saisir votre nom" HorizontalAlignment="
Center" />
39
CHAPITRE 3. NOTRE PREMIRE APPLICATION
3 <TextBox x:Name="Nom" />
4 <Button Content="Valider" Tap="Button_Tap_1" />
5 <TextBlock x:Name="Resultat" Foreground="Red" />
6 </StackPanel >
Nous pouvons voir sur le designer que les contrles sont bien les uns en dessous des
autres. Nous avons donc au nal, la page qui contient une grille, qui contient un
StackPanel et une grille qui contiennent chacun des contrles.
Le contrle TextBox
Le contrle TextBox est une zone de texte modiable. Nous lavons utilise pour saisir
le prnom de lutilisateur. On dclare ce contrle ainsi :
1 <TextBox x:Name="Nom" />
Lorsque nous cliquons dans la zone de texte, le clavier virtuel apparait et nous ore
la possibilit de saisir une valeur. Nous verrons un peu plus loin quil est possible de
changer le type du clavier virtuel. La valeur saisie est rcupre via la proprit Text
du contrle, par exemple ici je rcupre la valeur saisie que je concatne la chane
Bonjour et que je stocke dans la variable resultat :
1 string resultat = "Bonjour " + Nom.Text;
Inversement, je peux pr-remplir la zone de texte avec une valeur en utilisant la pro-
prit Text, par exemple depuis le XAML :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0">
2 <StackPanel >
3 <TextBox x:Name="Nom" Text="Nicolas" />
4 </StackPanel >
5 </Grid >
Ce qui donne la gure 3.7.
La mme chose est faisable en code behind, il sut dinitialiser la proprit de la
variable dans le constructeur de la page :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6 Nom.Text = "Nicolas";
7 }
8 }
videmment, il sera toujours possible de modier la valeur pr-remplie grce au clavier
virtuel.
40
LE CONTRLE TEXTBLOCK
Figure 3.7 La valeur du TextBox sache dans la fentre de rendu
Le contrle TextBlock
Le contrle TextBlock reprsente une zone de texte non modiable. Nous lavons utilis
pour acher le rsultat de notre Hello World. Il sut dutiliser sa proprit Text pour
acher un texte. Par exemple, le XAML suivant :
1 <TextBlock Text="Je suis un texte non modifiable de couleur
rouge" Foreground="Red" FontSize="25" />
ache la fentre de prvisualisation prsente dans la gure 3.8.
Je peux modier la couleur du texte grce la proprit Foreground. Cest la mme
chose pour la taille du texte, modiable via la proprit FontSize. Nous pouvons
remarquer que le texte que jai saisi dpasse de lcran et que nous ne le voyons pas en
entier. Pour corriger a, jutilise la proprit TextWrapping que je positionne Wrap :
1 <TextBlock Text="Je suis un texte non modifiable de couleur
rouge" Foreground="Red" FontSize="25" TextWrapping="Wrap" />
Comme nous lavons dj fait, il est possible de modier la valeur dun TextBlock en
passant par le code-behind :
1 Resultat.Text = "Bonjour " + Nom.Text;
41
CHAPITRE 3. NOTRE PREMIRE APPLICATION
Figure 3.8 Le texte sache en rouge dans le TextBlock
Les vnements
Il sagit des vnements sur les contrles. Chaque contrle est capable de lever une srie
dvnements lorsque cela est opportun. Cest le cas par exemple du contrle bouton qui
est capable de lever un vnement lorsque nous tapotons dessus (ou que nous cliquons
avec la souris). Nous lavons vu dans lexemple du Hello World, il sut de dclarer une
mthode que lon associe lvnement, par exemple :
1 <Button Content="Valider" Tap="Button_Tap_1" />
qui permet de faire en sorte que la mthode Button_Tap_1 soit appele lors du clic sur
le bouton. Rappelez-vous, dans notre Hello World, nous avions la mthode suivante :
1 private void Button_Tap_1(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 Resultat.Text = "Bonjour " + Nom.Text;
4 }
Il est galement possible de sabonner un vnement via le code behind, il sut
davoir une variable de type bouton, pour cela donnons un nom un bouton :
1 <Button x:Name="UnBouton" Content="Cliquez -moi" />
Et dassocier une mthode lvnement de clic :
42
LES VNEMENTS
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6
7 UnBouton.Tap += UnBouton_Tap;
8 }
9
10 void UnBouton_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
11 {
12 throw new NotImplementedException ();
13 }
14 }
Il existe beaucoup dvnements de ce genre, par exemple la case cocher (CheckBox)
permet de sabonner lvnement qui est dclench lorsquon coche la case :
1 <CheckBox Content="Cochez -moi" Checked="CheckBox_Checked_1" />
Avec la mthode :
1 private void CheckBox_Checked_1(object sender , RoutedEventArgs
e)
2 {
3
4 }
Il existe normment dvnement sur les contrles, mais aussi sur la page, citons encore
par exemple lvnement qui permet dtre noti lors de la n du chargement de la
page :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 Loaded += MainPage_Loaded;
5 }
6
7 private void MainPage_Loaded(object sender , RoutedEventArgs e)
8 {
9 throw new NotImplementedException ();
10 }
Nous aurons loccasion de voir beaucoup dautres vnements tout au long de ce cours.
Remarquez que les vnements sont toujours construits de la mme faon. Le premier
paramtre est du type object et reprsente le contrle qui a dclench lvnement.
En loccurrence, dans lexemple suivant :
1 <Button Content="Valider" Tap="Button_Tap_1" />
Nous pouvons accder au contrle de cette faon :
43
CHAPITRE 3. NOTRE PREMIRE APPLICATION
1 private void Button_Tap_1(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 Button bouton = (Button)sender;
4 bouton.Content = "C'est valid !";
5 }
Le second paramtre est, quant lui, spcique au type dvnement et peut fournir
des informations complmentaires.
Le bouton
Revenons prsent rapidement sur le bouton, nous lavons vu il nest pas trs compliqu
utiliser. On utilise la proprit Content pour mettre du texte et il est capable de lever
un vnement lorsquon clique dessus, grce lvnement Tap. Le bouton possde
galement un vnement Click qui fait la mme chose et qui existe encore pour des
raisons de compatibilit avec Silverlight.
Prfrez cependant lvnement Tap qui est plus performant.
Il est galement possible de passer des paramtres un bouton. Pour un bouton tout
seul, ce nest pas toujours utile, mais dans certaines situations cela peut tre primordial.
Dans lexemple qui suit, jutilise deux boutons qui ont la mme mthode pour traiter
lvnement de clic sur le bouton :
1 <StackPanel >
2 <Button Content="Afficher" Tap="Button_Tap"
CommandParameter="Nicolas" />
3 <Button Content="Afficher" Tap="Button_Tap"
CommandParameter="Jrmie" />
4 <TextBlock x:Name="Resultat" Foreground="Red" />
5 </StackPanel >
Cest la proprit CommandParameter qui me permet de passer un paramtre. Je pour-
rais ensuite lutiliser dans mon code behind :
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 Button bouton = (Button)sender;
4 bouton.IsEnabled = false;
5 Resultat.Text = "Bonjour " + bouton.CommandParameter;
6 }
Jutilise ainsi le paramtre CommandParameter pour rcuprer le prnom de la personne
qui dire bonjour (voir la gure 3.9).
44
ET SILVERLIGHT DANS TOUT A?
Figure 3.9 Passage dun paramtre au bouton sachant dans lmulateur
Remarquez au passage lutilisation de la proprit IsEnabled qui permet dindiquer si
un contrle est activ ou pas. Si un bouton est dsactiv, il ne pourra pas tre cliqu.
Et Silverlight dans tout a ?
Vous avez remarqu que jai parl de Silverlight et de XAML. Quelle dirence ?
Pour bien comprendre, Silverlight tait utilis pour dvelopper avec les versions 7 de
Windows Phone. On utilise par contre le XAML/C# pour dvelopper pour la version
8. En fait, grosso modo cest la mme chose.
XAML est lvolution de Silverlight. Si vous avez des connaissances en Silverlight, vous
vous tes bien rendu compte que ce quon appelle aujourdhui XAML/C#, cest pareil.
Il sagit juste dun changement de vocabulaire an dunier les dveloppements utilisant
du code XAML pour dnir linterface dune application, quelle soit Windows Phone
ou Windows . . .
Ce qui est valable avec Silverlight lest aussi avec XAML/C#, et inversement propor-
tionnel.
45
CHAPITRE 3. NOTRE PREMIRE APPLICATION
En rsum
Le XAML permet de dcrire linterface de nos pages.
Le code behind permet dcrire le code C# de la logique de nos pages.
On utilise des contrles dans nos interfaces, comme le bouton ou la zone de
texte.
Les contrles sont des classes compltes qui savent sacher, se positionner ou
ragir des vnements utilisateurs, comme le clic sur un bouton.
46
Chapitre 4
Les contrles
Dicult :
Jusqu prsent nous avons vu peu de contrles, la zone de texte non modiable, la zone de
saisie modiable, le bouton. . . Il existe beaucoup de contrles disponibles dans les biblio-
thques de contrles XAML pour Windows Phone. Ceux-ci sont facilement visibles grce
la boite outils que lon retrouve gauche de lcran.
Voyons un peu ce quil y a autour de ces fameux contrles.
47
CHAPITRE 4. LES CONTRLES
Gnralits sur les contrles
Il y a plusieurs types de contrles, ceux-ci drivent tous dune classe de base
abstraite qui sappelle UIElement - http://msdn.microsoft.com/fr-fr/library/
system.windows.uielement(v=vs.95).aspx qui sert grer tout ce qui doit pou-
voir sacher et qui est capable de ragir une interaction simple de lutilisa-
teur. Mais la classe UIElement ne fait pas grand-chose sans la classe abstraite
drive FrameworkElement - http://msdn.microsoft.com/fr-fr/library/system.
windows.frameworkelement(v=vs.95).aspx qui fournit tous les composants de base
pour les objets qui doivent sacher sur une page. Cest cette classe galement qui
gre toute la liaison de donnes que nous dcouvrirons un peu plus tard. Cest donc
de cette classe que drivent deux grandes familles de contrles : les contrles propre-
ment parler et les panneaux. Les panneaux drivent de la classe abstraite de base
Panel - http://msdn.microsoft.com/fr-fr/library/system.windows.controls.
panel(v=vs.95).aspx et servent comme conteneurs permettant de grer le placement
des contrles. Nous allons y revenir dans un prochain chapitre. Les contrles drivent de
la classe abstraite Control - http://msdn.microsoft.com/fr-fr/library/system.
windows.controls.control(v=vs.95).aspx. Elle sert de classe de base pour tous les
lments qui utilisent un modle pour dnir leur apparence. Nous y reviendrons plus
tard, mais une des grandes forces du XAML est dorir la possibilit de changer lap-
parence dun contrle, tout en conservant ses fonctionnalits. Les contrles qui hritent
de la classe Control peuvent se rpartir en trois grandes catgories.
Ceux qui drivent de la classe ContentControl - http://msdn.microsoft.com/
fr-fr/library/system.windows.controls.contentcontrol(v=vs.95).aspx
et qui permettent de contenir dautres objets. Cest le cas du bouton par exemple,
nous y reviendrons.
Il y a galement les contrles qui drivent de la classe ItemsControl
- http://msdn.microsoft.com/fr-fr/library/system.windows.controls.
itemscontrol(v=vs.95).aspx, qui servent acher une liste dlments, cest
le cas de la ListBox par exemple, nous ltudierons plus loin.
Et enn, il reste les contrles qui drivent directement de la classe Control, qui
ne contiennent pas dautres contrles ou qui nachent pas de liste dlments,
comme par exemple le TextBlock ou le TextBox que nous avons vu.
Pour schmatiser, nous pouvons observer ce schma (incomplet) la gure 4.1.
Une dernire remarque avant de terminer, sur lutilisation des proprits. Nous avons
vu lcriture suivante pour par exemple modier la valeur de la proprit Text du
contrle TextBlock :
1 <TextBlock Text="Hello world" />
Il est galement possible dcrire la proprit Text de cette faon :
1 <TextBlock >
2 <TextBlock.Text >
3 Hello world
4 </TextBlock.Text >
5 </TextBlock >
48
UTILISER LE DESIGNER POUR AJOUTER UN CHECKBOX
Figure 4.1 Hirarchie de classe pour les contrles
Cette criture nous sera trs utile lorsque nous aurons besoin de mettre des choses plus
complexes que des chanes de caractres dans nos proprits. Nous y reviendrons. Enn,
une proprit possde gnralement une valeur par dfaut. Cest pour cela que notre
TextBox sait sacher mme si on ne lui prcise que sa proprit Text, elle possde
une couleur dcriture par dfaut, une taille dcriture par dfaut, etc.
Utiliser le designer pour ajouter un CheckBox
Revenons notre boite outils remplie de contrle. Elle se trouve gauche de lcran,
ainsi que vous pouvez le voir sur la gure 4.2.
Grce au designer, vous pouvez faire glisser un contrle de la bote outils dans le
rendu de la page. Celui-ci se positionnera automatiquement.
Prenons par exemple le contrle de case cocher que nous avons entre-aperu un peu
plus tt : CheckBox. Slectionnez-le et faites le glisser sur le rendu de la page (voir la
gure 4.3).
Le designer ma automatiquement gnr le code XAML correspondant :
1 <CheckBox Content="CheckBox" HorizontalAlignment="Left" Margin=
"168 ,167 ,0,0" VerticalAlignment="Top"/>
Vous aurez srement des valeurs lgrement direntes, notamment au niveau de la
proprit Margin. Cest dailleurs en utilisant ces valeurs que le designer a pu me
positionner le contrle dans la grille. Remarquons que si javais fait glisser un Canvas
et ensuite la case cocher dans ce Canvas, jaurais plutt eu du code comme le suivant :
1 <Canvas HorizontalAlignment="Left" Height="100" Margin="102 ,125
,0,0" VerticalAlignment="Top" Width="100">
49
CHAPITRE 4. LES CONTRLES
Figure 4.2 La bote outils des contrles dans Visual Studio
50
UTILISER LE DESIGNER POUR AJOUTER UN CHECKBOX
Figure 4.3 Ajout dun contrle CheckBox partir du designer
2 <CheckBox Content="CheckBox" Canvas.Left="56" Canvas.Top="
40"/>
3 </Canvas >
Ici, il a utilis la proprit Canvas.Top et Canvas.Left pour positionner la case
cocher. Nous allons revenir sur ce positionnement un peu plus loin.
Il est possible de modier les proprits de la case cocher, par exemple son contenu,
en allant dans la fentre de Proprits (voir la gure 4.4).
Si la fentre de proprits nest pas ache, vous pouvez la faire apparaitre
en allant dans le menu Affichage, Fentre proprits.
Ici, je change la valeur de la proprit Content. Je peux observer les modications sur
le rendu et dans le XAML. Remarquons que le designer est un outil utile pour crer
son rendu, par contre il ne remplace pas une bonne connaissance du XAML an de
grer correctement le positionnement.
51
CHAPITRE 4. LES CONTRLES
Figure 4.4 Modication des proprits dun contrle partir de la fentre des pro-
prits
Utiliser Expression Blend pour ajouter un ToggleBut-
ton
Jaurais aussi pu faire la mme chose dans Expression Blend qui est loutil de design
professionnel. Jai galement accs la bote outils (voir la gure 4.5).
Et de la mme faon, je peux faire glisser un contrle, disons le ToggleButton, sur
ma page. Jai galement accs ses proprits an de les modier. Ici, par exemple, je
modie la couleur du ToggleButton (voir la gure 4.6).
Une fois revenu dans Visual Studio, je peux voir les modications apportes depuis
Blend, avec par exemple dans mon cas :
1 <ToggleButton Content="ToggleButton" HorizontalAlignment="Left"
Margin="111 ,169 ,0,0" VerticalAlignment="Top" Background="#
FFF71616" BorderBrush="#FF2DC50C"/>
Nous reviendrons sur Blend tout au long de ce cours.
En rsum
Il existe tout une hirarchie des contrles utilisables dans nos pages.
Les contrles sont accessibles depuis la barre doutils de Visual Studio ou dans
expression blend.
52
UTILISER EXPRESSION BLEND POUR AJOUTER UN TOGGLEBUTTON
Figure 4.5 Barre doutils des contrles dans Blend
Figure 4.6 Modication des couleurs du ToggleButton dans Blend
53
CHAPITRE 4. LES CONTRLES
Le designer de Visual Studio et celui de Blend peuvent nous faciliter la tche
dans le design de nos applications.
54
Chapitre 5
Le clavier virtuel
Dicult :
Le clavier virtuel est ce petit clavier qui apparat lorsque lon clique dans une zone de texte
modiable, que nous avons pu voir dans notre Hello World. En anglais il se nomme le SIP,
pour Soft Input Panel, que lon traduit par clavier virtuel. Nous allons voir comment nous
en servir.
55
CHAPITRE 5. LE CLAVIER VIRTUEL
Acher le clavier virtuel
Vous vous rappelez de notre Hello World? Lorsque nous avons cliqu dans le TextBox,
nous avons vu apparatre ce fameux clavier virtuel (voir la gure 5.1).
Figure 5.1 Achage du clavier virtuel
Il ny a quune seule solution pour acher le clavier virtuel. Il faut que lutilisateur
clique dans une zone de texte modiable. Et ce moment-l, le clavier virtuel apparat
en bas de lcran. Techniquement, il sache quand le contrle TextBox prend le focus
(lorsque lon clique dans le contrle) et il disparat lorsque celui-ci perd le focus (lors-
quon clique en dehors du contrle). Il nest pas possible de dclencher son achage
par programmation, ni son masquage, part en manipulant le focus. Pour acher un
TextBox, on utilisera le XAML suivant :
1 <TextBox x:Name="MonTextBox" />
Intercepter les touches du clavier virtuel
Comme dj dit, il nest pas possible de manipuler le clavier. Par contre, on peut savoir
quand une touche est appuye en utilisant lvnement KeyDown ou KeyUp du TextBox.
Il sagit dvnements qui sont levs lorsquon appuie sur une touche ou lorsquon
relche la touche. Prenons par exemple le code suivant :
56
LES DIFFRENTS TYPES DE CLAVIER
1 <StackPanel >
2 <TextBox x:Name="MonTextBox" KeyDown="MonTextBox_KeyDown"
KeyUp="MonTextBox_KeyUp" />
3 <TextBlock x:Name="Statut" />
4 </StackPanel >
Et le code behind :
1 private void MonTextBox_KeyDown(object sender , KeyEventArgs e)
2 {
3 Statut.Text = "Touche appuye : " + e.Key;
4 }
5
6 private void MonTextBox_KeyUp(object sender , KeyEventArgs e)
7 {
8 Statut.Text = "Touche relache : " + e.Key;
9 }
Nous aurons la gure 5.2.
Figure 5.2 Achage de la touche relache dans lmulateur
Les dirents types de clavier
Le clavier que nous avons vu est le clavier par dfaut. Nous avons notre disposition
dautres types de clavier, par exemple un clavier numrique permettant de saisir des
57
CHAPITRE 5. LE CLAVIER VIRTUEL
numros de tlphone (voir la gure 5.3).
Figure 5.3 Clavier virtuel de type numrique
Pour choisir le type de clavier acher, nous allons utiliser la proprit InputScope
du contrle TextBox. Par exemple, pour acher le clavier numrique, je vais utiliser :
1 <TextBox x:Name="MonTextBox" InputScope="Number" />
La liste des dirents claviers supports est disponible ici - http://msdn.microsoft.
com/fr-fr/library/system.windows.input.inputscopenamevalue.aspx.
Cela permet davoir un clavier plus adapt, si lon doit par exemple permettre de saisir
un @ pour un email, ou des caractres spciaux, etc. Sur la gure 5.4, vous pouvez
voir un clavier optimis pour la saisie dun email (type EmailUserName), avec un
arrobas (@) et un .fr .
En rsum
Le clavier virtuel sache lorsque lon clique dans une zone de texte modiable.
Il existe plusieurs types de clavier notre disposition que nous pouvons choisir
grce la proprit InputScope.
58
LES DIFFRENTS TYPES DE CLAVIER
Figure 5.4 Clavier virtuel optimis pour la saisie dadresse email
59
CHAPITRE 5. LE CLAVIER VIRTUEL
60
Chapitre 6
Les conteneurs et le placement
Dicult :
Dans notre Hello World, lorsque nous avons parl du contrle TextBlock, nous avons dit
quil faisait partie du contrle StackPanel qui lui-mme faisait partie du contrle Grid. Ces
deux contrles sont en fait des conteneurs de contrles dont lobjectif est de regrouper des
contrles de direntes faons.
Les contrles conteneurs vont tre trs utiles pour organiser le look et lagencement de nos
pages. Il y en a quelques uns indispensables dcouvrir qui vont constamment vous servir
lors des vos dveloppements. Nous allons prsent les dcouvrir et voir comment nous en
servir.
61
CHAPITRE 6. LES CONTENEURS ET LE PLACEMENT
StackPanel
Le StackPanel par exemple, comme son nom peut le suggrer, permet dempiler les
contrles les uns la suite des autres. Dans lexemple suivant, les contrles sont ajouts
les uns en-dessous des autres :
1 <StackPanel >
2 <TextBlock Text="Bonjour tous" />
3 <Button Content="Cliquez -moi" />
4 <Image Source="http ://open -e-education -2013.openclassrooms.
com/img/logos/logo -openclassrooms.png" />
5 </StackPanel >
Ce qui donne la gure 6.1.
Figure 6.1 Empilement vertical des contrles grce au StackPanel
O nous achons un texte, un bouton et une image. Nous verrons un peu plus prci-
sment le contrle Image dans le chapitre suivant.
Notons au passage que Visual Studio et lmulateur peuvent trs facilement rcuprer
des contenus sur internet, sauf si vous utilisez un proxy. Ici par exemple, en utilisant
lURL dune image, je peux lacher sans problme dans mon application, si celle-ci
est connecte internet bien sr.
Le contrle StackPanel peut aussi empiler les contrles horizontalement. Pour cela, il
sut de changer la valeur dune de ses proprits :
62
STACKPANEL
1 <StackPanel Orientation="Horizontal">
2 <TextBlock Text="Bonjour tous" />
3 <Button Content="Cliquez -moi" />
4 <Image Source="http ://open -e-education -2013.openclassrooms.
com/img/logos/logo -openclassrooms.png" />
5 </StackPanel >
Ici, nous avons chang lorientation de lempilement pour la mettre en horizontal. Ce
qui donne la gure 6.2.
Figure 6.2 Empilement horizontal des contrles
Ce qui ne rend pas trs bien ici. . . Pour lamliorer, nous pouvons ajouter dautres
proprits nos contrles, notamment les rduire en hauteur ou en largeur grce aux
proprits Height ou Width. Par exemple :
1 <StackPanel Orientation="Horizontal" Height="40">
2 <TextBlock Text="Bonjour tous" />
3 <Button Content="Cliquez -moi" />
4 <Image Source="http ://open -e-education -2013.openclassrooms.
com/img/logos/logo -openclassrooms.png" />
5 </StackPanel >
Ici, jai rajout une hauteur pour le contrle StackPanel, en xant la proprit Height
40 pixels, ce qui fait que tous les sous-contrles se sont adapts cette hauteur. Nous
aurons donc la gure 6.3.
63
CHAPITRE 6. LES CONTENEURS ET LE PLACEMENT
Figure 6.3 Les contrles ont la taille xe 40 pixels
Par dfaut, le contrle StackPanel essaie doccuper le maximum de place disponible
dans la grille dont il fait partie. Comme nous avons forc la hauteur, le StackPanel
va alors se centrer. Il est possible daligner le StackPanel en haut grce la proprit
VerticalAlignment :
1 <StackPanel Orientation="Horizontal" Height="40"
VerticalAlignment="Top">
2 <TextBlock Text="Bonjour tous" />
3 <Button Content="Cliquez -moi" />
4 <Image Source="http ://open -e-education -2013.openclassrooms.
com/img/logos/logo -openclassrooms.png" />
5 </StackPanel >
Ce qui donne la gure 6.4.
Nous allons revenir sur lalignement un peu plus loin. Voil pour ce petit tour du
StackPanel !
ScrollViewer
Il existe dautres conteneurs, voyons par exemple le ScrollViewer. Il nous sert rendre
accessible des contrles qui pourraient tre masqus par un cran trop petit. Prenons
par exemple ce code XAML :
64
SCROLLVIEWER
Figure 6.4 Alignement vertical en haut du StackPanel
1 <ScrollViewer >
2 <StackPanel >
3 <TextBlock Text="Bonjour tous 1" Margin="40" />
4 <TextBlock Text="Bonjour tous 2" Margin="40" />
5 <TextBlock Text="Bonjour tous 3" Margin="40" />
6 <TextBlock Text="Bonjour tous 4" Margin="40" />
7 <TextBlock Text="Bonjour tous 5" Margin="40" />
8 <TextBlock Text="Bonjour tous 6" Margin="40" />
9 <TextBlock Text="Bonjour tous 7" Margin="40" />
10 </StackPanel >
11 </ScrollViewer >
Nous crons 7 contrles TextBlock, contenant une petite phrase, qui doivent se mettre
les uns en-dessous des autres. Vous aurez devin que la proprit Margin permet de
dnir une marge autour du contrle, jy reviendrai. Si nous regardons le rsultat, nous
pouvons constater quil nous manque un TextBlock (voir la gure 6.5).
Vous vous en doutez, il sache trop bas et nous ne pouvons pas le voir sur lcran car
il y a trop de choses. Le ScrollViewer va nous permettre de rsoudre ce problme. Ce
contrle gre une espce de dlement, comme lorsque nous avons un ascenseur dans
nos pages web. Ce qui fait quil sera possible de naviguer de haut en bas sur notre
mulateur en cliquant sur lcran et en maintenant le clic tout en bougeant la souris
de haut en bas (voir la gure 6.6).
65
CHAPITRE 6. LES CONTENEURS ET LE PLACEMENT
Figure 6.5 Il manque un contrle lcran
Figure 6.6 Le ScrollViewer permet de faire dler lcran
66
GRID
Vous pouvez galement vous amuser faire dler le ScrollViewer horizontalement,
mais il vous faudra changer une proprit :
1 <ScrollViewer HorizontalScrollBarVisibility="Auto">
2 <StackPanel Orientation="Horizontal">
3 ...
Grid
Parlons prsent du contrle Grid. Cest un contrle trs utilis qui va permettre
de positionner dautres contrles dans une grille. Une grille peut tre dnie par des
colonnes et des lignes. Il sera alors possible dindiquer dans quelle colonne ou quelle
ligne se positionne un contrle. Par exemple, avec le code suivant :
1 <Grid >
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*" />
4 <RowDefinition Height="*" />
5 <RowDefinition Height="*" />
6 </Grid.RowDefinitions >
7 <Grid.ColumnDefinitions >
8 <ColumnDefinition Width="*" />
9 <ColumnDefinition Width="*" />
10 <ColumnDefinition Width="*" />
11 </Grid.ColumnDefinitions >
12 <TextBlock Text="O" FontSize="50" Grid.Row="0" Grid.Column=
"0" HorizontalAlignment="Center" VerticalAlignment="
Center" />
13 <TextBlock Text="O" FontSize="50" Grid.Row="0" Grid.Column=
"1" HorizontalAlignment="Center" VerticalAlignment="
Center" />
14 <TextBlock Text="O" FontSize="50" Grid.Row="0" Grid.Column=
"2" HorizontalAlignment="Center" VerticalAlignment="
Center" />
15 <TextBlock Text="X" FontSize="50" Grid.Row="1" Grid.Column=
"0" HorizontalAlignment="Center" VerticalAlignment="
Center" />
16 <TextBlock Text="O" FontSize="50" Grid.Row="1" Grid.Column=
"1" HorizontalAlignment="Center" VerticalAlignment="
Center" />
17 <TextBlock Text="X" FontSize="50" Grid.Row="1" Grid.Column=
"2" HorizontalAlignment="Center" VerticalAlignment="
Center" />
18 <TextBlock Text="O" FontSize="50" Grid.Row="2" Grid.Column=
"0" HorizontalAlignment="Center" VerticalAlignment="
Center" />
19 <TextBlock Text="X" FontSize="50" Grid.Row="2" Grid.Column=
"1" HorizontalAlignment="Center" VerticalAlignment="
Center" />
67
CHAPITRE 6. LES CONTENEURS ET LE PLACEMENT
20 <TextBlock Text="X" FontSize="50" Grid.Row="2" Grid.Column=
"2" HorizontalAlignment="Center" VerticalAlignment="
Center" />
21 </Grid >
Je dnis une grille compose de 3 lignes sur 3 colonnes. Dans chaque case je pose un
TextBlock avec une valeur qui me simule un jeu de morpion. Ce quil est important de
remarquer ici cest que je dnis le nombre de colonnes grce ColumnDefinition :
1 <Grid.ColumnDefinitions >
2 <ColumnDefinition Width="*" />
3 <ColumnDefinition Width="*" />
4 <ColumnDefinition Width="*" />
5 </Grid.ColumnDefinitions >
De la mme faon, je dnis le nombre de lignes grce RowDefinition :
1 <Grid.RowDefinitions >
2 <RowDefinition Height="*" />
3 <RowDefinition Height="*" />
4 <RowDefinition Height="*" />
5 </Grid.RowDefinitions >
Il y a donc 3 colonnes et 3 lignes. Chaque colonne a une largeur dun tiers de lcran.
Chaque ligne a une hauteur dun tiers de lcran. Je vais y revenir juste aprs. Pour in-
diquer quun contrle est la ligne 1 de la colonne 2, jutiliserai les proprits Grid.Row
et Grid.Column avec les valeurs 1 et 2. ( noter quon commence numroter partir
de 0, classiquement). Ce qui donnera la gure 6.7.
Pratique non ? Nous pouvons voir aussi que dans la dnition dune ligne, nous po-
sitionnons la proprit Height. Cest ici que nous indiquerons la hauteur de chaque
ligne. Cest la mme chose pour la largeur des colonnes, cela se fait avec la proprit
Width sur chaque ColomnDefinition.
Ainsi, en utilisant ltoile, nous avons dit que nous voulions que le XAML soccupe de
rpartir toute la place disponible. Il y a trois toiles, chaque ligne et colonne a donc
un tiers de la place pour sacher. Dautres valeurs sont possibles. Il est par exemple
possible de forcer la taille une valeur prcise. Par exemple, si je modie lexemple
prcdent pour avoir :
1 <Grid.RowDefinitions >
2 <RowDefinition Height="*" />
3 <RowDefinition Height="200" />
4 <RowDefinition Height="*" />
5 </Grid.RowDefinitions >
6 <Grid.ColumnDefinitions >
7 <ColumnDefinition Width="100" />
8 <ColumnDefinition Width="*" />
9 <ColumnDefinition Width="50" />
10 </Grid.ColumnDefinitions >
68
GRID
Figure 6.7 Une grille de 3x3
Jindiquerai ici que la premire colonne aura une taille xe de 100, la troisime une
taille xe de 50 et la deuxime prendra la taille restante. De la mme faon, pour les
lignes, la deuxime est force 200 et les deux autres se rpartiront la taille restante,
savoir la moiti chacune.
Jen prote pour vous rappeler quun tlphone Windows Phone 7.5 a une rsolution
de 480 en largeur et de 800 en hauteur et quun tlphone Windows Phone 8 possde
trois rsolutions :
WVGA (800x480 pixels), comme Windows Phone 7.5
WXVGA (1280x768)
True 720p (1280x720)
Ainsi, sur un tlphone en WVGA la deuxime colonne aura une taille de 480 100
50 = 330. Ce qui donne une grille plutt disgracieuse, mais tant donn que chaque
contrle est align au centre, cela ne se verra pas trop. Pour bien le mettre en valeur, il
est possible de rajouter une proprit la grille lui indiquant que nous souhaitons voir
les lignes. Bien souvent, cette proprit ne servira qu des ns de dbogages. Il sut
dindiquer :
1 <Grid ShowGridLines="True">
Par contre, les lignes sachent uniquement dans lmulateur car le designer montre
dj ce que a donne (voir la gure 6.8).
69
CHAPITRE 6. LES CONTENEURS ET LE PLACEMENT
Figure 6.8 Achage des lignes de la grille
Il est bien sr possible de faire en sorte quun contrle stende sur plusieurs colonnes
ou sur plusieurs lignes, ce moment-l, on utilisera la proprit Grid.ColumnSpan ou
Grid.RowSpan pour indiquer le nombre de colonnes ou lignes que lon doit fusionner.
Par exemple :
1 <TextBlock Text="X" FontSize="50" Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Center" VerticalAlignment="Center" Grid
.ColumnSpan="3" />
la place de :
1 <TextBlock Text="X" FontSize="50" Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Center" VerticalAlignment="Center" />
2 <TextBlock Text="O" FontSize="50" Grid.Row="1" Grid.Column="1"
HorizontalAlignment="Center" VerticalAlignment="Center" />
3 <TextBlock Text="X" FontSize="50" Grid.Row="1" Grid.Column="2"
HorizontalAlignment="Center" VerticalAlignment="Center" />
Et nous avons donc la gure 6.9.
Avant de terminer sur les lignes et les colonnes, il est important de savoir quil existe une
autre valeur pour dnir la largeur ou la hauteur, savoir la valeur Auto. Elle permet
de dire que cest la largeur ou la hauteur des contrles qui vont dnir la hauteur dune
ligne ou dune colonne. Remarquez que par dfaut, un contrle sachera la ligne 0
et la colonne 0 tant que son Grid.Row ou son Grid.Column nest pas dni. Ainsi la
ligne suivante :
70
CANVAS
Figure 6.9 Une grille avec une case stirant sur 3 colonnes
1 <TextBlock Text="X" FontSize="50" Grid.Row="0" Grid.Column="0"
/>
est quivalente celle-ci :
1 <TextBlock Text="X" FontSize="50" />
Voil pour ce petit tour de ce contrle si pratique quest la grille.
Canvas
Nous nirons notre aperu des conteneurs avec le Canvas. Au contraire des autres
conteneurs qui calculent eux mme la position des contrles, ici cest le dveloppeur qui
indique lemplacement dun contrle, de manire relative la position du Canvas. De
plus le Canvas ne calculera pas automatiquement sa hauteur et sa largeur en analysant
ses enfants, contrairement aux autres conteneurs. Ainsi si on met dans un StackPanel
un Canvas suivi dun bouton, le bouton sera ach par-dessus le Canvas, car ce dernier
aura une hauteur de 0 bien quil possde des enfants. Ainsi, lexemple suivant :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <Canvas >
3 <TextBlock Text="Je suis en bas gauche" Canvas.Top="
500" />
71
CHAPITRE 6. LES CONTENEURS ET LE PLACEMENT
4 <TextBlock Text="Je suis en haut droite" Canvas.Left=
"250" Canvas.Top="10"/>
5 </Canvas >
6 </Grid >
achera la gure 6.10.
Figure 6.10 Positionnement absolu avec le Canvas
Nous nous servons des proprits Canvas.Top et Canvas.Left pour indiquer la position
du contrle relativement au Canvas.
Cest sans doute le conteneur qui permet le placement le plus simple comprendre, par
contre ce nest pas forcment le plus ecace, surtout pour sadapter plusieurs rsolu-
tions ou lorsque nous retournerons lcran. Jen parlerai un peu plus loin. Remarquons
quune page doit absolument commencer par avoir un conteneur comme contrle racine
de tous les autres contrles. Cest ce que gnre par dfaut Visual Studio lorsquon cre
une nouvelle page. Il y met en loccurrence un contrle Grid.
Alignement
Lalignement permet de dnir comment est align un contrle par rapport son
contenant, en gnral un panneau. Il existe plusieurs valeurs pour cette proprit :
Stretch (tir) qui est la valeur par dfaut
Left (gauche)
72
MARGES ET ESPACEMENT
Right (droite)
Center (centre)
Ainsi le code XAML suivant :
1 <Grid >
2 <TextBlock Text="Gauche -Haut" HorizontalAlignment="Left"
VerticalAlignment="Top" />
3 <TextBlock Text="Centre -Haut" HorizontalAlignment="Center"
VerticalAlignment="Top" />
4 <TextBlock Text="Droite -Haut" HorizontalAlignment="Right"
VerticalAlignment="Top" />
5 <TextBlock Text="Gauche -Centre" HorizontalAlignment="Left"
VerticalAlignment="Center" />
6 <TextBlock Text="Centre -Centre" HorizontalAlignment="Center
" VerticalAlignment="Center" />
7 <TextBlock Text="Droite -Centre" HorizontalAlignment="Right"
VerticalAlignment="Center" />
8 <TextBlock Text="Gauche -Bas" HorizontalAlignment="Left"
VerticalAlignment="Bottom" />
9 <TextBlock Text="Centre -Bas" HorizontalAlignment="Center"
VerticalAlignment="Bottom" />
10 <TextBlock Text="Droite -Bas" HorizontalAlignment="Right"
VerticalAlignment="Bottom" />
11 </Grid >
produira le rsultat que vous pouvez voir la gure 6.11.
Lorsquon utilise la valeur Stretch, les valeurs des proprits Width et Height peuvent
annuler leet de ltirement. On peut voir cet eet avec le code suivant :
1 <Grid >
2 <Button Content="Etir en largeur" Height="100"
VerticalAlignment="Top" />
3 <Button Content="Etir en hauteur" Width="300"
HorizontalAlignment="Left" />
4 </Grid >
Qui nous donne la gure 6.12.
Bien sr, un bouton avec que du Stretch remplirait ici tout lcran.
Les proprits dalignements nont pas dimpact dans un Canvas.
Marges et espacement
Avant de terminer, je vais revenir rapidement sur les marges. Je les ai rapidement
voques tout lheure. Pour mieux les comprendre, regardons cet exemple :
73
CHAPITRE 6. LES CONTENEURS ET LE PLACEMENT
Figure 6.11 Les dirents alignements
Figure 6.12 Ltirement est annul par les proprits Height et Width
74
MARGES ET ESPACEMENT
1 <StackPanel >
2 <Rectangle Height="40" Fill="Yellow" />
3 <StackPanel Orientation="Horizontal">
4 <TextBlock Text="Mon texte" />
5 <Rectangle Width="100" Fill="Yellow" />
6 </StackPanel >
7 <Rectangle Height="40" Fill="Yellow" />
8 </StackPanel >
Il donne la gure 6.13.
Figure 6.13 Un TextBlock sans marge
En rajoutant une marge au TextBlock, nous pouvons voir concrtement se dcaler le
texte :
1 <TextBlock Text="Mon texte" Margin="50"/>
Qui donne la gure 6.14.
Figure 6.14 Une marge de 50 autour du TextBlock
En fait, la marge prcdente rajoute une marge de 50 gauche, en haut, droite et en
bas. Ce qui est lquivalent de :
1 <TextBlock Text="Mon texte" Margin="50 50 50 50"/>
75
CHAPITRE 6. LES CONTENEURS ET LE PLACEMENT
Il est tout fait possible de choisir de mettre des marges direntes pour, respective-
ment, la marge gauche, en haut, droite et en bas :
1 <TextBlock Text="Mon texte" Margin="0 10 270 100"/>
Qui donne la gure 6.15.
Figure 6.15 La marge peut tre de taille dirente en haut, en bas, gauche ou
droite du contrle
Bref, les marges aident positionner le contrle lemplacement voulu, trs utile pour
avoir un peu despace dans un StackPanel. Remarquez que nous avons aperu dans
ces exemples le contrle Rectangle qui permet, vous vous en doutez, de dessiner un
rectangle. Nous ltudierons un peu plus loin.
En rsum
Les conteurs contiennent des contrles et nous sont utiles pour les positionner
sur la page.
Chaque page doit possder un unique conteneur racine.
Les proprits dalignement, de marge et despacement nous permettent daner
nos positionnements dans les conteneurs.
76
Chapitre 7
Ajouter du style
Dicult :
Nous avons vu quon pouvait modier les couleurs, la taille de lcriture. . . grce la fentre
des proprits dun contrle. Cela modie les proprits des contrles et aecte leur rendu.
Cest trs bien. Mais imaginons que nous voulions changer les couleurs et lcriture de
plusieurs contrles, il va falloir reproduire ceci sur tous les contrles, ce qui dun coup est
plutt moins bien !
Cest l quintervient le style. Il correspond lidentication de plusieurs proprits par un
nom, que lon peut appliquer facilement plusieurs contrles.
77
CHAPITRE 7. AJOUTER DU STYLE
Acher des images
Pour commencer, nous allons reparler du contrle Image. Ce nest pas vraiment un style
proprement parler, mais il va tre trs utile pour rendre nos pages un peu plus jolies.
Nous lavons rapidement utilis en montrant quil tait trs simple dacher une image
prsente sur internet simplement en indiquant lURL de celle-ci. Il est galement trs
facile dacher des images nous, embarques dans lapplication. Pour cela, jutilise
une petite image toute bte, reprsentant un cercle rouge (voir la gure 7.1).
Figure 7.1 Un cercle rouge sur fond blanc
Pour suivre cet exemple avec moi, je vous conseille de tlcharger cette image, en
cliquant ici - http://uploads.siteduzero.com/files/410001_411000/410620.png.
Ajoutons donc cette image la solution. Pour cela, je vais commencer par crer un
nouveau rpertoire Images sous le rpertoire Assets qui a t ajout lors de la cration
de la solution. Ensuite, nous allons ajouter un lment existant en faisant un clic droit
sur le projet. Je slectionne limage qui sajoute automatiquement la solution.
Jai cr un rpertoire pour que mes images soient mieux ranges et pour
illustrer le chemin daccs de celles-ci, mais ce nest pas du tout une tape
obligatoire.
Ici, il faut faire attention ce que dans les proprits de limage, laction de gnration
soit Contenu, ce qui est le paramtre par dfaut pour les projets ciblant Windows
Phone 8, mais pas Windows Phone 7 o cest laction de gnration Resource qui est
le paramtre par dfaut. Contenu permet dindiquer que limage sera un chier part,
non intgre lassembly, nous y reviendrons la n de la partie (voir la gure 7.2).
Nous pourrons alors trs simplement acher limage en nous basant sur lURL relative
de limage dans la solution :
1 <Image x:Name="MonImage" Source="/Assets/Images/rond.png" Width
="60" Height="60" />
noter que cela peut aussi se faire grce au code behind. Pour cela, supprimons la
proprit Source du XAML :
1 <Image x:Name="MonImage" Width="60" Height="60" />
Et chargeons limage dans le code de cette faon :
1 MonImage.Source = new BitmapImage(new Uri("/Assets/Images/rond.
png", UriKind.Relative));
78
AFFICHER DES IMAGES
Figure 7.2 Limage doit avoir son action de gnration Contenu
79
CHAPITRE 7. AJOUTER DU STYLE
Remarque : pour utiliser la classe BitmapImage - http://msdn.microsoft.com/fr-fr/
library/system.windows.media.imaging.bitmapimage(v=vs.95).aspx, il faut ajou-
ter le using suivant :
1 using System.Windows.Media.Imaging;
Cela semble moins pratique, mais je vous lai prsent car nous utiliserons cette mthode
un petit peu plus loin. Dune manire gnrale, il sera toujours plus pertinent de passer
par le XAML que par le code !
Il nest pas possible dacher des images GIF dans ce contrle lorsquon
dveloppe pour Windows Phone 7.5, seuls les formats JPG et PNG sont
supports. Par contre, le GIF est utilisable pour des projets Windows Phone
8 mais ne sanime pas.
Les ressources
Les ressources sont un mcanisme de XAML qui permet de rutiliser facilement des
objets ou des valeurs. Chaque classe qui drive de FrameworkElement dispose dune
proprit Resources, qui est en fait un dictionnaire de ressources. Chaque contrle
peut donc avoir son propre dictionnaire de ressources mais en gnral, on dnit les
ressources soit au niveau de la page, soit au niveau de lapplication. Par exemple, pour
dnir une ressource au niveau de la page, nous utiliserons la syntaxe suivante :
1 <phone:PhoneApplicationPage
2 x:Class="HelloWorld.MainPage"
3 xmlns="http :// schemas.microsoft.com/winfx/2006/xaml/
presentation"
4 [... plein de choses ...]
5 shell:SystemTray.IsVisible="True">
6
7 <phone:PhoneApplicationPage.Resources >
8 <SolidColorBrush x:Key="BrushRouge" Color="Red"/>
9 </phone:PhoneApplicationPage.Resources >
10
11 <[... plein de choses dans la page ...]>
12 </phone:PhoneApplicationPage >
Ici, jai cr un objet SolidColorBrush - http://msdn.microsoft.com/fr-fr/library/
system.windows.media.solidcolorbrush(v=vs.95).aspx, qui sert peindre une zone
dune couleur unie, dont la couleur est Rouge dans les ressources de ma page. Il est
obligatoire quune ressource possde un nom, ici je lai nomm BrushRouge. Je vais
dsormais pouvoir utiliser cet objet avec des contrles, ce qui donne :
1 <StackPanel >
2 <TextBlock Text="Bonjour ma ressource" Foreground="{
StaticResource BrushRouge}" />
80
LES RESSOURCES
3 <Button Content="Cliquez -moi , je suis rouge" Foreground="{
StaticResource BrushRouge}" />
4 </StackPanel >
Et nous aurons la gure 7.3.
Figure 7.3 Utilisation dune ressource de type pinceau rouge
Alors, quy-a-t-il derrire ces ressources ?
La premire chose que lon peut voir cest la syntaxe particulire lintrieur de la
proprit ForeGround :
1 Foreground="{StaticResource BrushRouge}"
Des accolades avec le mot-cl StaticResource. . . Cela signie qu lexcution de lap-
plication, le moteur va aller chercher la ressource associe au nom BrushRouge et il va
la mettre dans la proprit Foreground de notre contrle.
On appelle la syntaxe entre accolades une extension de balisage XAML ,
en anglais : extension markup.
Ce moteur commence par chercher la ressource dans les ressources de la page et sil ne
la trouve pas, il ira chercher dans le dictionnaire de ressources de lapplication. Nous
avons positionn notre ressource dans la page, cest donc celle-ci quil utilise en premier.
81
CHAPITRE 7. AJOUTER DU STYLE
Remarquez que le dictionnaire de ressources, cest simplement une collection dobjets
associs un nom. Sil est dni dans la page, alors il sera accessible pour tous les
contrles de la page. Sil est dni au niveau de lapplication, alors il sera utilisable
partout dans lapplication. Vous aurez pu constater quici, notre principal intrt duti-
liser une ressource est de pouvoir changer la couleur de tous les contrles en une seule
fois.
Nous pouvons mettre nimporte quel objet dans les ressources. Nous y avons mis un
SolidColorBrush an que cela se voit, mais il est possible dy mettre un peu tout et
nimporte quoi. Pour illustrer ce point, nous allons utiliser le dictionnaire de ressource
de lapplication et y stocker une chane de caractre. Ouvrez donc le chier App.xaml o
se trouve le dictionnaire de ressources. Nous pouvons ajouter notre chane de caractres
dans la section <Application.Resources> dj existante pour avoir :
1 <Application.Resources >
2 <system:String x:Key="TitreApplication">Hello World </ system
:String >
3 </Application.Resources >
Dans le projet cr par dfaut pour Windows Phone 8, il y a dj une
ligne dans les ressources de lapplication : <local:LocalizedStrings
xmlns:local="clr-namespace:HelloWorld"
x:Key="LocalizedStrings"/> qui fait globalement la mme chose, sauf
que lobjet mis en ressource est une instance de la classe LocalizedStrings
qui se trouve la racine du projet.
Vous serez obligs de rajouter lespace de nom suivant en haut du chier App.xaml :
1 xmlns:system="clr -namespace:System;assembly=mscorlib"
dans les proprits de lapplication de manire avoir :
1 <Application
2 x:Class="HelloWorld.App"
3 xmlns="http :// schemas.microsoft.com/winfx/2006/xaml/
presentation"
4 xmlns:x="http :// schemas.microsoft.com/winfx/2006/xaml"
5 xmlns:phone="clr -namespace:Microsoft.Phone.Controls;
assembly=Microsoft.Phone"
6 xmlns:shell="clr -namespace:Microsoft.Phone.Shell;assembly=
Microsoft.Phone"
7 xmlns:system="clr -namespace:System;assembly=mscorlib">
Pourquoi ? Parce que la classe String nest pas connue de lapplication. Il faut lui
indiquer o elle se trouve, en indiquant son espace de nom, un peu comme un using
C#. Pour cela on utilise la syntaxe prcdente pour dire que lespace de nom que jai
nomm system correspondra lespace de nom System de lassembly mscorlib.
Pour utiliser ma classe String, il faudra que je la prxe de system : .
82
LES RESSOURCES
Bref, revenons notre ressource de type String. Je vais pouvoir lutiliser depuis nim-
porte quelle page vu quelle est dnie dans le dictionnaire de ressources de lapplica-
tion, par exemple dans ma page principale :
1 <TextBlock Text="{StaticResource TitreApplication}" Foreground=
"{StaticResource BrushRouge}" />
Et nous aurons donc la gure 7.4.
Figure 7.4 Utilisation dune ressource de type chane de caractre
Le chier App.xaml est lapplication ce que le chier Mainpage.xaml
est la page MainPage. Il est accompagn de son code behind
App.xaml.cs et on peut voir que la classe App drive de la classe Applica-
tion - http://msdn.microsoft.com/fr-fr/library/system.windows.
application(v=vs.95).aspx. Nous y reviendrons mais cest dans cette
classe que nous pourrons grer tout ce qui rapporte lapplication. Cest le
cas par exemple du dictionnaire de ressources, mais cest galement l que
nous pourrons grer les erreurs applicatives non interceptes dans le code et
plein dautres choses que nous dcouvrirons au fur et mesure.
83
CHAPITRE 7. AJOUTER DU STYLE
Les styles
Le style correspond lidentication de plusieurs proprits par un nom, que lon peut
appliquer facilement plusieurs contrles. Un style trouve donc tout fait naturelle-
ment sa place dans les dictionnaires de ressources que nous avons dj vus. Un style
est, comme une ressource, caractris par un nom et cible un type de contrle. Par
exemple, observons le style suivant :
1 <phone:PhoneApplicationPage.Resources >
2 <Style x:Key="StyleTexte" TargetType="TextBlock">
3 <Setter Property="Foreground" Value="Green" />
4 <Setter Property="FontSize" Value="35" />
5 <Setter Property="FontFamily" Value="Comic Sans MS" />
6 <Setter Property="Margin" Value="0 20 0 20" />
7 <Setter Property="HorizontalAlignment" Value="Center"
/>
8 </Style >
9 </phone:PhoneApplicationPage.Resources >
On remarque llment important TargetType="TextBlock" qui me permet dindiquer
que le style sapplique aux contrles TextBlock. La lecture du style nous renseigne sur
ce quil fait. Nous pouvons remarquer que la proprit Foreground aura la valeur Green,
que la proprit FontSize aura la valeur 35, etc. Pour que notre contrle bncie de
ce style, nous pourrons utiliser encore la syntaxe suivante :
1 <TextBlock Text="{StaticResource TitreApplication}" Style="{
StaticResource StyleTexte}"/>
Ce qui nous donnera la gure 7.5.
Ah, mais a me rappelle quelque chose, on na pas dj vu des styles ? Et si, lorsque
nous crons une nouvelle application, Visual Studio nous cr le squelette dune page
dans le chier MainPage.xaml et nous avons notamment le titre de la page dni de
cette faon :
1 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12 ,17,0,28
">
2 <TextBlock Text="MON APPLICATION" Style="{StaticResource
PhoneTextNormalStyle}" Margin="12 ,0"/>
3 <TextBlock Text="Hello World" Margin="9,-7,0,0" Style="{
StaticResource PhoneTextTitle1Style}"/>
4 </StackPanel >
Vous pouvez dsormais comprendre que ces deux TextBlock utilisent les styles
PhoneTextNormalStyle et PhoneTextTitle1Style. Ce ne sont pas des styles que nous
avons crs. Il sagit de styles systmes, prsents directement dans le systme dexploi-
tation et que nous pouvons utiliser comme bon nous semble.
Le style est un lment qui sera trs souvent utilis dans nos applications. Dnir le
XAML associ ces styles est un peu rbarbatif. Heureusement, Blend peut nous aider
dans la cration de style. . . Prenons par exemple le code XAML suivant :
84
LES STYLES
Figure 7.5 Le style appliqu au TextBlock
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <Grid.ColumnDefinitions >
3 <ColumnDefinition Width="*"/>
4 <ColumnDefinition Width="*"/>
5 </Grid.ColumnDefinitions >
6 <Grid.RowDefinitions >
7 <RowDefinition Height="auto"/>
8 <RowDefinition Height="auto"/>
9 <RowDefinition Height="auto"/>
10 </Grid.RowDefinitions >
11 <TextBlock Text="Nom" Grid.Column="0" Grid.Row="0" />
12 <TextBox Grid.Row="0" Grid.Column="1" />
13 <TextBlock Text="Prnom" Grid.Column="0" Grid.Row="1" />
14 <TextBox Grid.Row="1" Grid.Column="1" />
15 <TextBlock Text="Age" Grid.Column="0" Grid.Row="2" />
16 <TextBox Grid.Row="2" Grid.Column="1" />
17 </Grid >
Qui donne la gure 7.6.
Si nous passons dans Blend, nous pouvons facilement crer un style en faisant un clic
droit sur un TextBlock et en choisissant de modier le style, puis de crer un nouveau
style en choisissant de crer un lment vide (voir la gure 7.7).
85
CHAPITRE 7. AJOUTER DU STYLE
Figure 7.6 Aperu dun formulaire construit en XAML
Figure 7.7 Modication du style dans Blend
86
LES STYLES
Blend nous ouvre une nouvelle fentre o nous pouvons crer un nouveau style (voir
la gure 7.8).
Figure 7.8 Fentre de cration dun nouveau style
Nous devons fournir un nom au style puis nous pouvons indiquer quelle est la porte
du style, soit toute lapplication (ce que jai choisi), soit la page courante, soit un
dictionnaire de ressources dj existant.
Le style est cr dans le chier App.xaml, comme nous lavons dj vu, qui est le chier
de lancement de lapplication. Je peux aller modier les proprits du style, par exemple
la couleur (voir la gure 7.9).
Figure 7.9 Modication de la couleur du style
Une fois le style termin, je peux retourner dans ma page pour appliquer ce style aux
autres contrles. Pour cela, jutilise le bouton droit sur le contrle, Modifier le style
, Appliquer la ressource, et je peux retrouver mon style tout en haut (voir la gure
7.10).
Figure 7.10 Notre nouveau style fait partie de la liste des styles
On remarque au passage quil existe plein de styles dj tout prts, ce sont des styles
systmes comme ceux que nous avons vu un peu plus haut et dont nous pouvons
87
CHAPITRE 7. AJOUTER DU STYLE
allgrement nous servir ! De retour dans le XAML, je peux constater quune proprit
a t rajoute mes TextBlock :
1 <TextBlock Text="Prnom" Grid.Column="0" Grid.Row="1" Style="{
StaticResource TexteStyle}" />
Cest la proprit Style bien videmment, qui va permettre dindiquer que lon applique
le style TexteStyle. Celui-ci est dni dans le XAML du chier App.xaml :
1 <Style x:Key="TexteStyle" TargetType="TextBlock">
2 <Setter Property="Foreground" Value="#FF0B5EF0"/>
3 <Setter Property="FontFamily" Value="Andy"/>
4 <Setter Property="FontSize" Value="32"/>
5 </Style >
Ce qui correspond aux valeurs que jai modies. Et voil, plutt simple non? Remar-
quons avant de terminer que les styles peuvent hriter entre eux, ce qui permet de
complter ou de remplacer certaines valeurs. Prenons par exemple le XAML suivant :
1 <Style x:Key="TexteStyle" TargetType="TextBlock">
2 <Setter Property="Foreground" Value="#FF0B5EF0"/>
3 <Setter Property="FontFamily" Value="Andy"/>
4 <Setter Property="FontSize" Value="32"/>
5 </Style >
6 <Style x:Key="TexteStyle2" TargetType="TextBlock" BasedOn="{
StaticResource TexteStyle}">
7 <Setter Property="FontSize" Value="45"/>
8 <Setter Property="HorizontalAlignment" Value="Center" />
9 </Style >
Le deuxime style hrite du premier grce la proprit BaseOn. Notez que les styles
sont encore plus puissants que a, nous aurons loccasion de voir dautres utilisations
plus loin dans le cours.
Les thmes
Si vous avez jou avec lmulateur ou avec vos Windows Phone, vous avez pu vous rendre
compte que Windows Phone disposait de plusieurs thmes. Ouvrez votre mulateur et
faites glisser lcran sur la droite ou cliquez sur la che en bas de lcran daccueil,
cliquez ensuite sur Paramtres (voir la gure 7.11).
Puis sur thme (voir la gure 7.12).
On obtient cet cran (voir la gure 7.13).
Il est possible de choisir le thme, soit sombre soit clair puis la couleur daccentuation
(voir la gure 7.14).
Quest-ce que a veut dire ? Eh bien cela veut dire quon ne peut pas faire nimporte
quoi avec les couleurs et surtout pas nimporte comment. Par exemple, si jcris du
88
LES THMES
Figure 7.11 Accs au menu de paramtrage de lmulateur
Figure 7.12 Accs au paramtrage des thmes
89
CHAPITRE 7. AJOUTER DU STYLE
Figure 7.13 Paramtrage des thmes
Figure 7.14 Modication de la couleur daccentuation
90
LES THMES
texte de couleur blanche, cela passera trs bien avec mon thme sombre, mais cela
deviendra invisible avec un thme clair.
Les contrles de Windows Phone savent grer ces dirents thmes sans aucun pro-
blme grce aux styles systmes qui savent sadapter aux dirents thmes, comme
par exemple les styles PhoneTextNormalStyle et PhoneTextTitle1Style. Ainsi, si
vous lancez votre application frachement cre en mode sombre, vous aurez les titres
suivants (voir la gure 7.15).
Figure 7.15 Le titre est blanc sur fond noir en mode sombre
Alors quen mode clair, vous aurez la gure 7.16.
Les couleurs sont direntes, cest le style qui gre les dirents thmes. Il est possible de
dtecter le thme de lapplication an dadapter nos designs, par exemple en changeant
une image ou en changeant une couleur, etc. Pour ce faire, on peut utiliser la technique
suivante :
1 Visibility darkBackgroundVisibility = (Visibility)Application.
Current.Resources["PhoneDarkThemeVisibility"];
2 if (darkBackgroundVisibility == Visibility.Visible)
3 {
4 // le thme est sombre
5 }
6 else
7 {
8 // le thme est clair
9 }
91
CHAPITRE 7. AJOUTER DU STYLE
Figure 7.16 Le titre est noir sur fond blanc en mode clair
De mme, on peut rcuprer la couleur daccentuation choisie an de lutiliser sur nos
pages, par exemple :
1 Color couleur = (Color)Application.Current.Resources["
PhoneAccentColor"];
2 MonTextBox.Foreground = new SolidColorBrush(couleur);
Changer lapparence de son contrle
Il ny a pas que les styles qui permettent de changer lapparence dun contrle. Rappelez-
vous, nous avons dit que certains contrles drivaient de la classe ContentControl. Il
sagit de contrles qui contiennent dautres objets. Cest le cas du bouton par exemple.
Il est possible de modier son apparence sans changer ses fonctionnalits. Cest une
des grandes forces du XAML. Il sut de rednir la proprit Content du bouton. . .
Jusqu prsent, un bouton ctait ce XAML ( lintrieur dun StackPanel) :
1 <Button Content="Cliquez -moi !" />
Qui donnait la gure 7.17.
Nous avons mis une chane de caractres dans la proprit Content. Cette proprit
est de type object, il est donc possible dy mettre nimporte quoi. En loccurrence, on
peut y mettre un TextBlock qui donnera le mme rsultat visuel :
92
CHANGER LAPPARENCE DE SON CONTRLE
Figure 7.17 Un simple bouton
1 <Button >
2 <Button.Content >
3 <TextBlock Text="Cliquez -moi" />
4 </Button.Content >
5 </Button >
Si on peut mettre un TextBlock, on peut mettre nimporte quoi et cest a qui est
formidable. Par exemple, on peut facilement mettre une image. Reprenons notre rond
rouge du dbut du chapitre, puis utilisez le XAML suivant :
1 <Button >
2 <Button.Content >
3 <StackPanel >
4 <Image Source="/Assets/Images/rond.png" Width="100"
Height="100" />
5 <TextBlock Text="Cliquez -moi !" />
6 </StackPanel >
7 </Button.Content >
8 </Button >
Nous obtenons un bouton tout fait fonctionnel possdant une image et un texte (voir
la gure 7.18).
Nous navons rien eu dautre faire que de modier lobjet Content et ce bouton
continue se comporter comme un bouton classique. Remarquons avant de terminer
quil est possible de pousser la personnalisation encore plus loin grce aux modles (en
anglais template) que nous verrons plus loin.
En rsum
Les styles sont un lment trs puissant nous permettant de modier lapparence
de nos contrles.
On peut changer lapparence des contrles de type ContentControl pour crer
un autre look tout en conservant la fonctionnalit du contrle.
Il faut faire attention aux dirents thmes dune application et toujours vrier
93
CHAPITRE 7. AJOUTER DU STYLE
Figure 7.18 Un bouton avec une image
que ce quon souhaite acher soit bien visible en fonction des thmes et de la
couleur daccentuation.
94
Chapitre 8
TP1 : Cration du jeu du plus ou du
moins
Dicult :
Bienvenue dans ce premier TP! Vous avez pu dcouvrir dans les chapitres prcdents les
premires bases du XAML permettant la construction dapplications Windows Phone. Il est
grand temps de mettre en pratique ce que nous avons appris. Cest ici loccasion pour vous
de tester vos connaissances et de valider ce que vous appris en ralisant cet exercice.
Pour loccasion, nous allons raliser un petit jeu, le classique jeu du plus ou du moins.
95
CHAPITRE 8. TP1 : CRATION DU JEU DU PLUS OU DU MOINS
Instructions pour raliser le TP
Voici donc un petit TP sous forme de cration dun jeu simple qui va vous permettre
de vous entraner. Lide est de raliser le jeu classique du plus ou du moins. . . Je vous
rappelle les rgles. Lordinateur calcule un nombre alatoire et nous devons le deviner.
chaque saisie, il nous indique si le nombre saisi est plus grand ou plus petit que le
nombre trouver, ainsi que le nombre de coups. Une fois trouv, il nous indique que
nous avons gagn.
Nous allons donc pouvoir utiliser nos connaissances en XAML pour crer une interface
graphique permettant de raliser ce jeu. Nous aurons bien sr besoin dun TextBox
pour obtenir la saisie de lutilisateur. Vous pouvez ensuite utiliser un TextBlock pour
donner les instructions, qui pourront tre de la couleur daccentuation. De mme, vous
utiliserez un autre TextBlock pour acher le nombre de coups. Vous pourrez utiliser
un bouton an de vrier le rsultat et un autre bouton pour recommencer une partie.
Pour rappel, vous pouvez obtenir un nombre alatoire en instanciant un objet Random
et en appelant la mthode Next :
1 Random random = new Random ();
2 int valeurSecrete = random.Next(1, 500);
Vous pouvez choisir les bornes que vous voulez, mais de 1 500 me parat pas trop mal.
Noubliez pas de grer le cas o lutilisateur saisit nimporte quoi. Nous ne voudrions
pas que notre premier jeu sur Windows Phone ait un bug qui fasse planter lapplication!
Cest vous de jouer. Bon courage.
Correction
Alors, comment tait ce TP? Pas trop dicile, non?
Alors, voyons ma correction. Il y a plusieurs faons de raliser ce TP ainsi quune
innit de mise en page possible. Jai choisi un look trs simple, mais nhsitez pas
faire parler votre crativit.
Commenons par le XAML :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 <RowDefinition Height="Auto"/>
6 </Grid.RowDefinitions >
7
8 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12 ,17,
0,28">
9 <TextBlock x:Name="ApplicationTitle" Text="TP du jeu du
plus ou du moins" Style="{StaticResource
PhoneTextTitle2Style}"/>
10 </StackPanel >
96
CORRECTION
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0"
>
13 <StackPanel >
14 <TextBlock Text="Veuillez saisir une valeur (entre
0 et 500)" Style="{StaticResource
PhoneTextNormalStyle}" HorizontalAlignment="
Center" />
15 <TextBox x:Name="Valeur" InputScope="Number" />
16 <Button Content="Vrifier" Tap="Button_Tap_1" />
17 <TextBlock x:Name="Indications" Height="50"
TextWrapping="Wrap" />
18 <TextBlock x:Name="NombreDeCoups" Height="50"
TextWrapping="Wrap" Style="{StaticResource
PhoneTextNormalStyle}" />
19 </StackPanel >
20 </Grid >
21 <Button Content="Rejouer" Tap="Button_Tap_2" Grid.Row="2"
/>
22 </Grid >
Il sagit de disposer mes contrles de manire obtenir ce rendu (voir la gure 8.1).
Figure 8.1 Rendu du TP du jeu du plus ou du moins dans lmulateur
Ce quil est important de voir ici cest que tous mes TextBlock possdent un style
qui sait grer les thmes, sauf celui pour les indications car cest par code que je
97
CHAPITRE 8. TP1 : CRATION DU JEU DU PLUS OU DU MOINS
vais positionner la couleur. Remarquez galement que le TextBox achera un clavier
numrique grce lInputScope qui vaut Number.
Passons prsent au code behind :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private Random random;
4 private int valeurSecrete;
5 private int nbCoups;
6
7 public MainPage ()
8 {
9 InitializeComponent ();
10
11 random = new Random ();
12 valeurSecrete = random.Next(1, 500);
13 nbCoups = 0;
14 Color couleur = (Color)Application.Current.Resources["
PhoneAccentColor"];
15 Indications.Foreground = new SolidColorBrush(couleur);
16 }
17
18 private void Button_Tap_1(object sender , System.Windows.
Input.GestureEventArgs e)
19 {
20 int num;
21 if (int.TryParse(Valeur.Text , out num))
22 {
23 if (valeurSecrete == num)
24 {
25 Indications.Text = "Gagn !!";
26 }
27 else
28 {
29 nbCoups ++;
30 if (valeurSecrete < num)
31 Indications.Text = "Trop grand ...";
32 else
33 Indications.Text = "Trop petit ...";
34 if (nbCoups == 1)
35 NombreDeCoups.Text = nbCoups + " coup";
36 else
37 NombreDeCoups.Text = nbCoups + " coups";
38 }
39 }
40 else
41 Indications.Text = "Veuillez saisir un entier ...";
42 }
43
44 private void Button_Tap_2(object sender , System.Windows.
98
CORRECTION
Input.GestureEventArgs e)
45 {
46 valeurSecrete = random.Next(1, 500);
47 nbCoups = 0;
48 Indications.Text = string.Empty;
49 NombreDeCoups.Text = string.Empty;
50 Valeur.Text = string.Empty;
51 }
52 }
La classe Color et la classe SolidColorBrush ncessitent limport suivant :
1 using System.Windows.Media;
Le jeu en lui-mme ne devrait pas avoir pos trop de problmes. Lalgorithme est
classique, on commence par dterminer un nombre alatoire puis chaque demande
de vrication, on transforme la valeur saisie en entier, an de vrier que lutilisateur
na pas saisi nimporte quoi. Avec le clavier numrique, les erreurs sont limites, mais
elles sont encore possible car on demande des entiers et lutilisateur a la possibilit de
saisir des nombres virgule. Puis on compare et on indique le rsultat (voir la gure
8.2).
Figure 8.2 Une partie en cours de jeu . . .
Et voil pour notre premier TP. Vous avez pu voir comme il est nalement assez simple
de crer des petits programmes sur nos tlphones grce au XAML et au C#.
99
CHAPITRE 8. TP1 : CRATION DU JEU DU PLUS OU DU MOINS
100
Chapitre 9
Dessiner avec le XAML
Dicult :
En plus des contrles, le XAML possde les formes (en anglais Shape). Elles permettent
de dessiner direntes formes sur nos pages. Voyons prsent comment cela fonctionne.
101
CHAPITRE 9. DESSINER AVEC LE XAML
Dessin 2D
Il existe plusieurs types de formes. Elles sont reprsentes par des classes qui d-
rivent toutes dune classe abstraite de base : Shape - http://msdn.microsoft.com/
fr-fr/library/system.windows.shapes.shape(v=vs.95).aspx. Shape est un l-
ment achable sur une page dans la mesure o elle drive, comme les contrles, de
FrameworkElement et de UIElement. Nous avons notre disposition :
Les ellipses et cercles via la classe Ellipse - http://msdn.microsoft.com/fr-fr/
library/system.windows.shapes.ellipse(v=vs.95).aspx
Les lignes, via la classe Line - http://msdn.microsoft.com/fr-fr/library/
system.windows.shapes.line(v=vs.95).aspx
Plusieurs lignes ou courbes connectes, via la classe Path - http:
//msdn.microsoft.com/fr-fr/library/system.windows.shapes.path(v=
vs.95).aspx. Path pouvant tre traduit en trac, il sagit dun trac de lignes
ou de courbes.
Des lignes connectes via la classe PolyLine - http://msdn.microsoft.com/
fr-fr/library/system.windows.shapes.polyline(v=vs.95).aspx
Les polygones, via la classe Polygon - http://msdn.microsoft.com/fr-fr/
library/system.windows.shapes.polygon(v=vs.95).aspx. La dirence avec
le PolyLine est que la forme se termine en reliant le dernier trait au premier.
Des rectangles via la classe Rectangle - http://msdn.microsoft.com/fr-fr/
library/system.windows.shapes.rectangle(v=vs.95).aspx
Si vous vous rappelez, nous avons utilis la classe Rectangle dans un prcdent chapitre
pour illustrer les marges. Dessinons par exemple un carr et un cercle. Pour cela, je
peux utiliser les classes Rectangle et Ellipse :
1 <StackPanel >
2 <Rectangle Width="100" Height="100" Fill="Aqua" />
3 <Ellipse Height="100" Width="100" Fill="Azure" />
4 </StackPanel >
Ce qui nous donne la gure 9.1.
Remarquons que la proprit Fill permet de colorer les formes. Nous allons y revenir.
Mais le plus simple est encore dutiliser Blend pour ce genre de choses. Vous avez accs
aux formes soit dans longlet des composants, soit en cliquant sur le rectangle (voir la
gure 9.2).
Blend est votre meilleur alli pour dessiner sur vos pages. Noubliez pas quil est capable
dexploiter le XAML que vous avez saisi la main dans Visual Studio, par exemple :
1 <Canvas >
2 <Line X1="10" Y1="100" X2="150" Y2="100" Stroke="Blue"
StrokeThickness="15"/>
3 </Canvas >
qui va nous permettre de tracer une ligne bleue horizontale dpaisseur 15. Nous la
voyons apparatre dans Blend (voir la gure 9.3).
102
DESSIN 2D
Figure 9.1 Achage dun rectangle et dune ellipse grce leurs contrles respectifs
Figure 9.2 Accs aux formes depuis Blend
103
CHAPITRE 9. DESSINER AVEC LE XAML
Figure 9.3 Achage dune ligne bleue dans Blend
Je vais marrter l pour les exemples de formes car la documentation en ligne possde
des exemples qui sont plutt simples comprendre. Vous allez dailleurs voir dans le
prochain chapitre un exemple de polygone.
Pinceaux
Les pinceaux vont nous permettre de colorier nos formes. Nous avons rapidement vu
tout lheure que nous pouvions colorier nos formes grce la proprit Fill. Par
exemple, le XAML suivant :
1 <Canvas >
2 <Polygon Points="50 ,50 200 , 200 50,200" Fill="Aqua" Stroke=
"Blue" StrokeThickness="5" />
3 </Canvas >
dessine un triangle rectangle de couleur Aqua dont le trait est bleu, dpaisseur 5 (voir
la gure 9.4).
En fait, Aqua et Blue sont des objets drivs de la classe Brush, en loccurrence
ici il sagit dune SolidColorBrush - http://msdn.microsoft.com/fr-fr/library/
system.windows.media.solidcolorbrush(v=vs.95).aspx. Comme on la dj vu,
on peut donc crire notre prcdent pinceau de cette faon :
104
PINCEAUX
Figure 9.4 Le triangle est color grce au pinceau Aqua
1 <Polygon Points="50,50 200 , 200 50,200" Stroke="Blue"
StrokeThickness="5">
2 <Polygon.Fill >
3 <SolidColorBrush Color="Aqua" />
4 </Polygon.Fill >
5 </Polygon >
Ce qui nous ore un meilleur contrle sur le pinceau. Nous pouvons par exemple changer
lopacit et la passer de 1 (valeur par dfaut) 0.4 par exemple :
1 <Polygon Points="50,50 200 , 200 50,200" Stroke="Blue"
StrokeThickness="5">
2 <Polygon.Fill >
3 <SolidColorBrush Color="Aqua" Opacity="0.4" />
4 </Polygon.Fill >
5 </Polygon >
Et nous pouvons voir que la couleur est un peu plus transparente (voir la gure 9.5).
Figure 9.5 Lopacit joue sur la transparence du contrle
Toutes les proprits commenant par Stroke se rapportent au trait
de la forme. Par exemple, Stroke permet de modier la couleur du
trait, StrokeThickness permet de modier lpaisseur du trait ou encore
StrokeDash que nous navons pas vu qui permet de modier lapparence
dun trait (pointills, ches aux extrmits, . . .).
105
CHAPITRE 9. DESSINER AVEC LE XAML
Vous vous en doutez, il existe dautres pinceaux que le pinceau uni. Nous avons gale-
ment notre disposition :
Un gradient linaire, via la classe LinearGradientBrush - http:
//msdn.microsoft.com/fr-fr/library/system.windows.media.
lineargradientbrush(v=vs.95).aspx
Un gradient radial, via la classe RadialGradientBrush - http://msdn.microsoft.
com/fr-fr/library/system.windows.media.radialgradientbrush(v=vs.95)
.aspx
Une image, via la classe ImageBrush - http://msdn.microsoft.com/fr-fr/
library/system.windows.media.imagebrush(v=vs.95).aspx
Une vido, via la classe VideoBrush - http://msdn.microsoft.com/fr-fr/
library/system.windows.media.videobrush(v=vs.95).aspx
Utilisons par exemple une ImageBrush pour acher la mascotte dOpenClassrooms
dans notre triangle (voir la gure 9.6).
Figure 9.6 Zozor, la mascotte
Nous aurons le XAML suivant :
1 <Polygon Points="50 ,50 200 , 200 50,200" Stroke="Blue"
StrokeThickness="5">
2 <Polygon.Fill >
3 <ImageBrush ImageSource="http :// uploads.siteduzero.com/
files/337001_338000/337519.png" />
4 </Polygon.Fill >
5 </Polygon >
Qui donnera la gure 9.7.
Figure 9.7 Le triangle avec un pinceau utilisant limage de Zozor
Et voil comment utiliser une image comme pinceau. Sauf que ce triangle rectangle ne
lui rend vraiment pas honneur . . . ! Pour faire un dgrad, le mieux est dutiliser Blend.
106
PINCEAUX
Reprenons notre triangle rectangle et cliquez droite sur le pinceau de dgrad (voir
la gure 9.8).
Figure 9.8 Cration dun pinceau de dgrad
Il ne reste plus qu choisir les couleurs de votre dgrad. Il faut vous servir de la bande
en bas pour dnir les direntes couleurs du dgrad (voir la gure 9.9).
Figure 9.9 Choix du dgrad
Et nous aurons un mgnique triangle dgrad (voir la gure 9.10) !
Figure 9.10 Le triangle avec le pinceau dgrad
Notons que le XAML gnr est le suivant :
107
CHAPITRE 9. DESSINER AVEC LE XAML
1 <Polygon Points="50 ,50 200 , 200 50,200" Stroke="Blue"
StrokeThickness="5">
2 <Polygon.Fill >
3 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0
">
4 <GradientStop Color="Black" Offset="0"/>
5 <GradientStop Color="#FF1FDC0C" Offset="1"/>
6 <GradientStop Color="#FFE8AD11" Offset="0.488"/>
7 </LinearGradientBrush >
8 </Polygon.Fill >
9 </Polygon >
Voil pour ce petit tour des pinceaux.
Les transformations
Le XAML possde un systme de transformations qui permet dagir sur les contrles. Il
existe plusieurs types de transformations dites anes car elles conservent la structure
originale du contrle. Il est par exemple possible deectuer :
une rotation grce la classe RotateTransform - http://msdn.microsoft.com/
fr-fr/library/system.windows.media.rotatetransform(v=vs.95).aspx
une translation grce la classe TranslateTransform - http://msdn.microsoft.
com/fr-fr/library/system.windows.media.translatetransform(v=vs.95)
.aspx
une mise lchelle grce la classe ScaleTransform - http://msdn.microsoft.
com/fr-fr/library/system.windows.media.scaletransform(v=vs.95).aspx
une inclinaison grce la classe SkewTransform - http://msdn.microsoft.
com/fr-fr/library/system.windows.media.skewtransform(v=vs.95).aspx
Une transformation matricielle grce la classe MatrixTransform -
http://msdn.microsoft.com/fr-fr/library/system.windows.media.
matrixtransform(v=vs.95).aspx
Par exemple, pour faire pivoter un bouton de 45, je peux utiliser le code suivant :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <StackPanel >
3 <Button Content="Cliquez -moi !">
4 <Button.RenderTransform >
5 <RotateTransform x:Name="Rotation" Angle="45"
CenterX="100" CenterY="50" />
6 </Button.RenderTransform >
7 </Button >
8 </StackPanel >
9 </Grid >
Ce qui nous donne la gure 9.11.
Il sut de renseigner la proprit RenderTransform du contrle, sachant que cette
proprit fait partie de la classe UIElement qui est la classe mre de tous les contrles
108
LES TRANSFORMATIONS
Figure 9.11 Rotation dun contrle de 45
achables. Dans cette proprit, on met la classe RotateTransform en lui prcisant no-
tamment langle de rotation et les coordonnes du centre de rotation. Illustrons encore
une transformation grce la classe ScaleTransform pour eectuer un grossissement
dun TextBlock :
1 <TextBlock Text="Hello world" />
2 <TextBlock Text="Hello world">
3 <TextBlock.RenderTransform >
4 <ScaleTransform ScaleX="3" ScaleY="10" />
5 </TextBlock.RenderTransform >
6 </TextBlock >
Qui donne la gure 9.12.
Ces transformations peuvent se combiner grce la classe TransformGroup, par exemple
ici je combine une rotation avec une translation :
1 <TextBlock Text="Hello world">
2 <TextBlock.RenderTransform >
3 <TransformGroup >
4 <RotateTransform Angle="90" />
5 <TranslateTransform X="150" Y="100" />
6 </TransformGroup >
7 </TextBlock.RenderTransform >
8 </TextBlock >
109
CHAPITRE 9. DESSINER AVEC LE XAML
Figure 9.12 Mise lchelle du contrle
Et nous aurons la gure 9.13.
Sachant quil est possible de faire la mme chose avec une transformation compo-
site, grce la classe CompositeTransform - http://msdn.microsoft.com/fr-fr/
library/system.windows.media.compositetransform(v=vs.95).aspx. Elle sutilise
ainsi :
1 <TextBlock Text="Hello world">
2 <TextBlock.RenderTransform >
3 <CompositeTransform TranslateX="150" TranslateY="100"
Rotation="90" />
4 </TextBlock.RenderTransform >
5 </TextBlock >
Voil pour les transformations. En soi elles ne sont pas toujours trs utiles, mais elles
rvlent toutes leurs puissances grce aux animations que nous dcouvrirons dans le
chapitre suivant.
En rsum
Le XAML possde plein de formes que nous pouvons utiliser pour dessiner dans
nos applications, comme le trait, lellipse, le rectangle, etc.
chaque forme peut tre applique une couleur de remplissage ou de traits
grce aux pinceaux.
110
LES TRANSFORMATIONS
Figure 9.13 Rotation combine une translation
Il est galement possible de faire subir des transformations un contrle comme
une rotation ou une translation.
111
CHAPITRE 9. DESSINER AVEC LE XAML
112
Chapitre 10
Crer des animations
Dicult :
Des contrles, du dessin . . . nous sommes presque prts raliser des jolies interfaces en
laissant parler notre crativit. Mais tout cela manque un peu de dynamique, de trucs qui
bougent et nous en mettent plein la vue.
Le XAML nous a entendu ! Grce lui, il est trs facile de crer des animations. Elles
vont nous servir mettre en valeur certains lments, ou raliser un eet de transition en
rajoutant du mouvement et de linteractivit. Bref, de quoi innover un peu et embellir vos
applications.
Nous allons dcouvrir dans ce chapitre comment tout cela fonctionne et comment raliser
nos propres animations directement en manipulant le XAML, ou encore grce loutil
professionnel de design : Expression Blend. Soyez prt ce que a bouge.
113
CHAPITRE 10. CRER DES ANIMATIONS
Principes gnraux des animations
Une animation consiste faire varier les proprits dun contrle dans un temps prcis.
Par exemple, si je veux faire bouger un contrle dans un Canvas, je vais pouvoir faire
varier les proprits Canvas.Top et Canvas.Left. De la mme faon, si je veux faire
disparaitre un lment avec ce que lon appelle communment leet fade , je vais
pouvoir faire varier la proprit dopacit dun contrle.
Pour cela, le XAML possde plusieurs classes qui vont nous tre utiles. Des
classes permettant de faire varier une proprit de type couleur, une pro-
prit de type double et une proprit de type Point qui sont respectivement
les classes ColorAnimation - http://msdn.microsoft.com/fr-fr/library/
system.windows.media.animation.coloranimation(v=vs.95).aspx, DoubleA-
nimation - http://msdn.microsoft.com/fr-fr/library/system.windows.
media.animation.doubleanimation(v=vs.95).aspx et PointAnimation -
http://msdn.microsoft.com/fr-fr/library/system.windows.media.animation.
pointanimation(v=vs.95).aspx.
Il nest possible danimer que ces trois types de valeur.
Pour fonctionner, elles ont besoin dune autre classe qui soccupe de contrler les ani-
mations an dindiquer leurs cibles et la planication de lanimation. Il sagit de la
classe StoryBoard - http://msdn.microsoft.com/fr-fr/library/system.windows.
media.animation.storyboard(v=vs.95).aspx dont le nom explicite rappelle un peu
les projets de montage audio ou vido. Cest le mme principe, cest elle qui va cadencer
les direntes animations.
Cration dune animation simple (XAML)
Pour illustrer les animations, je vais vous montrer leet de disparition ( fade ) appli-
qu un contrle. Crons donc un contrle, par exemple un StackPanel contenant un
bouton et un TextBlock. Jai besoin galement dun autre bouton qui va me permettre
de dclencher lanimation :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6 <StackPanel x:Name="LeStackPanel">
7 <Button Content="Cliquez -moi !" />
8 <TextBlock Text="Je vais bientt disparatre ..." />
9 </StackPanel >
10 <StackPanel Grid.Row="1">
114
CRATION DUNE ANIMATION SIMPLE (XAML)
11 <Button Content="Dmarrer l'animation" Tap="Button_Tap"
/>
12 </StackPanel >
13 </Grid >
Nous allons maintenant crer notre Storyboard. Celui-ci doit se trouver en ressources.
Comme on la dj vu, vous pouvez le mettre en ressources de lapplication, de la page
ou bien en ressources dun contrle parent. Mettons-le dans les ressources de la grille :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6 <Grid.Resources >
7 <Storyboard x:Name="MonStoryBoard">
8 </Storyboard >
9 </Grid.Resources >
10
11 <StackPanel x:Name="LeStackPanel">
12 <Button Content="Cliquez -moi !" />
13 <TextBlock Text="Je vais bientt disparatre ..." />
14 </StackPanel >
15 <StackPanel Grid.Row="1">
16 <Button Content="Dmarrer l'animation" Tap="Button_Tap"
/>
17 </StackPanel >
18 </Grid >
Ce Storyboard doit avoir un nom an dtre manipul par le clic sur le bouton. Il faut
maintenant dnir lanimation :
1 <Storyboard x:Name="MonStoryBoard">
2 <DoubleAnimation From="1.0" To="0.0" Duration="0:0:2"
3 Storyboard.TargetName="LeStackPanel"
4 Storyboard.TargetProperty="Opacity"/>
5 </Storyboard >
Il sagit dune animation de type double o nous allons animer la proprit Opacity
pour la faire aller de la valeur 1 (visible) la valeur 0 (invisible) pendant une dure
de deux secondes, ciblant notre contrle nomm LeStackPanel. Il faut maintenant
dclencher lanimation lors du clic sur le bouton :
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 MonStoryBoard.Begin ();
4 }
Dicile de vous faire une copie dcran du rsultat mais nhsitez pas essayer par
vous-mme (voir la gure 10.1).
115
CHAPITRE 10. CRER DES ANIMATIONS
Figure 10.1 Lanimation de lopacit fait disparatre le contrle
Il est possible de faire en sorte que lanimation se joue en boucle et de manire indnie.
Il sut de rajouter les proprits AutoReverse et RepeatBehavior. Par exemple, ici je
vais animer un bouton de manire ce quil se dplace de gauche droite et de droite
gauche indniment.
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6 <Grid.Resources >
7 <Storyboard x:Name="MonStoryBoard">
8 <DoubleAnimation From="0" To="200" Duration="0:0:3"
9 AutoReverse="True"
RepeatBehavior="Forever"
10 Storyboard.TargetName="
MonBouton" Storyboard.
TargetProperty="(Canvas.Left
)"/>
11 </Storyboard >
12 </Grid.Resources >
13
14 <Canvas Width="480" Height="500" x:Name="LeCanvas">
15 <Button x:Name="MonBouton" Content="Cliquez -moi !" />
16 </Canvas >
116
CRATION DUNE ANIMATION SIMPLE (XAML)
17 <StackPanel Grid.Row="1">
18 <Button Content="Dmarrer l'animation" Tap="Button_Tap"
/>
19 </StackPanel >
20 </Grid >
Jen prote pour indiquer que pour animer une proprit complexe, il faut la
saisir entre parenthses. Je reviendrai sur ce type de proprit plus loin dans
le cours.
Nous pouvons contrler plus nement une animation. Jusqu prsent, nous avons uti-
lis la mthode Begin() pour dmarrer une animation. Vous pouvez galement utiliser
la mthode Stop() pour arrter une animation, la mthode Pause() pour la mettre
en pause et la mthode Resume() pour la reprendre. Vous pouvez galement faire des
animations de transformations. Il sut de combiner lutilisation des transformations
et dune DoubleAnimation. Par exemple, ici je vais faire tourner mon bouton de 90
degrs et le faire revenir sa position initiale :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6 <Grid.Resources >
7 <Storyboard x:Name="MonStoryBoard">
8 <DoubleAnimation From="0" To="90" Duration="0:0:1"
AutoReverse="True"
9 Storyboard.TargetName="Rotation"
Storyboard.TargetProperty="Angle
"/>
10 </Storyboard >
11 </Grid.Resources >
12
13 <StackPanel >
14 <Button x:Name="MonBouton" Content="Cliquez -moi !">
15 <Button.RenderTransform >
16 <RotateTransform x:Name="Rotation" Angle="0" />
17 </Button.RenderTransform >
18 </Button >
19 </StackPanel >
20 <StackPanel Grid.Row="1">
21 <Button Content="Dmarrer l'animation" Tap="Button_Tap"
/>
22 </StackPanel >
23 </Grid >
Il sut de cibler la proprit Angle de lobjet RotateTransform. Si vous voulez quune
animation dmarre partir dun certain temps, vous pouvez rajouter la proprit
BeginTime au Storyboard :
117
CHAPITRE 10. CRER DES ANIMATIONS
1 <Storyboard x:Name="MonStoryBoard" BeginTime="0:0:2">
2 <DoubleAnimation From="0" To="90" Duration="0:0:1"
AutoReverse="True"
3 Storyboard.TargetName="Rotation" Storyboard.
TargetProperty="Angle"/>
4 </Storyboard >
Par exemple ici, lanimation va durer une seconde et dmarrera deux secondes aprs son
dclenchement via la mthode Begin(). On peut contrler plus nement une animation
grce aux animations dites Key Frame qui permettent dindiquer dirents moments
cls dune animation. Il est possible ainsi de spcier la valeur de la proprit anime
un moment T. On utilisera les trois types danimations suivantes :
DoubleAnimationUsingKeyFrames
ColorAnimationUsingKeyFrames
PointAnimationUsingKeyFrames
Chacune de ces animations peut tre de trois types : Linear, Discret et Spline.
Lanimation linaire se rapproche des animations que nous avons vues prcdemment
dans la mesure o entre les moments cls, lanimation passera par toutes les valeurs
sparant les deux valeurs des moments cls. On pourrait illustrer ceci en simulant
un secouage de bouton an dattirer lattention de lutilisateur. Le secouage va
consister faire une rotation de X degrs dans le sens horaire, puis revenir la position
initiale, puis faire la rotation de X degrs dans le sens anti horaire et enn revenir la
position initiale. Il y a donc cinq moments cls dans cette animation :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6 <Grid.Resources >
7 <Storyboard x:Name="MonStoryBoard" >
8 <DoubleAnimationUsingKeyFrames Storyboard.
TargetName="Rotation" Storyboard.TargetProperty=
"Angle" RepeatBehavior="5x">
9 <LinearDoubleKeyFrame Value="0" KeyTime="00:00:
00"/>
10 <LinearDoubleKeyFrame Value="5" KeyTime="00:00:
00.1"/>
11 <LinearDoubleKeyFrame Value="0" KeyTime="00:00:
00.2"/>
12 <LinearDoubleKeyFrame Value="-5" KeyTime="00:00
:00.3"/>
13 <LinearDoubleKeyFrame Value="0" KeyTime="00:00:
00.4"/>
14 </DoubleAnimationUsingKeyFrames >
15 </Storyboard >
16 </Grid.Resources >
17
18 <StackPanel >
118
CRATION DUNE ANIMATION COMPLEXE (BLEND)
19 <Button x:Name="MonBouton" Content="Cliquez -moi !"
Width="200" Height="100">
20 <Button.RenderTransform >
21 <RotateTransform x:Name="Rotation" Angle="0"
CenterX="100" CenterY="50" />
22 </Button.RenderTransform >
23 </Button >
24 </StackPanel >
25 <StackPanel Grid.Row="1">
26 <Button Content="Dmarrer l'animation" Tap="Button_Tap"
/>
27 </StackPanel >
28 </Grid >
tant donn que nous animons un angle, nous utiliserons la classe
DoubleAnimationUsingKeyFrames. Vu que nous voulons des transitions linaires pour
une animation de type double, nous pourrons utiliser la classe LinearDoubleKeyFrame
pour indiquer nos moments cls. Ainsi, jindique quau moment 0, langle sera de 0
degrs. Une fraction de seconde plus tard, langle sera de 5 degrs. Au bout de deux
fractions de seconde, langle sera nouveau 0 degrs. Une fraction de seconde plus
tard, langle sera de -5 degrs et enn, une fraction de seconde plus tard, langle
reviendra sa position initiale.
noter que cette animation sera joue 5 fois grce la proprit RepeatBehavior="5x".
Il y aurait encore beaucoup de choses dire sur ce genre danimations, mais nous allons
prsent dcouvrir comment raliser des animations grce blend.
Cration dune animation complexe (Blend)
Expression Blend, en sa qualit de logiciel de design professionnel facilite la cration
danimations. Nous allons crer une petite animation inutile pour illustrer son fonc-
tionnement. Repartez dune page toute neuve et ouvrez-l dans Expression Blend.
Pour rappel, cliquez-droit sur le chier XAML et choisissez Ouvrir dans expression
blend. Nous allons prsent ajouter un bouton. Slectionnez le bouton dans la boite
outils et faites le glisser sur la surface de la page (voir la gure 10.2).
Allez maintenant dans le menu Fentre et choisissez espace de travail puis animation
an de passer dans la vue ddie lanimation (voir la gure 10.3).
En bas, dans longlet Objets et chronologie, cliquez sur le plus pour crer une nou-
velle animation (voir la gure 10.4).
Donnez un nom votre Storyboard, comme indiqu la gure 10.5.
Il apparat ensuite en bas droite la ligne de temps qui va nous permettre de dnir
des images cls (voir la gure 10.6).
Dplacez le trait jaune qui est sous le chire zro pour le placer sous le chire un, en
le slectionnant par le haut de la ligne. Cela nous permet de dnir une image cl la
premire seconde de lanimation. Nous allons dplacer le bouton vers le bas droite.
119
CHAPITRE 10. CRER DES ANIMATIONS
Figure 10.2 Ajout dun bouton partir de Blend
Figure 10.3 Changement de lespace de travail
Figure 10.4 Cration dune nouvelle animation
120
CRATION DUNE ANIMATION COMPLEXE (BLEND)
Figure 10.5 Nommage du storyboard
Figure 10.6 La ligne de temps du storyboard
Cela signiera que pendant cette seconde, lanimation fera le trajet de la position 0
la position 1 correspondant au dplacement du bouton que nous avons ralis.
Pour voir comment rend lanimation, cliquez sur le petit bouton de lecture en haut de
la ligne de temps (voir la gure 10.7).
Figure 10.7 Dmarrage de lanimation
Je ne peux pas vous illustrer le rsultat, mais vous devriez voir votre rectangle se
dplacer de haut en bas droite. Essayez ! Nhsitez pas rduire le zoom si vous
ne voyez pas tout lcran du designer. Et voil, un dbut danimation plutt simple
faire !
Sauvegardez votre chier et repassez dans Visual Studio. Vous pouvez voir que le chier
121
CHAPITRE 10. CRER DES ANIMATIONS
XAML, aprs rechargement, contient dsormais un code qui ressemble au suivant :
1 <phone:PhoneApplicationPage.Resources >
2 <Storyboard x:Name="MonStoryBoard">
3 <DoubleAnimation Duration="0:0:1" To="166" Storyboard.
TargetProperty="(UIElement.RenderTransform).(
CompositeTransform.TranslateX)" Storyboard.
TargetName="button" d:IsOptimized="True"/>
4 <DoubleAnimation Duration="0:0:1" To="26" Storyboard.
TargetProperty="(UIElement.RenderTransform).(
CompositeTransform.TranslateY)" Storyboard.
TargetName="button" d:IsOptimized="True"/>
5 </Storyboard >
6 </phone:PhoneApplicationPage.Resources >
7
8 <Grid x:Name="LayoutRoot" Background="Transparent">
9 <Grid.RowDefinitions >
10 <RowDefinition Height="Auto"/>
11 <RowDefinition Height="*"/>
12 </Grid.RowDefinitions >
13
14 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12 ,17,
0,28">
15 <TextBlock Text="MON APPLICATION" Style="{
StaticResource PhoneTextNormalStyle}" Margin="12,0"
/>
16 <TextBlock Text="nom de la page" Margin="9,-7,0,0"
Style="{StaticResource PhoneTextTitle1Style}"/>
17 </StackPanel >
18
19 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
>
20 <Button x:Name="button" Content="Button"
HorizontalAlignment="Left" Margin="137 ,68 ,0,0"
VerticalAlignment="Top" RenderTransformOrigin="0.5,0
.5">
21 <Button.RenderTransform >
22 <CompositeTransform/>
23 </Button.RenderTransform >
24 </Button >
25 </Grid >
26 </Grid >
On peut voir quil nous a mis une CompositeTransform dans le bouton avec une
translation sur laxe des X et sur laxe des Y de une seconde. Remarquez la syntaxe
particulire qua utilis Blend :
1 <DoubleAnimation Duration="0:0:1" To="166" Storyboard.
TargetProperty="(UIElement.RenderTransform).(
CompositeTransform.TranslateX)" Storyboard.TargetName="
button" d:IsOptimized="True"/>
122
CRATION DUNE ANIMATION COMPLEXE (BLEND)
et notamment sur la proprit TargetProperty. Alors que dans mon exemple, javais
donn un nom la transformation pour animer une proprit de cette transforma-
tion, ici Blend a choisi danimer une proprit relative du bouton, nomm button.
Il dit quil va animer la proprit TranslateX de lobjet CompositeTransform fai-
sant partie du RenderTransform correspondant au bouton, sachant que la proprit
RenderTransform fait partie de la classe de base UIElement.
Revenons Expression Blend pour rajouter une rotation. Plaons donc notre ligne
de temps sur la deuxime seconde. Je dplace mon bouton en bas gauche an de
raliser une translation laquelle je vais combiner une rotation. Aller dans la fentre
de proprits du bouton et aller tout en bas pour cliquer sur transformer, et choisir
le deuxime onglet pour faire pivoter (voir la gure 10.8).
Figure 10.8 Rotation dun contrle via Blend
Vous pouvez dsormais choisir un angle, disons 40. Vous pouvez vrier que la trans-
lation se fait en mme temps que la rotation en appuyant sur le bouton de lecture.
Terminons enn notre mini boucle en dplaant la ligne de temps sur la troisime se-
conde et en faisant revenir le bouton la position premire et en rglant langle sur
360. Et voil, nous avons termin. Enn. . . presque. Lanimation est prte mais rien
ne permet de la dclencher. Il existe une solution pour le faire avec Expression Blend,
via les comportements que lon trouve plus souvent sous le terme anglais de Behavior.
Jai choisi de ne pas en parler dans ce cours car cela ncessiterait pas mal dexplications
qui ne nous serviront pas particulirement pour la suite. Nous allons donc retourner
dans Visual Studio pour dmarrer manuellement lanimation, par exemple lors du clic
sur le bouton. Rajoutons donc lvnement clic directement dans notre bouton :
1 <Button x:Name="button" Content="Button" Height="77" Margin="98
,60 ,165 ,0" VerticalAlignment="Top" RenderTransformOrigin="0.
5,0.5" Tap="Button_Tap">
2 <Button.RenderTransform >
3 <CompositeTransform/>
4 </Button.RenderTransform >
5 </Button >
Avec dans le code behind :
123
CHAPITRE 10. CRER DES ANIMATIONS
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 MonStoryBoard.Begin ();
4 }
Et voil. Notre animation est termine !
Projections 3D
Chaque lment achable avec le XAML peut subir une projection 3D. Cela consiste
donner une surface 2D une perspective 3D an de raliser un eet visuel. Plutt
quun long discours, un petit exemple qui parlera de lui-mme. Prenons par exemple
une image, limage de la couverture de mon livre sur le C# :
1 <Image Source="http :// uploads.siteduzero.com/files/
365001_366000/365350.jpg"/>
Qui donne la gure 10.9.
Figure 10.9 Image de la couverture du livre pour apprendre le C# dans lmulateur
Pour lui faire subir un eet de perspective, nous pouvons utiliser le XAML suivant :
1 <Image Source="http :// uploads.siteduzero.com/files/
365001_366000/365350.jpg">
124
PROJECTIONS 3D
2 <Image.Projection >
3 <PlaneProjection RotationX="-35" RotationY="-35"
RotationZ="15" />
4 </Image.Projection >
5 </Image >
qui lui fera subir une rotation de -35 autour de laxe des X, de -35 autour de laxe
des Y et de 15 autour de laxe des Z, ce qui donnera la gure 10.10.
Figure 10.10 Limage avec une projection 3D
Plutt sympa comme eet non? Nous avons utilis la classe PlaneProjection - http://
msdn.microsoft.com/fr-fr/library/system.windows.media.planeprojection(v=
vs.95).aspx pour le raliser. Il existe une autre classe permettant de faire des projec-
tions suivant une matrice 3D, il sagit de la classe Matrix3DProjection - http://msdn.
microsoft.com/fr-fr/library/system.windows.media.matrix3dprojection(v=vs.
95).aspx mais je pense que vous ne vous servirez que de la projection plane.
Alors, cest trs joli comme a, mais combin une animation, cest encore mieux.
Prenons le XAML suivant :
1 <phone:PhoneApplicationPage.Resources >
2 <Storyboard x:Name="Sb">
3 <DoubleAnimation Storyboard.TargetName="Projection"
Storyboard.TargetProperty="RotationZ"
4 From="0" To="360" Duration="0:0:5"
/>
125
CHAPITRE 10. CRER DES ANIMATIONS
5 <DoubleAnimation Storyboard.TargetName="Projection"
Storyboard.TargetProperty="RotationY"
6 From="0" To="360" Duration="0:0:5"
/>
7 </Storyboard >
8 </phone:PhoneApplicationPage.Resources >
9 <StackPanel >
10 <Image Source="http :// uploads.siteduzero.com/files/
365001_366000/365350.jpg">
11 <Image.Projection >
12 <PlaneProjection x:Name="Projection" RotationX="0"
RotationY="0" RotationZ="0" />
13 </Image.Projection >
14 </Image >
15 </StackPanel >
Vous vous doutez que je vais animer la rotation sur laxe des Y et sur laxe des Z de 0
360 degrs pendant une dure de 5 secondes . . . Dicile de vous montrer le rsultat,
mais je ne peux que vous encourager tester chez vous (voir la gure 10.11).
Figure 10.11 Animation dune projection 3D
Vous naurez bien sr pas oubli de dmarrer lanimation, par exemple depuis lvne-
ment de chargement de page :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 Loaded += MainPage_Loaded;
5 }
126
PROJECTIONS 3D
6
7 void MainPage_Loaded(object sender , RoutedEventArgs e)
8 {
9 Sb.Begin ();
10 }
En rsum
Le XAML possde un framework complexe danimation.
Blend se rvle un atout de qualit dans la ralisation danimations complexes.
Les projections 3D permettent dajouter un eet de perspective 3D dont le rendu
est plutt intressant.
127
CHAPITRE 10. CRER DES ANIMATIONS
128
Deuxime partie
Un mobile orient donnes
129
Chapitre 11
Une application plusieurs pages, la
navigation
Dicult :
Pour linstant, notre application est simple, avec une unique page. Il est bien rare quune
application nait quune seule page. . . Cest comme pour un site internet, imaginons que
nous ralisions une application mobile pour commander des produits, nous aurons une page
contenant la liste des produits par rayon, une page pour acher la description dun produit,
une page pour commander. . .
Nous allons donc voir quil est possible de naviguer facilement entre les pages de notre
application grce au service de navigation de Windows Phone.
131
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
Naviguer entre les pages
Avant de pouvoir naviguer entre des multiples pages, il faut eectivement avoir plu-
sieurs pages ! Nous allons illustrer cette navigation en prenant pour exemple le site
OpenClassrooms. . . enn, en beaucoup beaucoup moins bien.
Premire fonctionnalit, il faut pouvoir se loguer an datteindre la page des cours.
Nous allons donc avoir deux pages, une qui permet de se loguer, et une qui permet
dacher la liste des cours.
Commenons par la page pour se loguer et vu quelle existe, utilisons la page
MainPage.xaml :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12 ,17,
0,28">
8 <TextBlock x:Name="ApplicationTitle" Text="D
monstration de la navigation" Style="{StaticResource
PhoneTextNormalStyle}"/>
9 <TextBlock x:Name="PageTitle" Text="Page de Login"
Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
>
13 <StackPanel >
14 <TextBlock Text="Saisir votre login"
HorizontalAlignment="Center" />
15 <TextBox x:Name="Login"/>
16 <Button Content="Se connecter" Tap="Button_Tap" />
17 </StackPanel >
18 </Grid >
19 </Grid >
Noubliez pas de gnrer chaque fois les vnements des contrles, si ce
nest pas dj fait. Dans lexemple prcdent : Button_Tap.
Pour que cela soit plus simple, nous utilisons uniquement un login pour nous connecter.
Si nous achons la page dans lmulateur, nous avons la gure 11.1.
Nous allons maintenant crer une deuxime page permettant dacher la liste des
cours. Crons donc une autre page que nous nommons ListeCours.xaml. Pour cela,
nous faisons un clic droit sur le projet et choisissons dajouter un nouvel lment. Il
132
NAVIGUER ENTRE LES PAGES
Figure 11.1 Achage de la page de login
sut de choisir le modle de chier Page en mode portrait Windows Phone et de lui
donner le bon nom (voir la gure 11.2).
Dans cette page, nous allons acher simplement bonjour et que la page est en construc-
tion. Pour cela, un XAML trs minimaliste :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
8 <TextBlock x:Name="ApplicationTitle" Text="D
monstration de la navigation" Style="{StaticResource
PhoneTextNormalStyle}"/>
9 <TextBlock x:Name="PageTitle" Text="Page des cours"
Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0"
>
13 <Grid.RowDefinitions >
133
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
Figure 11.2 Ajout dune nouvelle page XAML dans le projet
14 <RowDefinition Height="200" />
15 <RowDefinition Height="*" />
16 </Grid.RowDefinitions >
17 <TextBlock x:Name="Bonjour" Text="Bonjour"
HorizontalAlignment="Center" />
18 <TextBlock Grid.Row="1" Text="Cette page est en
construction ..." />
19 </Grid >
20 </Grid >
Retournons dans la mthode de clic sur le bouton de la premire page. Nous allons
utiliser le code suivant :
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 if (! string.IsNullOrEmpty(Login.Text))
4 NavigationService.Navigate(new Uri("/ListeCours.xaml",
UriKind.Relative));
5 }
Nous utilisons le service de navigation et notamment sa mthode Navigate pour acc-
der la page ListeCours.xaml, si le login nest pas vide. Grce cette mthode, nous
pouvons aller facilement sur la page en construction. Remarquons que si nous appuyons
sur le bouton en bas gauche du tlphone permettant de faire un retour arrire, alors
nous revenons la page prcdente. Si nous cliquons nouveau sur le retour arrire,
134
NAVIGUER ENTRE LES PAGES
alors nous quittons lapplication car il ny a pas de page prcdente. Bon, cest trs
bien tout a, mais si on pouvait acher un bonjour personnalis, a serait pas plus
mal, avec par exemple le login saisi juste avant . . . Il y a plusieurs solutions pour faire
cela. Une des solutions consiste utiliser la query string. Elle permet de passer des
informations complmentaires une page, un peu comme pour les pages web. Pour
cela, on utilise la syntaxe suivante :
1 Page.xaml?parametre1=valeur1&parametre2=valeur2
Modions donc notre mthode pour avoir :
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 if (! string.IsNullOrEmpty(Login.Text))
4 NavigationService.Navigate(new Uri("/ListeCours.xaml?
login=" + Login.Text , UriKind.Relative));
5 }
Dsormais, la page ListeCours sera appele avec le paramtre login qui vaudra la
valeur saisie dans la TextBox. Pour rcuprer cette valeur, rendez-vous dans le code
behind de la seconde page o nous allons substituer la mthode appele lorsquon
navigue sur la page, il sagit de la mthode OnNavigatedTo, cette mthode faisant
partie de la classe PhoneApplicationPage. Nous aurons donc le code behind suivant :
1 public partial class ListeCours : PhoneApplicationPage
2 {
3 public ListeCours ()
4 {
5 InitializeComponent ();
6 }
7
8 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
9 {
10 base.OnNavigatedTo(e);
11 }
12 }
Cest cet endroit que nous allons extraire la valeur du paramtre avec le code suivant :
1 protected override void OnNavigatedTo(System.Windows.Navigation
.NavigationEventArgs e)
2 {
3 string login;
4 if (NavigationContext.QueryString.TryGetValue("login", out
login))
5 {
6 Bonjour.Text += " " + login;
7 }
8 base.OnNavigatedTo(e);
9 }
135
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
On utilise la mthode TryGetValue en lui passant le nom du paramtre. Cette m-
thode fait partie de lobjet QueryString du contexte de navigation accessible via
NavigationContext. Ce qui nous donne la gure 11.3.
Figure 11.3 Achage de la seconde page
Une autre solution pour passer des informations de page en page serait dutiliser le
dictionnaire dtat de lapplication an de communiquer un contexte la page vers
laquelle nous allons naviguer. Il sagit dun objet accessible de partout o nous pouvons
stocker des informations et les lier une cl. Cela donne :
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 if (! string.IsNullOrEmpty(Login.Text))
4 {
5 PhoneApplicationService.Current.State["login"] = Login.
Text;
6 NavigationService.Navigate(new Uri("/ListeCours.xaml",
UriKind.Relative));
7 }
8 }
Et pour rcuprer la valeur dans la deuxime page, nous ferons :
1 protected override void OnNavigatedTo(System.Windows.Navigation
.NavigationEventArgs e)
2 {
136
NAVIGUER ENTRE LES PAGES
3 string login = (string)PhoneApplicationService.Current.
State["login"];
4 Bonjour.Text += " " + login;
5 base.OnNavigatedTo(e);
6 }
Lutilisation du dictionnaire dtat est trs pratique pour faire transiter un objet com-
plexe qui sera dicilement reprsentable dans des paramtres de query string.
Attention : le dictionnaire dtat ne doit contenir que des informations sria-
lisables.
Voil pour ce premier aperu du service de navigation. Remarquez que le XAML
possde galement un contrle qui permet de naviguer entre les pages, comme le
NavigationService. Il sagit du contrle HyperlinkButton - http://msdn.microsoft.
com/fr-fr/library/system.windows.controls.hyperlinkbutton(v=vs.95).aspx.
Il sura de renseigner sa proprit NavigateUri. Compltons notre page ListeCours
pour rajouter en bas un HyperLinkButton qui renverra vers une page Contact.xaml :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="200" />
4 <RowDefinition Height="*" />
5 <RowDefinition Height="auto" />
6 </Grid.RowDefinitions >
7 <TextBlock x:Name="Bonjour" Text="Bonjour"
HorizontalAlignment="Center" />
8 <TextBlock Grid.Row="1" Text="Cette page est en
construction ..." />
9 <HyperlinkButton Grid.Row="2" Content="Nous contacter"
NavigateUri="/Contact.xaml" />
10 </Grid >
Puis crons une page Contact.xaml :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
8 <TextBlock x:Name="ApplicationTitle" Text="D
monstration de la navigation" Style="{StaticResource
PhoneTextNormalStyle}"/>
9 <TextBlock x:Name="PageTitle" Text="Nous contacter"
Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
137
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
>
13 <StackPanel >
14 <TextBlock Text="Il n'y a rien pour l'instant ..."
/>
15 <Button Content="Revenir la page prcdente" Tap=
"Button_Tap" />
16 </StackPanel >
17 </Grid >
18 </Grid >
Ainsi, lorsque nous dmarrerons lapplication et aprs nous tre logus, nous pouvons
voir le bouton nous contacter en bas de la page (voir la gure 11.4).
Figure 11.4 Utilisation du contrle HyperLinkButton pour la navigation
Un clic dessus nous amne la page de contact (voir la gure 11.5).
Et voil, la navigation est rendue trs simple avec ce contrle, nous naviguons entre les
pages de notre application en nayant presque rien fait, part ajouter un contrle
HyperlinkButton. Il sait grer facilement une navigation avec des liens entre des
pages. Cest la forme de navigation la plus simple. Nous avons pu voir ainsi deux
faons direntes de naviguer entre les pages, via le contrle HyperlinkButton et via
le NavigationService. Puis nous avons vu deux faons direntes de passer des infor-
mations entre les pages, via la query string et via le dictionnaire dtat de lapplication.
138
GRER LE BOUTON DE RETOUR ARRIRE
Figure 11.5 Achage de la page de contact
On remarque que la premire page sacher lorsquon dmarre une appli-
cation est la page MainPage.xaml. Ceci est congurable en allant modier
le chier WMAppManifest.xml qui se trouve dans lexplorateur de solutions,
sous properties (voir la gure 11.6).
Double-cliquez dessus et une nouvelle page souvre permettant de saisir une autre page
de dmarrage (voir la gure 11.7).
Grer le bouton de retour arrire
Et pour revenir en arrire ? Nous lavons vu, il faut cliquer sur le bouton de retour
arrire qui fait ncessairement partie dun tlphone Windows Phone. Mais il est ga-
lement possible de dclencher ce retour arrire grce au service de navigation. Cest
cela que va servir le bouton que jai rajout dans la page Contact.xaml. Observons
lvnement associ au clic :
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 NavigationService.GoBack ();
4 }
139
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
Figure 11.6 Le chier WMAppManifest.xml dans lexplorateur de solutions
Figure 11.7 Le concepteur permettant de modier la page XAML de dmarrage de
lapplication
140
GRER LE BOUTON DE RETOUR ARRIRE
Trs simple, il sut de dclencher le retour arrire avec la mthode GoBack() du service
de navigation. Notez quil peut tre utile dans certaines situations de tester si un retour
arrire est eectivement possible. Cela se fait avec la proprit CanGoBack :
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 if (NavigationService.CanGoBack)
4 NavigationService.GoBack ();
5 }
Il est galement possible de savoir si lutilisateur a appuy sur le fameux bouton de
retour arrire. ce moment-l, on passera dans la mthode OnBackKeyPress. Pour
pouvoir faire quelque chose lors de ce clic, on pourra substituer cette mthode dans
notre classe :
1 protected override void OnBackKeyPress(System.ComponentModel.
CancelEventArgs e)
2 {
3 base.OnBackKeyPress(e);
4 }
Il est possible ici de faire ce que lon veut, comme acher un message de conrmation
demandant si on veut rellement quitter cette page, ou sauvegarder des infos, etc. On
pourra annuler laction de retour arrire en modiant la proprit Cancel de lobjet
CancelEventArgs true, si par exemple lutilisateur ne souhaite nalement pas revenir
en arrire. On peut galement choisir de rediriger vers une autre page si cest pertinent :
1 protected override void OnBackKeyPress(System.ComponentModel.
CancelEventArgs e)
2 {
3 if (MessageBox.Show("Vous n'avez pas sauvegard votre
travail , voulez -vous vraiment quitter cette page ?", "
Attention", MessageBoxButton.OKCancel) ==
MessageBoxResult.Cancel)
4 {
5 e.Cancel = true;
6 }
7 base.OnBackKeyPress(e);
8 }
Qui donne la gure 11.8.
Et voil pour les bases de la navigation. Dune manire gnrale, il est de bon ton de
garder une mcanique de navigation uide et cohrente. Il faut privilgier la navigation
intuitive pour que lutilisateur ne soit pas perdu dans un labyrinthe dcran. . .
141
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
Figure 11.8 Achage dune conrmation avant de quitter la page
Ajouter une image daccueil (splash screen)
Il est maintenant dun usage commun de faire en sorte quau dmarrage de son appli-
cation il y ait une image pour faire patienter lutilisateur pendant que tout se charge.
On appelle cela en gnral de son nom anglais : Splash screen, que lon peut traduire
en image daccueil. On y trouve souvent un petit logo de lapplication ou de lentre-
prise qui la ralis, pourquoi pas le numro de version,. . . bref, des choses pour faire
patienter lutilisateur et lui dire que lapplication va bientt dmarrer. Avec Windows
Phone, il est trs facile de raliser ce genre dimage daccueil, il sut de rajouter (si
elle nest pas dj prsente) une image sappelant SplashScreenImage.jpg la racine
du projet. Elle doit avoir son action de gnration Contenu (voir la gure 11.9).
Pour les applications Windows Phone 8, elle doit avoir la taille 768x1280 pixels alors
que pour les applications Windows Phone 7.X elle devra tre de 480x800 (voir la gure
11.10).
Vous noterez au passage mon talent de dessinateur et ma grande force exploiter toute
la puissance des formes de Paint.
142
AJOUTER UNE IMAGE DACCUEIL (SPLASH SCREEN)
Figure 11.9 Limage daccueil dans lexplorateur de solutions
Figure 11.10 Achage de lcran daccueil dans lmulateur
143
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
Le tombstonning
Avec Windows Phone 7 est apparu un changement radical dans la faon dont sont
traites les applications. Fini le multitche comme on le connaissait auparavant avec
un Windows classique, il ny a dsormais quune application qui sexcute la fois.
Cela veut dire que si je suis dans une application, que jappuie sur le bouton de menu
et que jouvre une nouvelle application, je nai pas deux applications qui tournent en
parallle, mais une seule. Ma premire application ne sest pas ferme non plus, elle
est passe dans un mode suspendu , voire dsactiv en fonction du contexte.
Ainsi, si je quitte ma seconde application en appuyant par exemple sur le bouton de
retour arrire, alors ma premire application qui tait en mode suspendu ou dsactiv,
se ractive et repasse dans le mode en cours dexcution.
Ce fonctionnement est conserv pour Windows Phone 8 et a t galement tendu pour
les applications Windows 8. Une application peut donc soit tre :
En cours dexcution
Suspendue
Dsactive
Non dmarre
Lorsque lapplication passe en mode suspendu, par exemple lorsque jappuie sur le
bouton de menu, elle reste intacte en mmoire. Cela veut dire quun retour arrire
pour retourner lapplication sera trs rapide et vous retrouverez votre application
comme elle se trouvait prcdemment.
Enn, a, cest la thorie. En vrai, cest un peu plus compliqu que a. Cest le systme
dexploitation qui soccupe de grer les tats des applications en fonction notamment
de la mmoire disponible. En eet, Windows Phone peut choisir de dsactiver une
application suspendue si lapplication en cours dexcution a besoin de mmoire. De
la mme faon, lapplication peut avoir simplement t suspendue et se ractiver de
manire optimale si le systme dexploitation na pas eu besoin de mmoire. Une ap-
plication dsactive a t termine par le systme dexploitation, bien souvent parce
quil avait besoin de mmoire. Quelques informations restent cependant disponibles et
si lutilisateur revient sur lapplication, celle-ci est alors redmarre depuis zro mais
ces informations sont accessibles an de permettre de restaurer ltat de lapplication.
Tout ceci implique que lon ne peut jamais garantir que lutilisateur va fermer correcte-
ment une application ou que celle-ci va se terminer proprement, cest mme dailleurs
rarement le cas. Il peut y avoir plein de scnarios possibles. Par exemple votre utilisateur
est en train de saisir des informations dans votre application, il change dapplication
pour aller lire un mail, voir la mto, puis plus tard il revient votre application; entre
temps il a reu un coup de tlphone, recharg son tlphone . . . Quest devenue notre
application ? Comment apporter lutilisateur tout le confort dutilisation possible et
lui garantir quil na pas perdu toute sa saisie ? Heureusement, lorsque lapplication
change dtat, nous pouvons tre prvenus grce des vnements. Ce sont des vne-
ments applicatifs que lon retrouve dans le chier dapplication que nous avons dj vu :
App.xaml. Par contre, ici nous allons nous intresser son code behind : App.xaml.cs
et notamment aux vnements dj gnrs pour nous. Ouvrez-le et vous pouvez voir :
144
LE TOMBSTONNING
1 // Code excuter lorsque l'application dmarre (par exemple ,
partir de Dmarrer)
2 // Ce code ne s'excute pas lorsque l'application est ractive
3 private void Application_Launching(object sender ,
LaunchingEventArgs e)
4 {
5 }
6
7 // Code excuter lorsque l'application est active (affiche
au premier plan)
8 // Ce code ne s'excute pas lorsque l'application est dmarre
pour la premire fois
9 private void Application_Activated(object sender ,
ActivatedEventArgs e)
10 {
11 }
12
13 // Code excuter lorsque l'application est dsactive (envoy
e l'arrire-plan)
14 // Ce code ne s'excute pas lors de la fermeture de l'
application
15 private void Application_Deactivated(object sender ,
DeactivatedEventArgs e)
16 {
17 }
18
19 // Code excuter lors de la fermeture de l'application (par
exemple , lorsque l'utilisateur clique sur Prcdent)
20 // Ce code ne s'excute pas lorsque l'application est dsactiv
e
21 private void Application_Closing(object sender ,
ClosingEventArgs e)
22 {
23 }
Les commentaires gnrs parlent deux-mmes. Ces mthodes sont donc lendroit idal
pour faire des sauvegardes de contexte. Voici la gure 11.11 un schma rcapitulatif
des dirents tats.
- Action vnement applicatif
1 Dmarrage Launching
2 Dsactivation Deactivated
3 Reprise rapide Activated
4 Reprise lente Activated
5 Fermeture Closing
6 Fermeture force par lOS -
145
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
Figure 11.11 Les dirents tats dune application Windows Phone
Lvnement Closing nest pas lev lorsque cest le systme dexploitation
qui choisit de terminer lapplication, par manque de ressources par exemple.
Imaginons que je sois en train de saisir un long texte dans mon application, que mon
tlphone sonne et que je doive partir durgence. Lapplication va commencer par pas-
ser en mode suspendu. Si je retourne dans mon application rapidement en appuyant
sur le retour arrire, alors je vais retrouver mon texte intact. Par contre, si celle-ci est
dsactive par le systme dexploitation, alors je peux dire adieu ma saisie. Et l, je
risque de maudire cette application et ne plus jamais lutiliser. Et cest encore pire si
cest moi qui relance depuis zro lapplication depuis le menu, je ne pourrais mme pas
maudire le systme dexploitation. Une solution est de sauvegarder ce texte au fur et
mesure de sa saisie. Comme a, si jamais lapplication est dsactive, je pourrai alors
proter des vnements applicatifs pour enregistrer ce texte dans la mmoire du tl-
phone, an de le repositionner si jamais lutilisateur r-ouvre lapplication. Mais avant
cela, essayons de bien comprendre le processus dactivation/dsactivation et modions
MainPage.xaml pour avoir ceci :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0">
2 <StackPanel >
3 <TextBox />
4 </StackPanel >
5 </Grid >
Et dans le code-behind :
146
LE TOMBSTONNING
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private bool _estNouvelleInstance = false;
4 private string laPage; // info conserver
5
6 public MainPage ()
7 {
8 InitializeComponent ();
9 _estNouvelleInstance = true;
10 }
11
12 protected override void OnNavigatedFrom(System.Windows.
Navigation.NavigationEventArgs e)
13 {
14 if (e.NavigationMode != System.Windows.Navigation.
NavigationMode.Back)
15 {
16 // l'appli est dsactive, la page est quitte
17 State["MainPage"] = laPage;
18 }
19 else
20 {
21 // on quitte l'appli en appuyant sur back
22 }
23 }
24
25 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
26 {
27 if (_estNouvelleInstance)
28 {
29 if (State.Count > 0)
30 {
31 // application a t dsactive par l'OS, on
peut accder au dictionnaire d'tat
32 // pour restaurer les infos
33 laPage = (string)State["MainPage"];
34 }
35 else
36 {
37 // quivalent un dmarrage de l'appli
38 laPage = "MainPage";
39 }
40 }
41 else
42 {
43 // la page est garde en mmoire , pas besoin d'
aller lire le dictionnaire d'tat
44 }
45 _estNouvelleInstance = false;
147
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
46 }
47 }
Jespre que les commentaires sont assez explicites. Ce quil faut retenir cest que si
nous dmarrons lapplication en appuyant sur

F5 , que nous saisissons un texte dans


le TextBox et que nous appuyons sur le bouton menu, alors lapplication est suspendue
(voir la gure 11.12).
Figure 11.12 Appui sur le bouton de menu pour que lapplication soit suspendue
Nous sommes alors passs dans la mthode OnNavigatedTo et nous sommes dans le cas
o _estNouvelleInstance vaut vrai et que le dictionnaire dtat est vide (dmarrage
de lapplication). Lorsquon clique sur le bouton de menu, alors nous passons dans la
mthode OnNavigatedFrom qui indique que la page est dsactive. Vous arrivez alors
sur la page daccueil de votre mulateur (ou de votre Windows Phone). Un petit clic
sur le bouton de retour vous ramne sur notre application avec la zone de texte qui
correspond ce que nous avons saisi. On repasse dans la mthode OnNavigatedTo avec
_estNouvelleInstance qui vaut faux. Ceci prouve bien que lapplication est intacte
en mmoire et que nous ne sommes pas repasss dans le constructeur de la classe. Il ny
a rien faire car lapplication est exactement la mme quavant son changement dtat.
Il ne reste plus qu cliquer nouveau sur la che de retour pour fermer lapplication
et ainsi repasser dans la mthode OnNavigatedFrom mais cette fois-ci dans le else,
quand e.NavigationMode vaut NavigationMode.Back. Remarquez que le dbogueur
est toujours en route et quil faut larrter. Voil pour ltat suspendu.
Pour simuler ltat dsactiv, il faut aller dans les proprits du projet en faisant un
148
LE TOMBSTONNING
clic droit dessus, puis proprits. On arrive sur lcran des proprits du projet, cliquez
sur dboguer et vous pouvez alors cocher la case qui permet de forcer passer dans
ltat dsactiv (Tombstone) lorsque lon suspend lapplication (voir la gure 11.13).
Figure 11.13 Activer le tombstoning de lapplication
Maintenant, lorsque vous allez appuyer sur

F5 , saisir un texte dans la TextBox, puis


appuyer sur le bouton de menu, lapplication sera dsactive, comme si ctait le sys-
tme dexploitation qui le faisait pour librer de la mmoire. Revenez en arrire pour
rveiller lapplication, nous pouvons constater que le TextBox est vide. Ltat de lappli-
cation nest pas conserv et nous passons cette fois-ci dans la mthode OnNavigatedTo
mais lorsque le dictionnaire dtat nest pas vide. Il contient en loccurrence ce que
nous avons associ la chane MainPage . Nous allons donc pouvoir nous servir du
dictionnaire dtat pour restaurer ltat de lapplication lorsque celle-ci est dsactive.
Noubliez pas quil ny a rien faire lorsque lapplication est suspendue.
Allez modier le XAML pour donner un nom notre TextBox :
1 <TextBox x:Name="LeTextBox" />
Puis modiez le code behind, tout en conservant le squelette de MainPage, pour avoir
ceci :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private bool _estNouvelleInstance = false;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8 _estNouvelleInstance = true;
9 }
10
149
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
11 protected override void OnNavigatedFrom(System.Windows.
Navigation.NavigationEventArgs e)
12 {
13 if (e.NavigationMode != System.Windows.Navigation.
NavigationMode.Back)
14 {
15 // l'appli est dsactive, la page est quitte
16 State["MonTexte"] = LeTextBox.Text;
17 }
18 else
19 {
20 // on quitte l'appli en appuyant sur back
21 }
22 }
23
24 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
25 {
26 if (_estNouvelleInstance)
27 {
28 if (State.Count > 0)
29 {
30 // application a t dsactive par l'OS , on
peut accder au dictionnaire d'tat pour
restaurer les infos
31 LeTextBox.Text = (string)State["MonTexte"];
32 }
33 else
34 {
35 // quivalent un dmarrage de l'appli
36 }
37 }
38 else
39 {
40 // la page est garde en mmoire , pas besoin d'
aller lire le dictionnaire d'tat
41 }
42 _estNouvelleInstance = false;
43 }
44 }
Et voil. Ltat de la zone de texte est restaur grce :
1 LeTextBox.Text = (string)State["MonTexte"];
Qui est excut lorsque lapplication est dsactive. Vous me direz quon sembte
peut-tre un peu pour rien. Ne pourrait-on pas remplacer la mthode OnNavigatedTo
par :
1 protected override void OnNavigatedTo(System.Windows.Navigation
.NavigationEventArgs e)
150
LE TOMBSTONNING
2 {
3 if (State.ContainsKey("MonTexte"))
4 LeTextBox.Text = (string)State["MonTexte"];
5 }
Car nalement, peu importe si on est en mode dmarr, suspendu ou dsactiv, tout
ce qui nous intresse cest que le TextBox soit rempli si jamais il la t auparavant.
Je vous dirais oui, mais. . . Ici, lappel au dictionnaire dtat est assez rapide, mais
imaginons que nous ayons besoin daller lire une information sur internet (ce que nous
apprendrons faire trs bientt), ou eectuer un calcul complexe, ou quoi que ce soit,
ce nest pas la peine de le faire si nous possdons dj linformation. Cela uidie
le redmarrage de lapplication, vite de consommer des datas pour rien, etc. Veillez
toujours ne pas faire des choses inutiles et gardez lesprit quun tlphone a des
ressources limites.
Et les vnements applicatifs ?
Ils servent aussi a. Lorsque lapplication est suspendue ou dsactive, nous avons
vu que lvnement application Deactivated tait lev. Cest galement lemplacement
idal pour faire persister des informations dans le dictionnaire dtat :
1 private void Application_Deactivated(object sender ,
DeactivatedEventArgs e)
2 {
3 PhoneApplicationService.Current.State["DateDernierLancement
"] = DateTime.Now;
4 }
De la mme faon, lorsque lapplication est ractive, que ce soit en reprise rapide
(depuis ltat suspendu) ou en reprise lente (depuis ltat dsactive), lvnement
applicatif Activated est lev. Cest galement un endroit idal pour prparer nouveau
ltat de notre application :
1 private void Application_Activated(object sender ,
ActivatedEventArgs e)
2 {
3 if (PhoneApplicationService.Current.State.ContainsKey("
DateDernierLancement"))
4 {
5 DateTime dernierLancement = (DateTime)
PhoneApplicationService.Current.State["
DateDernierLancement"];
6 if (DateTime.Now - dernierLancement > TimeSpan.
FromMinutes(30))
7 {
8 // si ca fait plus de trente minutes que l'
application est dsactive, mon information n'
est peut -tre plus jour
151
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
9 TelechargerLesNouvellesDonnees ();
10 }
11 }
12 }
Remarquez que le dictionnaire dtat est accessible via la pro-
prit PhoneApplicationService.Current.State["..."] depuis nim-
porte quel emplacement et via la proprit State["..."] depuis une page
(qui drive de PhoneApplicationPage). Cest la mme chose.
Mais bon, il y a encore un petit problme ! tant donn que nous ne matrisons pas le
passage en dsactiv, encore moins la fermeture force de lapplication par le systme
dexploitation, ou encore le redmarrage manuel de lapplication par lutilisateur (sil
relance lapplication depuis la page daccueil), nous risquons de perdre nouveau toutes
les informations que notre utilisateur a saisi mais cette fois-ci, pas parce que nous avons
mal gr la dsactivation, mais parce que lapplication sest termine !
La solution est dutiliser la mme mcanique mais en faisant persister les informations
dans la mmoire du tlphone ddie lapplication. Il sagit du rpertoire local (en
anglais Local folder), galement connu sous son ancien nom : IsolatedStorage. Voyez
cela un peu comme des chiers sur un disque dur o nous pouvons enregistrer ce que
bon nous semble. Puisque cette information persiste entre les dmarrages successifs de
lapplication, il sera possible denregistrer ltat de notre application an par exemple
que lutilisateur ne perde pas toute sa saisie. Je ne vais pas dtailler le code qui permet
denregistrer des informations dans la mmoire du tlphone, car jy reviendrai dans
un prochain chapitre.
Avant de terminer, sachez quil existe un autre tat, ltat Obscured, que lon peut
traduire par obscurci . Il sagit dun tat o une partie de lcran est masqu, par
exemple lorsquon reoit un SMS, un appel, une notication, etc. Lapplication reste
dans un tat o elle est en cours dexcution, mais lapplication peut devenir dicile
utiliser. Imaginons que votre utilisateur soit en plein compte rebours nal, prt
vaincre le boss nal et quil reoive un SMS juste au moment o il va gagner et qu
cause de cela il reoit la che fatale juste en plein milieu du cur. . ., il va maudire votre
application, juste titre ! Pour viter cela, il est possible dtre noti lorsque lapplica-
tion passe en mode Obscured, ce qui nous laisse par exemple lopportunit de faire une
pause dans notre compte rebours nal . . . Pour cela, rendez-vous dans le constructeur
de la classe App pour vous abonner aux vnements Obscured et Unobscured :
1 public App()
2 \{
3 // plein de choses ...
4
5 RootFrame.Obscured += RootFrame_Obscured;
6 RootFrame.Unobscured += RootFrame_Unobscured;
7 }
8
9 private void RootFrame_Unobscured(object sender , EventArgs e)
152
LE TOMBSTONNING
10 {
11 // L application quitte le mode Obscured
12 }
13
14 private void RootFrame_Obscured(object sender ,
ObscuredEventArgs e)
15 {
16 // L application passe en mode Obscured
17 bool estVerouille = e.IsLocked;
18 }
Remarquez que le paramtre de type ObscuredEventArgs permet de savoir si lcran
est verrouill ou non.
En rsum
Il est possible de naviguer de page en page dans une application grce au service
de navigation.
Le contrle HyperlinkButton permet de dmarrer une navigation trs simple-
ment.
Il est possible de faire transiter des informations de contexte entre les pages ; on
pourra utiliser la query string ou le dictionnaire dtat.
Pour dclencher un retour arrire par code, on utilisera la mthode GoBack()
du NavigationService.
On peut ajouter facilement une image daccueil une application Windows
Phone en utilisant une image JPEG, nomme SplashScreenImage.jpg.
Il est trs important de grer correctement les dirents tats par lesquels peut
passer une application an de fournir une exprience dutilisation la plus opti-
male.
153
CHAPITRE 11. UNE APPLICATION PLUSIEURS PAGES, LA NAVIGATION
154
Chapitre 12
TP 2 : Crer une animation de
transition entre les pages
Dicult :
Maintenant que nous avons vu comment naviguer entre les pages et que nous savons faire
des animations, il est temps de nous entrainer dans un contexte combin. Le but bien sr
est de vrier si vous avez bien compris ces prcdents chapitres et de vous exercer.
Ce TP va nous permettre de crer une animation de transition entre des pages et par la
mme occasion embellir nos applications avec tout notre savoir.
155
CHAPITRE 12. TP 2 : CRER UNE ANIMATION DE TRANSITION ENTRE
LES PAGES
Instructions pour raliser le TP
Nous allons donc raliser une animation de transition entre des pages, histoire que nos
navigations soient un peu plus jolies. Vous allez crer une application avec deux pages.
Vous pouvez mettre ce que vous voulez sur les pages, une image, du texte. . ., mais il
faudra que la premire page possde un bouton permettant de dclencher la navigation
vers la seconde page. Lanimation fera glisser le contenu de la page vers le bas jusqu
sortir de lcran tout en rduisant lopacit jusqu la disparition. Lanimation ne sera
pas trop longue, disons seconde, voire 1 seconde (ce qui est dj long !). Lachage
de la seconde page subira aussi une transition. Lanimation fera apparatre le contenu
de la page comme si elle apparaissait den haut et lopacit augmentera pour devenir
compltement visible. Bref, linverse de la premire transition.
Vous vous le sentez ? Alors, vous de jouer.
Si vous vous le sentez un peu moins, je vais vous donner quelques indications pour
raliser ce TP sereinement. La premire chose faire est danimer le contenu de la
page. Dans tous nos exemples, nous avons utilis un conteneur racine (bien souvent
une Grid), qui contient tous les lments de la page. Il sut de faire porter lanimation
sur ce contrle pour faire tout disparatre. Ensuite, mme si cela fonctionne, il est
plus propre dattendre la n de lanimation pour dclencher la navigation. Il faut donc
sabonner lvnement de n danimation et ce moment-l dclencher la navigation.
Enn, pour dmarrer la seconde animation, il faudra le faire depuis la mthode qui est
appele lorsquon arrive sur la seconde page. Voil, vous savez tout.
Correction
Passons la correction, maintenant que tout le monde a ralis ce d haut la main. Il
sagit dans un premier temps de crer deux pages direntes. Vous avez pu y mettre ce
que vous vouliez, il fallait juste un moyen de pouvoir naviguer sur une autre page. La
premire chose faire est donc de crer lanimation qui va permettre de faire disparaitre
lgamment la premire page. Il sagit dune animation qui cible le conteneur de premier
niveau de notre page, dans mon cas une Grid. tant donn que je vais avoir besoin de
faire une translation, je vais dnir une classe TranslateTransform dans la proprit
RenderTransform de ma grille :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RenderTransform >
3 <TranslateTransform x:Name="Translation" />
4 </Grid.RenderTransform >
5 [... reste du code supprim pour plus de lisibilit...]
6 <Button Content="Aller la page 2" Tap="Button_Tap" />
7 </Grid >
Mon Storyboard sera dclar dans les ressources de ma page :
1 <phone:PhoneApplicationPage.Resources >
2 <Storyboard x:Name="CachePage">
156
CORRECTION
3 <DoubleAnimation Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="Opacity"
4 From="1" To="0" Duration="0:0:0.5"
/>
5 <DoubleAnimation Storyboard.TargetName="Translation"
Storyboard.TargetProperty="Y"
6 From="0" To="800" Duration="0:0:0.5
" />
7 </Storyboard >
8 </phone:PhoneApplicationPage.Resources >
Lanimation consiste faire varier la proprit Opacity de la grille et la proprit Y de
lobjet de translation. Puis il faut dmarrer cette animation lors du clic sur le bouton
sachant quauparavant, je vais mabonner lvnement de n danimation an de
pouvoir dmarrer la navigation ce moment-l :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6 CachePage.Completed += CachePage_Completed;
7 }
8
9 private void CachePage_Completed(object sender , EventArgs e
)
10 {
11 NavigationService.Navigate(new Uri("/Page2.xaml",
UriKind.Relative));
12 }
13
14 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
15 {
16 CachePage.Begin ();
17 }
18
19 }
Lvnement de n danimation est videmment lvnement Completed, cest dans
la mthode associe que je dclencherai la navigation via la mthode Navigate du
NavigationService. Passons maintenant la deuxime page. Le principe est le mme,
voici le XAML qui nous intresse :
1 <phone:PhoneApplicationPage.Resources >
2 <Storyboard x:Name="AffichePage">
3 <DoubleAnimation Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="Opacity"
4 From="0" To="1" Duration="0:0:0.5"
/>
157
CHAPITRE 12. TP 2 : CRER UNE ANIMATION DE TRANSITION ENTRE
LES PAGES
5 <DoubleAnimation Storyboard.TargetName="Translation"
Storyboard.TargetProperty="Y"
6 From="-800" To="0" Duration="0:0:0.
5" />
7 </Storyboard >
8 </phone:PhoneApplicationPage.Resources >
9
10 <Grid x:Name="LayoutRoot" Background="Transparent">
11 <Grid.RenderTransform >
12 <TranslateTransform x:Name="Translation" />
13 </Grid.RenderTransform >
14 [... code supprim pour plus de lisibilit...]
15 </Grid >
Cette fois-ci on incrmente lopacit et on passe de -800 0 pour les valeurs de la
translation de Y. Cot code behind nous aurons :
1 public partial class Page2 : PhoneApplicationPage
2 {
3 public Page2()
4 {
5 InitializeComponent ();
6 }
7
8 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
9 {
10 AffichePage.Begin ();
11 base.OnNavigatedTo(e);
12 }
13 }
On rednit la mthode qui est appele lorsquon navigue sur la page an de dmarrer
lanimation. Et voil ! Quoique. . . ce nest pas tout fait complet en ltat car si vous
revenez sur la page prcdente en appuyant sur le bouton de retour arrire, vous vous
rendrez compte que la page est vide. Eh oui, nous avons fait disparaitre la page lors de
lanimation de transition! Nous devons donc arrter cette fameuse animation lorsque
nous revenons sur la page avec :
1 protected override void OnNavigatedTo(System.Windows.Navigation
.NavigationEventArgs e)
2 {
3 CachePage.Stop();
4 base.OnNavigatedTo(e);
5 }
Et voil, prsentes comme jai pu, nos deux animations (voir la gure 12.1).
158
CORRECTION
Figure 12.1 Rendu des animations de transitions
159
CHAPITRE 12. TP 2 : CRER UNE ANIMATION DE TRANSITION ENTRE
LES PAGES
Remarquez que jai choisi la valeur 800 pour lanimation car jai considr
que la plupart des rsolutions de tlphones taient du 800. Cest videment
une mauvaise ide car je ne connais pas le comportement sur les tlphones
qui ont une autre rsolution. Il aurait t judicieux de xer la valeur la
rsolution de lcran, sauf que nous ne savons pas encore comment faire.
Avant de terminer ce TP, notez que le toolkit pour Windows Phone, que nous dcou-
vrirons plus loin, possde tout un lot de transitions prtes lemploi.
160
Chapitre 13
Les proprits de dpendances et
proprits attaches
Dicult :
Il est temps de vous dire la vrit sur les proprits. Jusqu prsent, jai fait comme si
toutes les proprits que nous avons vues taient des proprits classiques au sens C#.
Elles sont en fait plus volues que a.
161
CHAPITRE 13. LES PROPRITS DE DPENDANCES ET PROPRITS
ATTACHES
Les proprits de dpendances
De leurs noms anglais dependency properties , ces proprits sont plus complexes
que la proprit de base de C# que nous connaissons, savoir :
1 public class MaClasse
2 {
3 public int MaPropriete { get; set; }
4 }
Avec une telle classe, il est possible dutiliser cette proprit ainsi :
1 MaClasse maClasse = new MaClasse ();
2 maClasse.MaPropriete = 6;
3 int valeur = maClasse.MaPropriete;
En XAML, nous avons dit que le code suivant :
1 <TextBlock Text="Je suis un texte" Foreground="Red" />
correspondait au code C# suivant :
1 TextBlock monTextBlock = new TextBlock ();
2 monTextBlock.Text = "Je suis un texte";
3 monTextBlock.Foreground = new SolidColorBrush(Colors.Red);
Ici, on ne le voit pas mais ces deux proprits sont en fait des proprits de dpendances.
Le vrai appel qui sopre derrire est quivalent :
1 TextBlock monTextBlock = new TextBlock ();
2 monTextBlock.SetValue(TextBlock.TextProperty , "Je suis un texte
");
3 monTextBlock.SetValue(TextBlock.ForegroundProperty , new
SolidColorBrush(Colors.Red));
La mthode SetValue est hrite de la classe de base DependencyObject dont hritent
tous les UIElement. La proprit de dpendance tend les fonctionnalits dune pro-
prit classique C#. Cest la base notamment du systme de liaison de donnes que
nous dcouvrirons plus loin. Cela permet de traiter la valeur dune proprit en fonc-
tion du contexte de lobjet et dtre potentiellement dtermine partir de plusieurs
sources de donnes. La proprit de dpendance peut galement avoir une valeur par
dfaut et des informations de description.
Ce quil faut retenir cest que la proprit de dpendance est une proprit
volue gre par le moteur XAML qui va permettre de grer les styles, les
animations, la liaison de donnes, . . .
Pour obtenir la valeur dune proprit de dpendance, on pourra utiliser :
1 string text = (string)monTextBlock.GetValue(TextBlock.
TextProperty);
162
LES PROPRITS ATTACHES
Les proprits attaches
Le mcanisme de proprit attache permet de rajouter des proprits un contexte
donn. Prenons par exemple le XAML suivant :
1 <Canvas >
2 <TextBlock Text="Je suis un texte" Canvas.Top="150" Canvas.
Left="80" />
3 </Canvas >
Il est possible dindiquer la position du TextBlock dans le Canvas. Or, le TextBlock ne
possde pas de proprit Canvas.Top ou Canvas.Left. Il sagit de proprits attaches
qui vont permettre dindiquer des informations pour le TextBlock, dans le contexte de
son conteneur, le Canvas. Cest bien le Canvas qui va se servir de ces proprits pour
placer correctement le TextBlock. Le mme principe sapplique la grille par exemple,
si vous vous rappelez, an dindiquer dans quelle ligne ou colonne se place un contrle :
1 <Grid >
2 <Grid.ColumnDefinitions >
3 <ColumnDefinition Width="*" />
4 <ColumnDefinition Width="*" />
5 </Grid.ColumnDefinitions >
6 <TextBlock Grid.Column="0" Text="Je suis un texte" />
7 <TextBlock Grid.Column="1" Text="Je suis un autre texte" />
8 </Grid >
On utilise ici la proprit attache Grid.Column pour indiquer la grille quel endroit
il faut placer nos TextBlock.
Allez, jarrte de vous embter avec ces proprits volues. Jen ai rapidement parl
pour que vous sachiez que quand je parle de proprits, je parle en fait de quelque
chose dun peu plus pouss que ce que nous connaissions dj.
Ce quil faut retenir cest quil y a un systme complexe derrire qui est presque invisible
pour une utilisation de dbutant. Si le sujet vous intresse, nhsitez pas poser des
questions ou aller chercher des informations sur internet.
Sachez enn quil est possible de crer nos propres proprits de dpendances et nos
propres proprits attaches, mais nous sortons du cadre dbutant et je ne le montrerai
pas dans ce cours.
En rsum
Les proprits de dpendances orent un mcanisme plus complet que la pro-
prit classique C#.
Ces proprits sont utilises par le moteur XAML pour grer les styles, la liaison
de donnes, etc.
En tant que dbutant, nous navons pas vraiment besoin de savoir ce quil se
cache l dessous.
163
CHAPITRE 13. LES PROPRITS DE DPENDANCES ET PROPRITS
ATTACHES
164
Chapitre 14
O est mon application ?
Dicult :
Nous avons commenc crer des applications, mais. . . que sont-elles rellement ? Lorsque
nous crons des programmes en C# pour Windows, nous obtenons des chiers excu-
tables dont lextension est .exe. Mais pour un tlphone, comment a marche ? Et lorsque
jajoute des images dans ma solution, o nissent-elles ? Voyons prsent les subtilits de
la construction dapplications pour Windows Phone.
165
CHAPITRE 14. O EST MON APPLICATION?
Le .XAP
Pour illustrer ce chapitre, crons un nouveau projet, que nous nommerons par exemple
DemoXap. Lorsque nous compilons notre application pour Windows Phone, celle-ci se
gnre par dfaut dans un sous rpertoire de notre projet : DemoXap\Bin\Debug, Debug
tant le mode de compilation par dfaut lorsque nous crons une solution. Nous verrons
dans la dernire partie comment passer le mode de compilation en Release.
Toujours est-il que dans ce rpertoire, il va sy gnrer plein de choses, mais une seule
nous intresse vraiment ici, cest le chier qui porte le nom du projet et dont lextension
est .xap. Dans mon cas, il sappelle DemoXap_Debug_AnyCPU.xap car mon mode de
compilation est Debug, Any Cpu (voir la gure 14.1).
Figure 14.1 Le mode de compilation est Debug, Any Cpu
Quest-ce donc que ce chier ? En fait, cest une archive au format compress (zip) qui
va contenir tous les chiers dont notre application va avoir besoin. Si vous louvrez avec
votre dcompresseur prfr, vous pourrez voir que cette archive contient les chiers
suivants :
Assets
Tiles
FlipCycleTileLarge.png
FlipCycleTileMedium.png
FlipCycleTileSmall.png
IconicTileMediumLarge.png
IconicTileSmall.png
AlignmentGrid.png
ApplicationIcon.png
AppManifest.xaml
DemoXap.dll
WMAppManifest.xml
Plein de choses que nous retrouvons dans notre solution. En fait, tout ce qui est du
XAML et du code a t compil dans lassembly DemoXap.dll, les chiers de Manifest
sont laisss dans larchive car ce sont eux qui donnent les instructions concernant la
conguration de lapplication. Et ensuite, il y a les quelques images.
Ajoutons un nouveau projet notre solution (clic droit sur la solution > Ajouter >
Nouveau projet), de type bibliothque de classes Windows Phone, que nous nommons
MaBibliotheque. Ciblez la plate-forme 8.0 et faites une rfrence cette assembly
depuis votre application DemoXap. Compilez et vous pourrez retrouver cette assembly
166
AFFICHAGE DIMAGES EN RESSOURCES
dans le .xap gnr. Nous retrouvons donc toutes les assemblys dont le projet a besoin
dans ce .xap.
Ajoutez prsent un nouvel lment dj existant votre projet et allez chercher une
image par exemple. Elle sajoute dans la solution et si vous compilez et que vous ouvrez
le chier .xap, alors cette image apparait dedans. Cest parce que votre image est par
dfaut ajoute avec laction de gnration Contenu . Si vous changez cette action
de gnration et que vous mettez Resource , alors cette fois-ci, elle napparait plus
dans le .xap. En fait, un chier inclus en tant que Resource est compil lintrieur
de son assembly. Si vous avez t attentifs aux chiers, vous aurez pu constater que
lassembly (DemoXap.dll) est beaucoup plus grosse lorsque limage est compile en
tant que ressource. Tandis que si elle est compile en tant que contenu, alors celle-ci
fait partie du .xap.
Achage dimages en ressources
Ceci implique des contraintes. Si nous voulons acher par code une image, nous avons
vu que nous pouvions compiler limage en tant que contenu et utiliser le code suivant :
1 <Image x:Name="MonImage" />
et
1 MonImage.Source = new BitmapImage(new Uri("/monimage.png",
UriKind.Relative));
Ceci sexplique simplement. tant donn que limage est inclue dans le .xap, il va
pouvoir aller la chercher tranquillement lemplacement /monimage.png, donc la
racine du package. Essayez dsormais de changer laction de gnration ressource, et
vous verrez que limage ne sache plus. En eet, limage nest plus cet emplacement
mais compile lintrieur de lassembly. Il est quand mme possible daccder son
contenu, mais cela demande daller lire lintrieur de lassembly, ce que lon peut faire
de cette faon :
1 MonImage.Source = new BitmapImage(new Uri("/DemoXap;component/
monimage.png", UriKind.Relative));
Bien sr, si limage nest pas place la racine, mais dans un sous rpertoire, il faudra
indiquer le sous rpertoire dans lURL de limage.
Remarquez que dune manire gnrale, il vaudra mieux positionner le plus
souvent possible laction de gnration contenu an de rduire la taille de
lassembly et ainsi augmenter les performances de chargement de celle-ci. Si
les images sont en ressources, elles se chargeront plus vite. Si elles sont en
contenu, alors cest lapplication qui se chargera plus vite. De mme, pour
des raisons de performances, vous aurez intrt utiliser des jpg partout sauf
si vous avez besoin de transparence.
167
CHAPITRE 14. O EST MON APPLICATION?
Accder au ux des ressources
Il est possible daccder en lecture aux ressources. Cela peut tre intressant par
exemple pour lire un chier texte, xml ou autre. Le chier doit bien sr avoir lac-
tion de gnration Ressource. Puis vous pouvez utiliser le code suivant :
1 StreamResourceInfo sr = Application.GetResourceStream(new Uri("
/DemoXap;component/MonFichier.txt", UriKind.Relative));
2 StreamReader s = new StreamReader(sr.Stream);
3 MonTextBlock.Text = s.ReadToEnd ();
4 s.Close();
En rsum
Une application Windows Phone est gnre sous la forme dune archive dont
lextension est .xap.
On peut embarquer des lments dans notre assembly en positionnant laction
de gnration Resource.
Un lment compil avec laction de gnration Contenu sera disponible direc-
tement dans le .xap.
168
Chapitre 15
ListBox
Dicult :
La ListBox est un lment incontournable dans la cration dapplications pour Windows
Phone. Elle permet un puissant achage dune liste dlment. Voyons tout de suite de
quoi il sagit car vous allez vous en servir trs souvent !
169
CHAPITRE 15. LISTBOX
Un contrle majeur
Utilisons notre designer prfr pour rajouter une ListBox dans notre page et nommons-
l ListeDesTaches, ce qui donne le XAML suivant :
1 <ListBox x:Name="ListeDesTaches">
2 </ListBox >
Une ListBox permet dacher des lments sous la forme dune liste. Pour ajouter des
lments, on peut utiliser le XAML suivant :
1 <ListBox x:Name="ListeDesTaches">
2 <ListBoxItem Content="Arroser les plantes" />
3 <ListBoxItem Content="Tondre le gazon" />
4 <ListBoxItem Content="Planter les tomates" />
5 </ListBox >
Ce qui donne la gure 15.1.
Figure 15.1 Une ListBox contenant 3 lments positionns par XAML
Il est cependant plutt rare dnumrer les lments dune ListBox directement dans
le XAML. En gnral, ces lments viennent dune source dynamique construite depuis
le code behind. Pour cela, il sut dalimenter la proprit ItemSource avec un objet
implmentant IEnumerable, par exemple une liste. Supprimons les ListBoxItem de
notre ListBox et utilisons ce code behind :
1 List <string > chosesAFaire = new List <string >
170
UN CONTRLE MAJEUR
2 {
3 "Arroser les plantes",
4 "Tondre le gazon",
5 "Planter les tomates"
6 };
7 ListeDesTaches.ItemsSource = chosesAFaire;
Il ne reste plus qu dmarrer lapplication. Nous pouvons voir que la ListBox sest
automatiquement remplie avec nos valeurs (voir la gure 15.2).
Figure 15.2 La ListBox est remplie depuis le code-behind
Et ceci sans rien faire de plus. Ce quil est important de remarquer, cest que si nous
ajoutons beaucoup dlments notre liste, alors celle-ci gre automatiquement un as-
censeur pour pouvoir faire dler la liste. La ListBox est donc une espce de ScrollVie-
wer qui contient une liste dlments dans un StackPanel. Tout ceci est gr nativement
par la ListBox.
Nous avons quand mme rencontr un petit truc trange. Dans le XAML, nous avons
mis la ListBox, mais la liste est vide, rien ne sache dans le designer. Ce qui nest
pas trs pratique pour crer notre page. Cest logique car lalimentation de la ListBox
est faite dans le constructeur, cest--dire lorsque nous dmarrons notre application.
Nous verrons plus loin comment y remdier. Lautre souci, cest que si vous essayez de
mettre des choses un peu plus complexes quune chane de caractre dans la ListBox,
par exemple un objet :
1 public partial class MainPage : PhoneApplicationPage
171
CHAPITRE 15. LISTBOX
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6
7 List <ElementAFaire > chosesAFaire = new List <
ElementAFaire >
8 {
9 new ElementAFaire { Priorite = 1, Description = "
Arroser les plantes"},
10 new ElementAFaire { Priorite = 2, Description = "
Tondre le gazon"},
11 new ElementAFaire { Priorite = 1, Description = "
Planter les tomates"},
12 new ElementAFaire { Priorite = 3, Description = "
Laver la voiture"},
13 };
14 ListeDesTaches.ItemsSource = chosesAFaire.OrderBy(e =>
e.Priorite);
15 }
16 }
17
18 public class ElementAFaire
19 {
20 public int Priorite { get; set; }
21 public string Description { get; set; }
22 }
vous aurez lachage suivant (voir la gure 15.3).
La ListBox ache la reprsentation de lobjet, cest--dire le rsultat de sa mthode
ToString(). Ce qui est un peu moche ici. Vous me direz, il sut de substituer la
mthode ToString() avec quelque chose comme a :
1 public class ElementAFaire
2 {
3 public int Priorite { get; set; }
4 public string Description { get; set; }
5
6 public override string ToString ()
7 {
8 return Priorite + " - " + Description;
9 }
10 }
Et laaire est rgle ! Et je vous rpondrai oui, parfait. Sauf que cela ne fonctionne que
parce que nous achons du texte ! Et si nous devions acher du texte et une image ?
Ou du texte et un bouton ?
172
GRER LES MODLES
Figure 15.3 Cest la reprsentation de lobjet qui sache ici dans la ListBox
Grer les modles
Cest l quinterviennent les modles, plus couramment appels en anglais : template.
Ils permettent de personnaliser le rendu de son contrle. Le contrle garde toute sa
logique mais peut nous coner le soin de grer lachage, si nous le souhaitons. Cest
justement ce que nous voulons faire.
Lutilisation de template est dirente de la rednition de la proprit
Content que nous avons dj fait dans la partie prcdente. Dune manire
gnrale, on rednit la proprit Content pour rednir le look gnral dun
contrle alors quon utilise les templates pour rednir lapparence de plu-
sieurs lments dune collection.
Nous allons donc rednir lachage de chaque lment de la liste. Pour cela, plutt
que dacher un simple texte, nous allons en proter pour acher une image pour la
priorit et le texte de la description. Si la priorit est gale 1, alors nous acherons
un rond rouge, sinon un rond vert (voir les gures 15.4 et 15.5).
Figure 15.4 Image rouge
173
CHAPITRE 15. LISTBOX
Figure 15.5 Image verte
Crez un rpertoire Images sous le rpertoire Assets par exemple et ajoutez les deux
images en tant que Contenu, comme nous lavons dj fait. Vous pouvez les tlcharger
la rouge ici - http://uploads.siteduzero.com/files/411001\T1\textbackslash{}_
412000/411562.png, et la verte l - http://uploads.siteduzero.com/files/411001\
T1\textbackslash{}_412000/411563.png.
La premire chose faire est de dnir le modle des lments de la ListBox. Cela se
fait avec le code suivant :
1 <ListBox x:Name="ListeDesTaches">
2 <ListBox.ItemTemplate >
3 <DataTemplate >
4 <StackPanel Orientation="Horizontal">
5 <Image Source="{Binding Image}" Width="30"
Height="30" />
6 <TextBlock Text="{Binding Description}" Margin=
"20 0 0 0" />
7 </StackPanel >
8 </DataTemplate >
9 </ListBox.ItemTemplate >
10 </ListBox >
On rednit la proprit ItemTemplate, cest--dire le modle dun lment de la liste.
Puis lintrieur de la balise DataTemplate, on peut rajouter nos propres contrles.
Ici, il y a un conteneur, le StackPanel, qui contient une image et une zone de texte
en lecture seule. Le DataTemplate doit toujours contenir un seul contrle. Vu que
vous avez lil, vous avez remarqu des extensions de balisage XAML lintrieur du
contrle Image et du contrle TextBlock. Je vais y revenir dans le prochain chapitre.
En attendant, nous allons modier lgrement le code behind de cette faon :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6
7 List <ElementAFaire > chosesAFaire = new List <
ElementAFaire >
8 {
9 new ElementAFaire { Priorite = 1, Description = "
Arroser les plantes"},
10 new ElementAFaire { Priorite = 2, Description = "
Tondre le gazon"},
11 new ElementAFaire { Priorite = 1, Description = "
Planter les tomates"},
174
GRER LES MODLES
12 new ElementAFaire { Priorite = 3, Description = "
Laver la voiture"},
13 };
14
15 ListeDesTaches.ItemsSource = chosesAFaire.OrderBy(e =>
e.Priorite).Select(e => new ElementAFaireBinding {
Description = e.Description , Image = ObtientImage(e.
Priorite) });
16 }
17
18 private BitmapImage ObtientImage(int priorite)
19 {
20 if (priorite <= 1)
21 return new BitmapImage(new Uri("/Assets/Images/vert
.png", UriKind.Relative));
22 return new BitmapImage(new Uri("/Assets/Images/rouge.
png", UriKind.Relative));
23 }
24 }
Pour rappel, la classe BitmapImage se trouve dans lespace de nom
System.Windows.Media.Imaging. Vriez galement que le lURL passe la
classe BitmapImage correspond lemplacement o vous avez ajout les images.
Nous aurons besoin de la nouvelle classe suivante :
1 public class ElementAFaireBinding
2 {
3 public BitmapImage Image { get; set; }
4 public string Description { get; set; }
5 }
Le principe est de construire des lments numrables partir de notre liste. Il sagit
dy mettre un nouvel objet qui possde une proprit Description et une proprit
Image qui contient un objet BitmapImage construit partir de la valeur de la priorit
de la tche. Il est important de constater que la classe contient des proprits qui ont
les mmes noms que ce quon a crit dans lextension de balisage vue plus haut.
1 <Image Source="{Binding Image}" Width="30" Height="30" />
2 <TextBlock Text="{Binding Description}" Margin="20 0 0 0" />
Jy reviendrai plus tard, mais nous avons ici fait ce quon appelle un binding, que lon
peut traduire par une liaison de donnes. Nous indiquons que nous souhaitons mettre la
valeur de la proprit Image de llment courant dans la proprit Source de limage
et la valeur de la proprit Description de llment courant dans la proprit Text
du TextBlock. Rappelez-vous, llment courant est justement un objet spcial qui
contient ces proprits.
Si nous excutons le code, nous obtenons donc la gure 15.6.
Magique ! Le seul dfaut viendrait de mes images qui ne sont pas transparentes. . .
175
CHAPITRE 15. LISTBOX
Figure 15.6 Les images sachent dans la ListBox grce au modle
Remarquons quil est obligatoire de crer une nouvelle classe contenant les
proprits Description et Image. Il naurait pas t possible dutiliser un
type anonyme car le type anonyme nest pas public mais internal. Dans
ce cas, il aurait fallu rajouter une instruction particulire permettant de dire
que les classes qui font la liaison de donnes ont le droit de voir les classes
internes. Ce qui est beaucoup plus compliqu que ce que nous avons fait !
Sachez quil existe beaucoup de contrles qui utilisent ce mme mcanisme de modle,
nous aurons loccasion den voir dautres. Cest une fonctionnalit trs puissante qui
nous laisse beaucoup de contrle sur le rendu de nos donnes.
Slection dun lment
La ListBox gre galement un autre point intressant : savoir quel lment est slec-
tionn. Cela se fait en toute logique grce un vnement. Pour que cela soit plus
simple, enlevons nos templates et modions le XAML pour avoir :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*" />
4 <RowDefinition Height="100" />
5 </Grid.RowDefinitions >
176
SLECTION DUN LMENT
6 <ListBox x:Name="ListeDesTaches" SelectionChanged="
ListeDesTaches_SelectionChanged">
7 </ListBox >
8 <TextBlock x:Name="Selection" Grid.Row="1" />
9 </Grid >
Notre grille a donc deux lignes, la premire contenant la ListBox et la seconde un
TextBlock. Remarquons lvnement SelectionChanged qui est associ la mthode
ListeDesTaches_SelectionChanged. Dans le code behind, nous aurons :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6 List <string > chosesAFaire = new List <string >
7 {
8 "Arroser les plantes",
9 "Tondre le gazon",
10 "Planter les tomates"
11 };
12 ListeDesTaches.ItemsSource = chosesAFaire;
13 }
14
15 private void ListeDesTaches_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
16 {
17 if (e.AddedItems.Count > 0)
18 Selection.Text = e.AddedItems[0]. ToString ();
19 }
20 }
Ce qui va nous permettre dacher dans le TextBlock la valeur de ce que nous avons
choisi (voir la gure 15.7).
Nous voyons au passage que la slection est mise en valeur automatiquement dans la
ListBox.
Remarquez qutant donn que notre ListBox a un nom et donc une variable pour
la manipuler, il est galement dobtenir la valeur slectionne grce linstruction
suivante :
1 private void ListeDesTaches_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
2 {
3 Selection.Text = ListeDesTaches.SelectedItem.ToString ();
4 }
Ce qui est dailleurs plus propre. Lobjet SelectedItem est du type object et sera
du type de ce que nous avons mis dans la proprit ItemsSource. tant donn que
nous avons mis une liste de chane de caractres, SelectedItem sera une chane, nous
pouvons donc faire :
177
CHAPITRE 15. LISTBOX
Figure 15.7 lment slectionn dans la ListBox
1 private void ListeDesTaches_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
2 {
3 Selection.Text = (string)ListeDesTaches.SelectedItem;
4 }
Dans lexemple prcdent, avec les templates, SelectedItem aurait bien sr
t du type ElementAFaireBinding.
De la mme faon, lindex de llment slectionn sera accessible grce la proprit
SelectedIndex et sera du type entier. Ce qui permet par exemple de prslectionner
une valeur dans notre ListBox au chargement de celle-ci. Ainsi, pour slectionner le
deuxime lment, je pourrais faire :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 List <string > chosesAFaire = new List <string >
5 {
6 "Arroser les plantes",
7 "Tondre le gazon",
8 "Planter les tomates"
9 };
178
SLECTION DUN LMENT
10 ListeDesTaches.ItemsSource = chosesAFaire;
11 ListeDesTaches.SelectedIndex = 1;
12 }
Ou encore :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 List <string > chosesAFaire = new List <string >
5 {
6 "Arroser les plantes",
7 "Tondre le gazon",
8 "Planter les tomates"
9 };
10 ListeDesTaches.ItemsSource = chosesAFaire;
11 ListeDesTaches.SelectedValue = chosesAFaire[1];
12 }
sachant que le fait dinitialiser la slection dun lment par code dclenche lvne-
ment de changement de slection ; ce qui nous arrange pour que notre TextBlock soit
rempli. Pour viter ceci, il faudrait associer la mthode lvnement de changement
de slection aprs avoir slectionn llment. Cela revient enlever la dnition de
lvnement dans le XAML :
1 <ListBox x:Name="ListeDesTaches">
2 </ListBox >
Et sabonner lvnement depuis le code behind, aprs avoir initialis llment
slectionn :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 List <string > chosesAFaire = new List <string >
5 {
6 "Arroser les plantes",
7 "Tondre le gazon",
8 "Planter les tomates"
9 };
10 ListeDesTaches.ItemsSource = chosesAFaire;
11 ListeDesTaches.SelectedValue = chosesAFaire[1];
12 ListeDesTaches.SelectionChanged +=
ListeDesTaches_SelectionChanged;
13 }
Pour nir sur la slection dun lment, il faut savoir que la ListBox peut permettre
de slectionner plusieurs lments en changeant sa proprit SelectionMode et en la
passant Multiple :
1 <ListBox x:Name="ListeDesTaches" SelectionChanged="
ListeDesTaches_SelectionChanged" SelectionMode="Multiple">
179
CHAPITRE 15. LISTBOX
2 </ListBox >
Et nous pourrons rcuprer les direntes valeurs slectionnes grce la collection
SelectedItems :
1 private void ListeDesTaches_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
2 {
3 string selection = string.Empty;
4 foreach (string choix in ListeDesTaches.SelectedItems)
5 {
6 selection += choix + ";";
7 }
8 Selection.Text = selection;
9 }
Trs bien tout a !
En rsum
La ListBox est un contrle trs utile qui permet dacher une liste dlments
trs facilement.
Il est possible de personnaliser ecacement le rendu de chaque lment dune
ListBox grce au systme de modles.
La ListBox est un contrle complet qui possde tout une gestion de llment
slectionn.
180
Chapitre 16
La manipulation des donnes
(DataBinding & Converters)
Dicult :
Sil y a vraiment un chapitre o il faut tre attentif, cest bien celui-l. La liaison de
donnes (ou databinding en anglais) est une notion indispensable et incontournable pour
toute personne souhaitant raliser des applications XAML srieuses. Nous allons voir dans
ce chapitre de quoi il sagit et comment le mettre en place.
181
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
Principe du Databinding
Le databinding se traduit en franais par liaison de donnes . Il sagit de la possibi-
lit de lier un contrle des donnes. Le principe consiste indiquer un contrle o il
peut trouver sa valeur et celui-ci se dbrouille pour lacher. Nous lavons entre-aperu
dans le chapitre prcdent avec la ListBox, il est temps de creuser un peu son fonc-
tionnement. Techniquement, le moteur utilise un objet de type Binding - http://msdn.
microsoft.com/fr-fr/library/system.windows.data.binding(v=vs.95).aspx qui
associe une source de donnes un lment de destination, do lemploi du mot rac-
courci binding pour reprsenter la liaison de donnes. Le binding permet de positionner
automatiquement des valeurs aux proprits des contrles en fonction du contenu de la
source de donnes. En eet, il est trs frquent de mettre des valeurs dans des TextBox,
dans des TextBlock ou dans des ListBox, comme nous lavons fait. Le binding est l
pour faciliter tout ce qui peut tre automatisable et risque derreurs. De plus, si la
source de donnes change, il est possible de faire en sorte que le contrle soit automa-
tiquement mis jour. Inversement, si des modications sont faites depuis linterface,
alors on peut tre noti automatiquement des changements.
Le binding des donnes
Pour illustrer le fonctionnement le plus simple du binding, nous allons lier une zone de
texte modiable (TextBox) une proprit dune classe. Puisque le TextBox travaille
avec du texte, il faut crer une proprit de type string sur une classe. Cette classe sera
le contexte de donnes du contrle. Crons donc la nouvelle classe suivante :
1 public class Contexte
2 {
3 public string Valeur { get; set; }
4 }
Et une instance de cette classe dans notre code behind :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private Contexte contexte;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8
9 contexte = new Contexte { Valeur = "Nicolas" };
10 DataContext = contexte;
11 }
12 }
Nous remarquons la n du constructeur que la proprit DataContext de la page
est initialise avec notre contexte de donnes, tape obligatoire permettant de lier la
182
LE BINDING DES DONNES
page au contexte de donnes. Chaque objet FrameworkElement possde une proprit
DataContext et chaque lment enfant dun autre lment hrite de son contexte de
donnes implicitement. Cest pour cela quici on initialise notre contexte de donnes
au niveau de la page an que tous les lments contenus dans la page hritent de ce
contexte de donnes.
Il ne reste plus qu ajouter un contrle TextBox qui sera li cette proprit :
1 <TextBox Text="{Binding Valeur}" Height="80"/>
Cela se fait grce lexpression de balisage {Binding}. Lorsque nous excutons notre
application, nous pouvons voir que la TextBox sest correctement remplie avec la chane
de caractres Nicolas (voir la gure 16.1).
Figure 16.1 La valeur du TextBox est lie la proprit Valeur
Et tout a automatiquement, sans avoir besoin de positionner la valeur de la proprit
Text depuis le code behind.
Quest-ce qua fait le moteur de binding ? Il est all voir dans son contexte (proprit
DataContext) puis il est all prendre le contenu de la proprit Valeur de ce contexte
pour le mettre dans la proprit Text du TextBox, cest--dire la chane Nicolas .
Il faut faire attention car dans le XAML nous crivons du texte, si nous orthographions
mal Valeur, par exemple en oubliant le u :
1 <TextBox Text="{Binding Valer}" Height="80"/>
183
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
Alors la liaison de donnes naura pas lieu car la proprit est introuvable sur lobjet
Contexte. Ce qui est vrai ! Valer nexiste pas. Il ny a pas de vrication la
compilation, cest donc au moment de lexcution que nous remarquerons labsence
du binding. La seule information que nous aurons, cest dans la fentre de sortie du
dbogueur, o nous aurons :
1 System.Windows.Data Error: BindingExpression path error: 'Valer
' property not found on 'DemoPartie2.Contexte ' 'DemoPartie2.
Contexte '
2 (HashCode=54897010). BindingExpression: Path='Valer ' DataItem='
DemoPartie2.Contexte ' (HashCode=54897010); target element is
'System.Windows.Controls.TextBox '
3 (Name=''); target property is 'Text ' (type 'System.String ')..
indiquant que la proprit na pas t trouve.
Attention, le binding ne fonctionne quavec une proprit ayant la visibilit
public.
Il est galement possible de dnir un binding par code behind, pour cela enlevez
lexpression de balisage dans le XAML et donnez un nom votre contrle :
1 <TextBox x:Name="MonTextBox" Height="80"/>
puis utilisez le code behind suivant :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private Contexte contexte;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8
9 MonTextBox.SetBinding(TextBox.TextProperty , new Binding
("Valeur"));
10 contexte = new Contexte { Valeur = "Nicolas" };
11 DataContext = contexte;
12 }
13 }
La classe Binding fait partie de lespace de nom System.Windows.Data que
vous devrez ajouter avec un using.
On en prote pour constater que le binding se fait bien avec une proprit de dpen-
dance, ici TextBox.TextProperty.
Le binding est trs pratique pour quun contrle se remplisse avec la bonne valeur.
184
LE BINDING DES DONNES
Il est possible de modier la valeur ache dans la zone de texte trs facilement en
modiant la valeur du contexte depuis le code. Pour cela, changeons le XAML pour
ajouter un bouton qui va nous permettre de dclencher ce changement de valeur :
1 <StackPanel >
2 <TextBox Text="{Binding Valeur}" Height="80"/>
3 <Button Content="Changer valeur" Tap="Button_Tap" />
4 </StackPanel >
Et dans lvnement de Tap, faisons :
1 private void button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 if (contexte.Valeur == "Nicolas")
4 contexte.Valeur = "Jrmie";
5 else
6 contexte.Valeur = "Nicolas";
7 }
Par contre, il va manquer quelque chose. Un moyen de dire la page h, jai
modi un truc, il faut que tu regardes si tu es impact . a, cest le rle de
linterface INotifyPropertyChanged - http://msdn.microsoft.com/fr-fr/library/
system.componentmodel.inotifypropertychanged.aspx. Notre classe de contexte
doit implmenter cette interface et faire en sorte que quand on modie la proprit,
elle lve lvnement qui va permettre linterface de se mettre jour. Notre classe de
contexte va donc devenir :
1 public class Contexte : INotifyPropertyChanged
2 {
3 private string valeur;
4 public string Valeur
5 {
6 get
7 {
8 return valeur;
9 }
10 set
11 {
12 if (value == valeur)
13 return;
14 valeur = value;
15 NotifyPropertyChanged("Valeur");
16 }
17 }
18
19 public event PropertyChangedEventHandler PropertyChanged;
20
21 public void NotifyPropertyChanged(string nomPropriete)
22 {
23 if (PropertyChanged != null)
185
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
24 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
25 }
26 }
Noubliez pas de rajouter le using System.ComponentModel;
Limplmentation de linterface INotifyPropertyChanged est trs classique
dans les applications XAML, aussi cette faon de faire est souvent factorise
dans des classes mres. Vous le verrez dans le chapitre suivant.
Ici, lorsque nous aectons une valeur la proprit, la mthode NotifyPropertyChanged
est appele en passant en paramtre le nom de la proprit de la classe quil faut ra-
fraichir sur la page. Attention, cest une erreur classique de ne pas avoir le bon nom de
proprit en paramtres, faites-y attention.
Notez quavec la version 8.0 du SDK (en fait, grce au framework 4.5), il est possible
dutiliser une autre solution pour implmenter INotifyPropertyChanged sans avoir
linconvnient de devoir passer une chane de caractre en paramtre. Il sut dutiliser
lattribut de mthode CallerMemberName - http://msdn.microsoft.com/fr-Fr/
library/system.runtime.compilerservices.callermembernameattribute.aspx,
qui permet dobtenir le nom de la proprit (ou mthode) qui a appel notre mthode,
en loccurrence il sagira justement du nom de la proprit quon aurait pass en
paramtre :
1 public class Contexte : INotifyPropertyChanged
2 {
3 private string valeur;
4 public string Valeur
5 {
6 get { return valeur; }
7 set { NotifyPropertyChanged(ref valeur , value); }
8 }
9
10 public event PropertyChangedEventHandler PropertyChanged;
11
12 public void NotifyPropertyChanged(string nomPropriete)
13 {
14 if (PropertyChanged != null)
15 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
16 }
17
18 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
19 {
186
LE BINDING DES DONNES
20 if (object.Equals(variable , valeur)) return false;
21
22 variable = valeur;
23 NotifyPropertyChanged(nomPropriete);
24 return true;
25 }
26 }
La syntaxe est plus lgante et il ny a pas de risque de mal orthographier le nom de la
proprit. Par contre, je suis dsol pour ceux qui suivent le cours avec la version 7.1
du SDK, il faudra continuer utiliser la solution que jai prsente juste avant.
Note, il faudra inclure lespace de nom :
1 using System.Runtime.CompilerServices;
Relanons lapplication, nous pouvons voir que le clic sur le bouton entrane bien le
changement de valeur dans la TextBox.
Ok, cest bien beau tout a, mais nest-ce pas un peu compliqu par rapport
ce quon a dj fait, savoir modier directement la valeur de la proprit
Text ?
Eectivement, dans ce cas-l, on pourrait juger que cest sortir lartillerie lourde pour
pas grand-chose. Cependant cest une bonne pratique dans la mesure o on automatise
le processus de mise jour de la proprit. Vous aurez remarqu que lon ne manipule
plus directement le contrle mais une classe qui na rien voir avec le TextBox. Et
quand il y a plusieurs valeurs mettre jour dun coup, cest dautant plus facile. De
plus, nous pouvons faire encore mieux avec ce binding grce la bidirectionnalit de la
liaison de donnes. Par exemple, modions le XAML pour rajouter encore un bouton :
1 <StackPanel >
2 <TextBox Text="{Binding Valeur , Mode=TwoWay}" Height="80"/>
3 <Button Content="Changer valeur" Tap="Button_Tap" />
4 <Button Content="Afficher valeur" Tap="Button_Tap_1" />
5 </StackPanel >
La mthode associe ce nouveau clic achera la valeur du contexte :
1 private void button_Tap_1(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 MessageBox.Show(contexte.Valeur);
4 }
On utilise pour cela la mthode MessageBox.Show qui ache une petite bote de dia-
logue minimaliste. Les lecteurs attentifs auront remarqu que jai enrichi le binding
sur la Valeur en rajoutant un Mode=TwoWay. Ceci permet dindiquer que le binding
seectue dans les deux sens. Cest--dire que si je modie la proprit de la classe
de contexte, alors linterface est mise jour. Inversement, si je modie la valeur de la
187
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
TextBox avec le clavier virtuel, alors la proprit de la classe est galement mise jour.
Cest cela que va servir notre deuxime bouton. Dmarrez lapplication, modiez la
valeur du champ avec le clavier virtuel et cliquez sur le bouton permettant dacher
la valeur (voir la gure 16.2).
Figure 16.2 La valeur est ache grce la liaison de donnes bidirectionnelle
La valeur est bien rcupre. Vous pouvez faire le test en enlevant le mode TwoWay,
vous verrez que vous ne rcuprerez pas la bonne valeur. Plutt pas mal non ?
Maintenant que nous avons un peu mieux compris le principe du binding, il est temps
de prciser un point important. Pour illustrer le fonctionnement du binding, jai cr
une classe puis jai cr une variable lintrieur de cette classe contenant une instance
de cette classe. Puis jai reli cette classe au contexte de donnes de la page. En gnral,
on utilise ce dcoupage dans une application utilisant le patron de conception MVVM
(Model-View-ViewModel ). Je parlerai de ce design pattern dans le prochain chapitre.
Remarquez que lon voit souvent la construction o cest la classe de la page
qui sert de contexte de donnes de la page. Cela veut dire quon peut modier
lexemple prcdent pour que a soit la classe MainPage qui implmente linterface
INotifyPropertyChanged, ce qui donne :
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 private string valeur;
4 public string Valeur
5 {
188
LE BINDING DES DONNES
6 get { return valeur; }
7 set { NotifyPropertyChanged(ref valeur , value); }
8 }
9
10 public event PropertyChangedEventHandler PropertyChanged;
11
12 public void NotifyPropertyChanged(string nomPropriete)
13 {
14 if (PropertyChanged != null)
15 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
16 }
17
18 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
19 {
20 if (object.Equals(variable , valeur)) return false;
21
22 variable = valeur;
23 NotifyPropertyChanged(nomPropriete);
24 return true;
25 }
26
27 public MainPage ()
28 {
29 InitializeComponent ();
30
31 Valeur = "Nicolas";
32 DataContext = this;
33 }
34
35 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
36 {
37 if (Valeur == "Nicolas")
38 Valeur = "Jrmie";
39 else
40 Valeur = "Nicolas";
41 }
42 private void Button_Tap_1(object sender , System.Windows.
Input.GestureEventArgs e)
43 {
44 MessageBox.Show(Valeur);
45 }
46 }
La classe Contexte na plus de raison dtre. Tout est port par la classe reprsentant
la page. On aecte donc lobjet this la proprit DataContext de la page. Cette
construction est peut-tre un peu plus perturbante dun point de vue architecture
o on a tendance mlanger les responsabilits dans la classe mais elle a lavantage
189
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
de simplier pas mal le travail. Personnellement jemploie trs rarement ce genre de
construction (jutilise plutt un driv de la premire solution), mais je lutiliserai de
temps en temps dans ce cours pour simplier le code.
Notre ListBox fonctionne galement avec le binding. Il sut dutiliser lexpression de
balisage avec la proprit ItemsSource :
1 <ListBox ItemsSource="{Binding Prenoms}" />
Nous aurons bien sr dni la proprit Prenoms dans notre contexte :
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 private List <string > prenoms;
4 public List <string > Prenoms
5 {
6 get { return prenoms; }
7 set { NotifyPropertyChanged(ref prenoms , value); }
8 }
9
10 public event PropertyChangedEventHandler PropertyChanged;
11
12 public void NotifyPropertyChanged(string nomPropriete)
13 {
14 if (PropertyChanged != null)
15 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
16 }
17
18 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
19 {
20 if (object.Equals(variable , valeur)) return false;
21
22 variable = valeur;
23 NotifyPropertyChanged(nomPropriete);
24 return true;
25 }
26
27 public MainPage ()
28 {
29 InitializeComponent ();
30
31 Prenoms = new List <string > { "Nicolas", "Jrmie", "
Delphine" };
32 DataContext = this;
33 }
34 }
Ce qui donne la gure 16.3.
190
LE BINDING DES DONNES
Figure 16.3 Liaison de donnes avec une ListBox
Le binding est encore plus puissant que a, voyons encore un point intressant. Il sagit
de la capacit de lier une proprit dun contrle la proprit dun autre contrle.
Par exemple, mettons un TextBlock en plus de notre ListBox :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <Grid.ColumnDefinitions >
3 <ColumnDefinition Width="*" />
4 <ColumnDefinition Width="*" />
5 </Grid.ColumnDefinitions >
6 <ListBox x:Name="ListeBoxPrenoms" ItemsSource="{Binding
Prenoms}" />
7 <TextBlock Grid.Column="1" Text="{Binding ElementName=
ListeBoxPrenoms , Path=SelectedItem}" Foreground="Red" />
8 </Grid >
Regardons lexpression de binding du TextBlock, nous indiquons que nous vou-
lons lier la valeur du TextBlock la proprit SelectedItem du contrle nomm
ListeBoxPrenoms. Ici cela voudra dire que lorsque nous slectionnerons un lment
dans la ListBox, alors celui-ci sera automatiquement ach dans le TextBlock, sans
avoir rien dautre faire comme le montre la gure 16.4.
Tout simplement !
Voil pour cet aperu du binding. Nous nen avons pas vu toutes les subtilits mais ce
que nous avons tudi ici vous sera grandement utile et bien souvent susant dans vos
191
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
Figure 16.4 Liaison de donnes entre proprits de contrles
futures applications Windows Phone !
Binding et mode design
Vous vous rappelez notre ListBox quelques chapitres avant ? Nous avions cr une
ListBox avec une liste de choses faire. Cette liste de choses faire tait alimente
par la proprit ItemsSource dans le constructeur de la page. Le problme cest que
notre ListBox tait vide en mode design. Du coup, pas facile pour faire du style, pour
mettre dautres contrles, etc. Le binding va nous permettre de rsoudre ce problme.
Prenons le code XAML suivant :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0">
2 <ListBox ItemsSource="{Binding ListeDesTaches}" >
3 <ListBox.ItemTemplate >
4 <DataTemplate >
5 <StackPanel Orientation="Horizontal">
6 <Image Source="{Binding Image}" Width="30"
Height="30" />
7 <TextBlock Text="{Binding Description}"
Margin="20 0 0 0" />
8 </StackPanel >
9 </DataTemplate >
10 </ListBox.ItemTemplate >
192
BINDING ET MODE DESIGN
11 </ListBox >
12 </Grid >
Avec dans le code behind :
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 private IEnumerable <ElementAFaireBinding > listeDesTaches;
4 public IEnumerable <ElementAFaireBinding > ListeDesTaches
5 {
6 get { return listeDesTaches; }
7 set { NotifyPropertyChanged(ref listeDesTaches , value);
}
8 }
9
10 public event PropertyChangedEventHandler PropertyChanged;
11
12 public void NotifyPropertyChanged(string nomPropriete)
13 {
14 if (PropertyChanged != null)
15 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
16 }
17
18 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
19 {
20 if (object.Equals(variable , valeur)) return false;
21
22 variable = valeur;
23 NotifyPropertyChanged(nomPropriete);
24 return true;
25 }
26
27 public MainPage ()
28 {
29 InitializeComponent ();
30
31 List <ElementAFaire > chosesAFaire = new List <
ElementAFaire >
32 {
33 new ElementAFaire { Priorite = 1, Description = "
Arroser les plantes"},
34 new ElementAFaire { Priorite = 2, Description = "
Tondre le gazon"},
35 new ElementAFaire { Priorite = 1, Description = "
Planter les tomates"},
36 new ElementAFaire { Priorite = 3, Description = "
Laver la voiture"},
37 };
193
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
38
39 ListeDesTaches = chosesAFaire.OrderBy(e => e.Priorite).
Select(e => new ElementAFaireBinding { Description =
e.Description , Image = ObtientImage(e.Priorite) });
40
41 DataContext = this;
42 }
43
44 private BitmapImage ObtientImage(int priorite)
45 {
46 if (priorite <= 1)
47 return new BitmapImage(new Uri("/Assets/Images/vert
.png", UriKind.Relative));
48 return new BitmapImage(new Uri("/Assets/Images/rouge.
png", UriKind.Relative));
49 }
50 }
51
52 public class ElementAFaire
53 {
54 public int Priorite { get; set; }
55 public string Description { get; set; }
56 }
57 public class ElementAFaireBinding
58 {
59 public BitmapImage Image { get; set; }
60 public string Description { get; set; }
61 }
Pour linstant, rien na chang, la ListBox est toujours vide en mode design. Sauf que
nous avons galement la possibilit de lier le mode design un contexte de design.
Crons donc une nouvelle classe :
1 public class MainPageDesign
2 {
3 public IEnumerable <ElementAFaireBinding > ListeDesTaches
4 {
5 get
6 {
7 return new List <ElementAFaireBinding >
8 {
9 new ElementAFaireBinding { Image = new
BitmapImage(new Uri("/Assets/Images/vert.png
", UriKind.Relative)), Description = "
Arroser les plantes"},
10 new ElementAFaireBinding { Image = new
BitmapImage(new Uri("/Assets/Images/rouge.
png", UriKind.Relative)), Description = "
Tondre le gazon"},
11 new ElementAFaireBinding { Image = new
BitmapImage(new Uri("/Assets/Images/rouge.
194
BINDING ET MODE DESIGN
png", UriKind.Relative)), Description = "
Planter les tomates"},
12 new ElementAFaireBinding { Image = new
BitmapImage(new Uri("/Assets/Images/vert.png
", UriKind.Relative)), Description = "Laver
la voiture"},
13 }; ;
14 }
15 }
16 }
Cette classe ne fait que renvoyer une proprit ListeDesTaches avec des valeurs de
design. Compilez et rajoutez maintenant dans le XAML linstruction suivante avant le
conteneur de plus haut niveau :
1 <d:DesignProperties.DataContext >
2 <design:MainPageDesign />
3 </d:DesignProperties.DataContext >
Ceci permet de dire que le contexte de design est aller chercher dans la classe
MainPageDesign. Attention, la classe MainPageDesign nest pas connue de la page !
Il faut lui indiquer o elle se trouve, en indiquant son espace de nom, un peu
comme un using C#. Cette proprit se rajoute dans les proprits de la page,
<phone:PhoneApplicationPage> :
1 <phone:PhoneApplicationPage
2 x:Class="DemoPartie2.MainPage"
3 [... plein de choses ...]
4 xmlns:design="clr -namespace:DemoPartie2"
5 shell:SystemTray.IsVisible="True">
Avec cette criture, je lui dis que le raccourci design correspond lespace de nom
DemoPartie2.
Nous commenons voir apparatre des choses dans le designer de Visual Studio (voir
la gure 16.5).
Avouez que cest beaucoup plus pratique pour raliser le design de sa page.
Dans la mesure o le contexte de la page et le contexte de design doivent
contenir des proprits communes, cest une bonne ide de faire en sorte
quils implmentent tous les deux une interface qui contienne les proprits
implmenter des deux cts. . .
Avant de terminer, il faut savoir que Blend est galement capable de nous gnrer des
donnes de design sans que lon ait forcment besoin de crer une classe spcique. Pour
illustrer ceci, repartez dune nouvelle page vide. Puis ouvrez la page dans Expression
Blend.
195
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
Figure 16.5 Le designer ache les donnes de design grce la liaison de donnes
196
BINDING ET MODE DESIGN
Si vous suivez ce cours pas pas, vous vous trouvez srement dans lespace
de travail animation. Revenez lespace de travail design (menu Fentre >
Espaces de travail > Design).
Cliquez sur longlet donnes, puis sur licne tout droite crer des exemples de
donnes (voir la gure 16.6).
Figure 16.6 Cration des exemples de donnes dans Blend
Cliquez sur nouvel exemple de donnes dans le menu propos. Indiquez un nom pour
la source de donnes et choisissez de la dnir dans ce document uniquement (voir la
gure 16.7).
Figure 16.7 Cration de la source de donnes
Nous obtenons notre source de donnes, comme vous pouvez le voir la gure 16.8.
Figure 16.8 La source de donnes est visibles dans lcran de donnes
197
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
Elle est compose dune collection dobjets contenant 2 proprits. Property1 est de
type chane de caractres et Property2 est de type boolen (on peut le voir en cliquant
sur les petits boutons droite). Renommez la premire en Description et la seconde
en Image, puis cliquez sur licne droite pour changer le type de la proprit de la
seconde, comme sur la gure 16.9.
Figure 16.9 Modication du type de la proprit
Et choisissez le type Image (voir la gure 16.10).
Figure 16.10 Le type de la donnes est dsormais Image
Nous avons cr ici un jeu de donnes, stockes sous la forme dun chier XAML. Il
est possible de modier les donnes en cliquant sur le bouton modifier les exemples
de valeurs (voir la gure 16.11).
Nous obtenons une fentre de ce style (voir la gure 16.12).
On peut y mettre nos propres valeurs. Ici, jai chang le premier lment pour lui
indiquer la valeur que je voulais et limage que je souhaitais, mais il est galement
possible dindiquer un rpertoire pour slectionner les images. Maintenant, il est temps
dutiliser nos donnes. Slectionnez la collection et faites-la glisser dans la fentre de
design, comme indiqu sur la gure 16.13.
Il vous cre automatiquement une ListBox avec les nouvelles donnes de la source de
donnes (voir la gure 16.14).
198
BINDING ET MODE DESIGN
Figure 16.11 Modication des exemples de valeurs
Figure 16.12 Fentre de modication des exemples de valeurs
199
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
Figure 16.13 La source de donnes est glisse dans le designer
Figure 16.14 Une ListBox est automatiquement cre partir de la source de donnes
200
UTILISER LOBSERVABLECOLLECTION
Utiliser lObservableCollection
Avant de terminer sur la liaison de donnes, reprenons un exemple simpli de notre
liste de taches. Avec le XAML suivant :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*"/>
4 <RowDefinition Height="100"/>
5 </Grid.RowDefinitions >
6 <ListBox ItemsSource="{Binding ListeDesTaches}" >
7 <ListBox.ItemTemplate >
8 <DataTemplate >
9 <StackPanel Orientation="Horizontal">
10 <TextBlock Text="{Binding Priorite}" Margin
="20 0 0 0" />
11 <TextBlock Text="{Binding Description}"
Margin="20 0 0 0" />
12 </StackPanel >
13 </DataTemplate >
14 </ListBox.ItemTemplate >
15 </ListBox >
16 <Button Content="Ajouter un lment" Tap="Button_Tap" Grid.
Row="1" />
17 </Grid >
O nous achons notre liste des tches avec la valeur de la priorit et la description
dans des TextBlock. Nous disposons galement dun bouton en bas pour rajouter un
nouvel lment. Le code behind sera :
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 private List <ElementAFaire > listeDesTaches;
4 public List <ElementAFaire > ListeDesTaches
5 {
6 get { return listeDesTaches; }
7 set { NotifyPropertyChanged(ref listeDesTaches , value);
}
8 }
9
10 public event PropertyChangedEventHandler PropertyChanged;
11
12 public void NotifyPropertyChanged(string nomPropriete)
13 {
14 if (PropertyChanged != null)
15 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
16 }
17
201
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
18 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
19 {
20 if (object.Equals(variable , valeur)) return false;
21
22 variable = valeur;
23 NotifyPropertyChanged(nomPropriete);
24 return true;
25 }
26
27 public MainPage ()
28 {
29 InitializeComponent ();
30
31 List <ElementAFaire > chosesAFaire = new List <
ElementAFaire >
32 {
33 new ElementAFaire { Priorite = 1, Description = "
Arroser les plantes"},
34 new ElementAFaire { Priorite = 2, Description = "
Tondre le gazon"},
35 new ElementAFaire { Priorite = 1, Description = "
Planter les tomates"},
36 new ElementAFaire { Priorite = 3, Description = "
Laver la voiture"},
37 };
38
39 ListeDesTaches = chosesAFaire.OrderBy(e => e.Priorite).
ToList ();
40
41 DataContext = this;
42 }
43
44 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
45 {
46 ListeDesTaches.Add(new ElementAFaire { Priorite = 1,
Description = "Faire marcher ce binding !" });
47 }
48 }
49
50 public class ElementAFaire
51 {
52 public int Priorite { get; set; }
53 public string Description { get; set; }
54 }
La dirence avec la version prcdente est que nous utilisons une
List<ElementAFaire> comme type dobjet li la source de donnes de la
ListBox. Nous pouvons galement voir que dans lvnement de clic sur le bouton,
202
UTILISER LOBSERVABLECOLLECTION
nous ajoutons un nouvel lment la liste des taches, en utilisant la mthode Add()
de la classe List<>. Si nous excutons notre application et que nous cliquons sur
le bouton, un lment est rajout la liste, sauf que rien nest visible dans notre
ListBox. Problme !
Ah oui, cest vrai, nous navons pas inform la page que la ListBox devait se mettre
jour. Pour ce faire, il faudrait modier lvnement de clic sur le bouton de cette faon :
1 List <ElementAFaire > nouvelleListe = new List <ElementAFaire >(
ListeDesTaches);
2 nouvelleListe.Add(new ElementAFaire { Priorite = 1, Description
= "Faire marcher ce binding !" });
3 ListeDesTaches = nouvelleListe;
Cest--dire crer une copie de la liste, ajouter un nouvel lment et aecter cette
nouvelle liste la proprit ListDesTaches. Ce qui devient peu naturel . . .
Cest parce que la liste nimplmente pas INotifyCollectionChanged qui permet den-
voyer des vnements sur lajout ou la suppression dun lment dans une liste. Heu-
reusement il existe une autre classe dans le framework .NET qui implmente dj ce
comportement, il sagit de la classe ObservableCollection - http://msdn.microsoft.
com/fr-fr/library/vstudio/ms668604(v=vs.95).aspx. Il sagit dune liste volue
prenant en charge les mcanismes de notication automatiquement lorsque nous faisons
un ajout la collection, lorsque nous supprimons un lment, etc. Changeons donc le
type de notre proprit de liaison :
1 private ObservableCollection <ElementAFaire > listeDesTaches;
2 public ObservableCollection <ElementAFaire > ListeDesTaches
3 {
4 get { return listeDesTaches; }
5 set { NotifyPropertyChanged(ref listeDesTaches , value); }
6 }
Remarque : vous devez importer lespace de nom
System.Collections.ObjectModel.
Dans le constructeur, il faudra changer linitialisation de la liste :
1 ListeDesTaches = new ObservableCollection <ElementAFaire >(
chosesAFaire.OrderBy(e => e.Priorite));
Et dsormais, lors du clic, il sura de faire :
1 ListeDesTaches.Add(new ElementAFaire { Priorite = 1,
Description = "Faire marcher ce binding !" });
Ce qui est quand mme beaucoup plus simple. Plutt pratique cette
ObservableCollection. Elle nous simplie normment la tche lorsquil sagit
de faire des oprations sur une collection et quun contrle doit tre noti de ce
changement. Cest le complment idal pour toute ListBox qui se respecte. De plus,
203
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
avec lObservableCollection, notre ListBox ne sest pas compltement rafrachie,
elle a simplement ajout un lment. Avec la mthode prcdente, cest toute la liste
qui se met jour dun coup, ce qui pnalise un peu les performances.
Alors pourquoi je ne lai pas utilis avant ? Parce que je considre quil est important de
comprendre ce que lon a fait. Le binding fonctionne avec tout ce qui est numrable,
comme la List<> ou nimporte quoi implmentant IEnumerable<>. Cest ce que jai
illustr au dbut du chapitre. Lorsquon a besoin uniquement de remplir un contrle et
quil ne va pas se mettre jour, ou pas directement, utiliser une liste ou un IEnumerable
est le plus simple et le plus performant. Cela permet galement de ne pas avoir besoin
dinstancier une ObservableCollection. Si bien sr, il y a beaucoup dopration sur
la liste, suppression, mise jour, ajout, . . . il sera beaucoup plus pertinent dutiliser
une ObservableCollection. Mais il faut faire attention lutiliser correctement. . .
Imaginons par exemple que je veuille mettre jour toutes mes priorits. . . Comme je
suis en avance, je rajoute un bouton me permettant daugmenter la priorit de 1 pour
chaque lment :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*"/>
4 <RowDefinition Height="150"/>
5 </Grid.RowDefinitions >
6 <ListBox ItemsSource="{Binding ListeDesTaches}" >
7 <ListBox.ItemTemplate >
8 <DataTemplate >
9 <StackPanel Orientation="Horizontal">
10 <TextBlock Text="{Binding Priorite}" Margin
="20 0 0 0" />
11 <TextBlock Text="{Binding Description}"
Margin="20 0 0 0" />
12 </StackPanel >
13 </DataTemplate >
14 </ListBox.ItemTemplate >
15 </ListBox >
16 <StackPanel Grid.Row="1">
17 <Button Content="Ajouter un lment" Tap="Button_Tap"
/>
18 <Button Content="Augmenter les priorits" Tap="
Button_Tap_1" />
19 </StackPanel >
20 </Grid >
Et dans la mthode du clic, je peux faire :
1 private void Button_Tap_1(object sender , RoutedEventArgs e)
2 {
3 foreach (ElementAFaire element in ListeDesTaches)
4 {
5 element.Priorite ++;
6 }
7 }
204
UTILISER LOBSERVABLECOLLECTION
Sauf quaprs un clic sur notre bouton, on se rend compte que lObservableCollection
est mise jour mais pas la ListBox. . . Aarrrgghhhh ! Alors que notre
ObservableCollection tait cense rsoudre tous nos problmes de notication . . .
Cest l o il est important davoir compris ce quon faisait rellement . . . Ici, ce nest
pas la collection que lon a modie (pas dajout, pas de suppression, . . .), mais bien
lobjet contenu dans la collection. Il doit donc implmenter INotifyPropertyChanged,
ce qui donne :
1 public class ElementAFaire : INotifyPropertyChanged
2 {
3 public event PropertyChangedEventHandler PropertyChanged;
4
5 public void NotifyPropertyChanged(string nomPropriete)
6 {
7 if (PropertyChanged != null)
8 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
9 }
10
11 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
12 {
13 if (object.Equals(variable , valeur)) return false;
14
15 variable = valeur;
16 NotifyPropertyChanged(nomPropriete);
17 return true;
18 }
19
20 private int priorite;
21 public int Priorite
22 {
23 get { return priorite; }
24 set { NotifyPropertyChanged(ref priorite , value); }
25 }
26 public string Description { get; set; }
27 }
Il faut galement notier du changement lors de laccs la proprit Priorite. En
toute logique, il faudrait galement le faire sur la proprit Description, mais vu que
nous ne nous en servons pas ici, je vous fais grce de ce changement (voir la gure
16.15).
LObservableCollection est donc une classe puissante mais qui peut nous jouer
quelques tours si son fonctionnement nest pas bien matris.
205
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
Figure 16.15 La collection est mise jour grce limplmentation de linterface
INotifyPropertyChanged
Les converters
Parfois, lorsque nous faisons des liaisons de donnes, la source de donnes ne correspond
pas exactement ce que nous souhaitons acher ; la preuve juste au-dessus. Nous
voulions acher une image dans une ListBox mais nous navions notre disposition
quun chire reprsentant une priorit. Pour y remdier, nous avions construit un objet
spcial avec directement les bonnes valeurs via la classe ElementAFaireBinding :
1 List <ElementAFaire > chosesAFaire = new List <ElementAFaire >
2 {
3 new ElementAFaire { Priorite = 1, Description = "Arroser
les plantes"},
4 new ElementAFaire { Priorite = 2, Description = "Tondre le
gazon"},
5 new ElementAFaire { Priorite = 1, Description = "Planter
les tomates"},
6 new ElementAFaire { Priorite = 3, Description = "Laver la
voiture"},
7 };
8
9 listeDesTaches.ItemsSource = chosesAFaire.OrderBy(e => e.
Priorite).Select(e => new ElementAFaireBinding { Description
= e.Description , Image = ObtientImage(e.Priorite) });
206
LES CONVERTERS
Cest une bonne faon de faire mais il existe une autre solution qui consiste appliquer
un convertisseur lors de la liaison de donnes. Appels converters en anglais, ils font
en sorte de transformer une donne en une autre, adapte ce que lon souhaite lier.
Un exemple sera plus clair quun long discours. Prenons par exemple le cas o lon
souhaite masquer une zone de lcran en fonction dune valeur. Lachage / masquage
dun contrle, cest le rle de la proprit Visibility qui a la valeur Visible par
dfaut ; pour tre invisible, il faut que la valeur soit Collapsed :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <StackPanel >
3 <TextBlock Text="Je suis visible" Visibility="Collapsed
" />
4 <Button Content="Masquer/Afficher" Tap="Button_Tap" />
5 </StackPanel >
6 </Grid >
Ces deux valeurs font partie de lnumration Visibility - http://msdn.microsoft.
com/fr-fr/library/system.windows.uielement.visibility(v=vs.95).aspx. Sauf
que pour nous, il est beaucoup plus logique de travailler avec un boolen : sil est vrai,
le contrle est visible, sinon il est invisible.
Cest l que va servir le converter, il va permettre de transformer true en Visible
et false en Collapsed. Pour crer un tel converter, nous allons ajouter une nou-
velle classe : VisibilityConverter. Cette classe doit implmenter linterface IValue-
Converter - http://msdn.microsoft.com/fr-fr/library/system.windows.data.
ivalueconverter(v=vs.95).aspx qui force implmenter une mthode de conver-
sion de bool vers Visibility et inversement une mthode qui transforme Visibility
en bool. Voici donc une telle classe :
1 public class VisibilityConverter : IValueConverter
2 {
3 public object Convert(object value , Type targetType , object
parameter , CultureInfo culture)
4 {
5 return (bool)value ? Visibility.Visible : Visibility.
Collapsed;
6 }
7
8 public object ConvertBack(object value , Type targetType ,
object parameter , CultureInfo culture)
9 {
10 Visibility visibility = (Visibility)value;
11 return (visibility == Visibility.Visible);
12 }
13 }
IValueConverter fait partie de lespace de nom System.Windows.Data,
CultureInfo fait partie de lespace de nom System.Globalization et
Visibility de System.Windows.
207
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
Le code nest pas trs compliqu. La seule chose peut-tre nouvelle pour certains est
lutilisation de loprateur ternaire ? . Lcriture suivante :
1 Visibility v = visibility ? Visibility.Visible : Visibility.
Collapsed;
permet de remplacer :
1 Visibility v;
2 if (visibility)
3 v = Visibility.Visible;
4 else
5 v = Visibility.Collapsed;
Il value le boolen (ou la condition) gauche du point dinterrogation. Si le rsultat
est vrai, alors il prend le premier oprande, sinon il prend le second, situ aprs les
deux points.
Bref, une fois ceci fait, il va falloir dclarer le converter dans notre page XAML. Cela
se fait dans les ressources et ici, je le mets dans les ressources de la page :
1 <phone:PhoneApplicationPage.Resources >
2 <converter:VisibilityConverter x:Key="VisibilityConverter"
/>
3 </phone:PhoneApplicationPage.Resources >
Ce code doit tre prsent au mme niveau que le conteneur de base de la page, cest-
-dire lintrieur de la balise <phone:PhoneApplicationPage>.
Attention, la classe converter nest pas connue de la page, il faut ajouter un espace de
nom dans les proprits de la page : xmlns:converter="clr-namespace:DemoPartie2"
Il ne reste plus qu crer une proprit pour le binding dans notre classe :
1 private bool textBlockVisible;
2 public bool TextBlockVisible
3 {
4 get { return textBlockVisible; }
5 set { NotifyPropertyChanged(ref textBlockVisible , value); }
6 }
Et modier sa valeur dans lvnement de clic sur le bouton :
1 private void Button_Tap(object sender , RoutedEventArgs e)
2 {
3 TextBlockVisible = !TextBlockVisible;
4 }
Maintenant, nous devons indiquer le binding dans le XAML et que nous souhaitons
utiliser un converter, cela se fait avec :
1 <TextBlock Text="Je suis visible" Visibility="{Binding
TextBlockVisible ,Converter ={ StaticResource
VisibilityConverter }}" />
208
LES CONVERTERS
Nous lui indiquons ici que le converter est accessible en ressources par son nom :
VisibilityConverter. Noublions pas de donner la valeur initiale du boolen, par
exemple dans le constructeur, ainsi que dalimenter le DataContext :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 TextBlockVisible = false;
5 DataContext = this;
6 }
Et voil, le fait de changer la valeur du boolen inue bien sur la visibilit du contrle,
comme vous pouvez le constater la gure 16.16.
Figure 16.16 Le converter permet de modier la visibilit du contrle grce une
liaison de donnes
Il est assez courant dcrire des converters pour se simplier la tche, par contre cela
rajoute un temps de traitement qui en fonction des cas peut tre important. Si cest
possible, prfrez les cas o la donne est correctement prpare ds le dbut, pensez que
les smartphones nont pas autant de puissance que votre machine de dveloppement. . .
En rsum
La liaison de donnes, binding en anglais, est un lment fondamental des ap-
plications XAML et permet dassocier une source de donnes un contrle.
209
CHAPITRE 16. LA MANIPULATION DES DONNES (DATABINDING &
CONVERTERS)
On utilise lextention de balisage {Binding} pour dclarer une liaison de donnes
depuis une proprit dun contrle dans le XAML.
Il est possible damliorer le mode design de ses pages grce au binding.
LObservableCollection est une liste volue qui gre automatiquement les noti-
cations en cas de changement dans la liste.
Les converters sont un mcanisme qui permet de transformer une donne en une
autre au moment du binding.
210
Chapitre 17
MVVM
Dicult :
Passons maintenant MVVM. . . Si vous tes dbutants en XAML, je ne vous cache pas
que ce chapitre risque dtre dicile apprhender. Il sagit de concepts avancs quil nest
pas ncessaire de maitriser immdiatement. Au contraire, dune manire gnrale, il faut
dj pas mal de pratique avant de pouvoir utiliser les concepts prsents dans ce chapitre.
Mais nhsitez pas le lire quand mme et y revenir plus tard, cela vous sera toujours
utile.
Trs la mode, MVVM est un patron de conception (design pattern en anglais) qui sest
construit au fur et mesure que les dveloppeurs craient des applications utilisant le
XAML. MVVM signie Model-View-ViewModel, nous allons dtailler son principe et son
fonctionnement dans ce chapitre.
211
CHAPITRE 17. MVVM
Principe du patron de conception
La premire chose savoir est quest-ce quun patron de conception ? Trs connu sous
son appellation anglaise, design pattern , un patron de conception constitue une
solution prouve et reconnue comme une bonne pratique un problme rcurrent
dans la conception dapplications informatiques. En gnral, il dcrit une modlisation
de classes utilises pour rsoudre un problme prcis. Il existe beaucoup de patrons de
conceptions, comme le populaire MVC (Modle-Vue-Contrleur), trs utilis dans la
ralisation de site webs.
Ici, le patron de conception MVVM est particulirement adapt la ralisation dap-
plications utilisant le XAML, comme les applications pour Windows Phone, mais ga-
lement les applications Silverlight, Windows 8 ou WPF. Il permet darchitecturer e-
cacement une application an den faciliter la maintenabilit et la testabilit. Certains
auront tendance considrer MVVM comme un ensemble de bonnes pratiques plu-
tt quun vrai patron de conception. Ce qui est important, cest quen le comprenant
vous allez amliorer votre productivit dans la ralisation dapplications consquentes.
Voyons prsent de quoi il sagit.
MVVM signie Model-View-ViewModel.
Model, en franais le modle , correspond aux donnes. Il sagit en gnral
de plusieurs classes qui permettent daccder aux donnes, comme une classe
Client, une classe Commande, etc. Peu importe la faon dont on remplit ces
donnes (base de donnes, service web,. . .), cest ce modle qui est manipul
pour accder aux donnes.
View, en franais la vue , correspond tout ce qui sera ach, comme la
page, les boutons, etc. En pratique, il sagit du chier .xaml.
View Model, que lon peut traduire en modle de vue , cest la colle entre le
modle et la vue. Il sagit dune classe qui fournit une abstraction de la vue. Ce
modle de vue, que jappellerai dsormais view-model, sappuie sur la puissance
du binding pour mettre disposition de la vue les donnes du modle. Il soccupe
galement de grer les commandes que nous verrons un peu plus loin.
Voici la gure 17.1 un schma reprsentant ce patron de conception.
Le but de MVVM est de faire en sorte que la vue neectue aucun traitement, elle ne
doit faire quacher les donnes prsentes par le view-model. Cest le view-model qui
a en charge de faire les traitements et daccder au modle.
Et si on se tentait une petite mtaphore pour essayer de comprendre un peu mieux ?
Essayons de reprsenter MVVM travers un jeu, disons une machine sous dun
casino.
Mon modle correspondra aux direntes valeurs internes des images de la ma-
chine sous, dont le fameux 7 qui fait gagner le gros lot.
Ma vue correspondra la carcasse de la boite sous et surtout aux images qui
sachent. Il sagira de tout ce que lon voit.
Mon view-model correspondra aux engrenages qui relient les images la machine
sous et qui transforment une valeur interne en image achable sur la machine
212
PRINCIPE DU PATRON DE CONCEPTION
Figure 17.1 Le patron de conception MVVM
213
CHAPITRE 17. MVVM
sous.
Sans ces engrenages, mes images ne peuvent pas saccrocher au cadre de la machine
sous et tout se casse la gure, on ne voit rien sur la vue. Lorsque ces engrenages
sont prsents, on peut voir les donnes lies la vue (grce au binding). Et je peux
agir sur mon modle par lintermdiaire de commandes, en loccurrence le levier de
la machine sous. Je tire sur le levier, une commande du view-model est active, les
images tournent, le modle se met jour (les valeurs internes ont changes) et la vue est
mise jour automatiquement. Je peux voir que les trois sept sont aligns. JACKPOT.
Plus comprhensible ? Nhsitez pas me proposer dautres mtaphores en commen-
taires pour expliquer MVVM.
Premire mise en place de MVVM
Nous avons commenc pratiquer un peu MVVM au chapitre prcdent, en fournissant
un contexte dans une classe spare. Ce contexte est le view-model, il prpare les
donnes an quelles soient achables par la vue. Si on veut tre un peu plus prcis
et utiliser un langage plus proche des patrons de conception, on pourrait dire que le
view-model adapte le modle pour la vue. Commenons par crer un nouveau projet
pour mettre en place une version simplie de MVVM. Comme lide est de sparer les
responsabilits, nous allons en proter pour crer des rpertoires pour notre modle,
nos vues et nos view-models. Crons donc les rpertoires et les chiers suivants :
Model
Client.cs
ServiceClient.cs
View
VoirClientView.xaml
ViewModel
VoirClientViewModel.cs
Et protons-en pour supprimer le chier MainPage.xaml, de manire avoir la mme
architecture que sur la gure 17.2.
Par convention, vous aurez compris que le modle se place dans le rpertoire Model,
que les vues se placent dans le rpertoire View et que les view-models se placent dans
le rpertoire ViewModel. De mme, on suxera les vues par View et les view-models
par ViewModel . En ltat, notre application ne pourra pas dmarrer ainsi, car notre
application va essayer de dmarrer en naviguant sur le chier MainPage.xaml, que nous
avons supprim. Nous devons donc lui indiquer un nouveau point dentre. Cela se fait
depuis le chier WMAppManifest.xml qui est sous le rpertoire Properties. Ouvrez-
le et modiez la Page de navigation, comme nous lavons dj fait, pour y mettre :
View/VoirClientView.xaml.
Cela nous permet de dire que lapplication doit dmarrer en achant la page
VoirClientView.xaml. Commenons par crer un modle ultra simple, qui consiste
en une classe client qui contient un prnom, un ge et un boolen indiquant sil est un
bon client :
214
PREMIRE MISE EN PLACE DE MVVM
Figure 17.2 Architecture de la solution MVVM
1 public class Client
2 {
3 public string Prenom { get; set; }
4 public int Age { get; set; }
5 public bool EstBonClient { get; set; }
6 }
Ainsi quun service qui va nous simuler le chargement dun client :
1 public class ServiceClient
2 {
3 public Client Charger ()
4 {
5 return new Client { Prenom = "Nico", Age = 30,
EstBonClient = true };
6 }
7 }
Maintenant, ralisons la vue. Nous allons simplement acher le prnom et lge du
client. Ceux-ci seront sur un fond vert si le client est un bon client et en rouge si cest
un mauvais client. Quelque chose comme a :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="auto"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
8 <TextBlock x:Name="PageTitle" Text="Fiche client"
Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
9 </StackPanel >
10
215
CHAPITRE 17. MVVM
11 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
Background="{Binding BonClient}">
12 <Grid.RowDefinitions >
13 <RowDefinition Height="auto" />
14 <RowDefinition Height="auto" />
15 </Grid.RowDefinitions >
16 <Grid.ColumnDefinitions >
17 <ColumnDefinition Width="*" />
18 <ColumnDefinition Width="*" />
19 </Grid.ColumnDefinitions >
20 <TextBlock Text="Prnom : " />
21 <TextBlock Grid.Column="1" Text="{Binding Prenom}" />
22 <TextBlock Grid.Row="1" Text="Age : " />
23 <TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding
Age}" />
24 </Grid >
25 </Grid >
On utilise les expressions de balisage pour indiquer les valeurs grce au binding.
Sauf quil est dicile de se rendre compte ainsi si la vue est bien construite, car
il nous manque les valeurs de design. Qu cela ne tienne, nous savons dsor-
mais comment crer un contexte de design. Crons un nouveau rpertoire sous le
rpertoire ViewModel que nous appelons Design et une nouvelle classe sappelant
DesignVoirClientViewModel.cs qui contiendra les valeurs de design suivantes :
1 public class DesignVoirClientViewModel
2 {
3 public string Prenom
4 {
5 get { return "Nico"; }
6 }
7
8 public int Age
9 {
10 get { return 30; }
11 }
12
13 public SolidColorBrush BonClient
14 {
15 get { return new SolidColorBrush(Color.FromArgb(100 , 0,
255 , 0)); }
16 }
17 }
Pour rappel, SolidColorBrush se trouve dans lespace de nom System.Windows.Media.
Il faut ensuite lier le contexte de design au view-model de design :
1 <d:DesignProperties.DataContext >
2 <design:DesignVoirClientViewModel />
3 </d:DesignProperties.DataContext >
216
PREMIRE MISE EN PLACE DE MVVM
sans oublier dimporter lespace de nom correspondant :
1 xmlns:design="clr -namespace:DemoMvvm.ViewModel.Design"
Ainsi, nous pourrons avoir en mode design le rsultat ach la gure 17.3.
Figure 17.3 Achage des donnes en mode design grce MVVM
Ce qui est le rsultat attendu. Chouette ! Passons enn au view-model. Nous avons vu
quil devait implmenter linterface INotifyPropertyChanged :
1 public class VoirClientViewModel : INotifyPropertyChanged
2 {
3 private string prenom;
4 public string Prenom
5 {
6 get { return prenom; }
7 set { NotifyPropertyChanged(ref prenom , value); }
8 }
9
10 private int age;
11 public int Age
12 {
13 get { return age; }
14 set { NotifyPropertyChanged(ref age , value); }
15 }
16
17 private SolidColorBrush bonClient;
18 public SolidColorBrush BonClient
217
CHAPITRE 17. MVVM
19 {
20 get { return bonClient; }
21 set { NotifyPropertyChanged(ref bonClient , value); }
22 }
23
24 public event PropertyChangedEventHandler PropertyChanged;
25
26 public void NotifyPropertyChanged(string nomPropriete)
27 {
28 if (PropertyChanged != null)
29 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
30 }
31
32 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
33 {
34 if (object.Equals(variable , valeur)) return false;
35
36 variable = valeur;
37 NotifyPropertyChanged(nomPropriete);
38 return true;
39 }
40 }
Rien de sorcier, nous dnissons galement les proprits Prenom, Age et BonClient.
Reste charger notre modle depuis notre view-model et aecter les proprits du
view-model partir des valeurs du modle :
1 public void ChargeClient ()
2 {
3 ServiceClient service = new ServiceClient ();
4 Client client = service.Charger ();
5
6 Prenom = client.Prenom;
7 Age = client.Age;
8 if (client.EstBonClient)
9 BonClient = new SolidColorBrush(Color.FromArgb(100 , 0,
255 , 0));
10 else
11 BonClient = new SolidColorBrush(Color.FromArgb(100 , 255
, 0, 0));
12 }
Il nous manque une dernire chose, hautement indispensable, qui est de lier la vue au
view-model. Pour linstant, nous avons vu que nous pouvions le faire depuis le code-
behind de la vue, avec :
1 public partial class VoirClientView : PhoneApplicationPage
2 {
3 public VoirClientView ()
218
PREMIRE MISE EN PLACE DE MVVM
4 {
5 InitializeComponent ();
6 DataContext = new VoirClientViewModel ();
7 }
8 }
Il y a une autre solution qui vite de passer par le code, en utilisant le XAML :
1 <phone:PhoneApplicationPage.DataContext >
2 <viewmodel:VoirClientViewModel />
3 </phone:PhoneApplicationPage.DataContext >
Ce qui revient au mme, vu quon positionne la proprit DataContext de la page
une instance du view-model. Cest cette solution que nous allons privilgier ici. Vous
naurez bien sr pas oubli dinclure lespace de nom qui va bien :
1 xmlns:viewmodel="clr -namespace:DemoMvvm.ViewModel"
Revenons prsent un peu sur ce que nous avons fait. Nous avons cr une vue, la
page XAML, lie lexcution au view-model VoirClientViewModel et lie en design
au pseudo view-model DesignVoirClientViewModel. Le pseudo view-model de design
expose des donnes en dur, pour nous permettre davoir des donnes dans le designer
alors que le view-model utilise et transforme le model pour exposer les mmes donnes.
Une bonne pratique ici serait de dnir une interface avec les donnes exposer et
que nos deux view-models limplmentent. Crons donc un rpertoire Interface dans le
rpertoire ViewModel et crons linterface IVoirClientViewModel :
1 public interface IVoirClientViewModel
2 {
3 string Prenom { get; set; }
4 int Age { get; set; }
5 SolidColorBrush BonClient { get; set; }
6 }
Nos deux view-models doivent implmenter cette interface :
1 public class VoirClientViewModel : INotifyPropertyChanged ,
IVoirClientViewModel
2 {
3 ...
4 }
Et :
1 public class DesignVoirClientViewModel : IVoirClientViewModel
2 {
3 public string Prenom
4 {
5 get { return "Nico"; }
6 set { }
7 }
8
219
CHAPITRE 17. MVVM
9 public int Age
10 {
11 get { return 30; }
12 set { }
13 }
14
15 public SolidColorBrush BonClient
16 {
17 get { return new SolidColorBrush(Color.FromArgb(100 , 0,
255 , 0)); }
18 set { }
19 }
20 }
Vous aurez remarqu que nous avons rajout le mutateur set dans le view-model de
design, et quelle na besoin de rien faire.
Nous pouvons encore faire une petite amlioration. Ici, elle est mineure car nous navons
quun seul view-model, mais elle sera intressante ds que nous en aurons plusieurs.
En eet, chaque view-model doit implmenter linterface INotifyPropertyChanged et
avoir le code suivant :
1 public event PropertyChangedEventHandler PropertyChanged;
2
3 public void NotifyPropertyChanged(string nomPropriete)
4 {
5 if (PropertyChanged != null)
6 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
7 }
8
9 private bool NotifyPropertyChanged <T>(ref T variable , T valeur ,
[CallerMemberName] string nomPropriete = null)
10 {
11 if (object.Equals(variable , valeur)) return false;
12
13 variable = valeur;
14 NotifyPropertyChanged(nomPropriete);
15 return true;
16 }
Nous pouvons factoriser ce code dans une classe de base dont vont driver tous les
view-models. Crons pour cela un rpertoire FrameworkMvvm et dedans, mettons-y la
classe ViewModelBase :
1 public class ViewModelBase : INotifyPropertyChanged
2 {
3 public event PropertyChangedEventHandler PropertyChanged;
4
5 public void NotifyPropertyChanged(string nomPropriete)
6 {
220
LES COMMANDES
7 if (PropertyChanged != null)
8 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
9 }
10
11 public bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
12 {
13 if (object.Equals(variable , valeur)) return false;
14
15 variable = valeur;
16 NotifyPropertyChanged(nomPropriete);
17 return true;
18 }
19 }
Noubliez pas de passer la mthode NotifyPropertyChanged en public. Il ne reste plus
qu supprimer ce code du view-model et de le faire hriter de cette classe de base :
1 public class VoirClientViewModel : ViewModelBase ,
IVoirClientViewModel
2 {
3 ...
4 }
Les commandes
Bon, cest trs bien tout a, mais nous navons fait quune partie du chemin. . . MVVM
ce nest pas que du binding avec une sparation entre la vue et les donnes. Il faut tre
capable de faire des actions. Imaginons que nous souhaitions charger les donnes du
client suite un appui sur un bouton. Avant MVVM, nous aurions utilis un vnement
sur le clic du bouton, puis nous aurions charg les donnes dans le code-behind et nous
les aurions aches sur notre page. Avec notre dcoupage, le view-model nest pas
au courant dune action sur linterface, car cest un chier part. Il nest donc pas
directement possible de raliser une action dans le view-model lors dun clic sur le
bouton. On peut rsoudre ce problme dune premire faon trs simple mais pas tout
fait parfaite. Crons tout dabord un bouton dans notre XAML :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0"
Background="{Binding BonClient}">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="auto" />
4 <RowDefinition Height="auto" />
5 <RowDefinition Height="auto" />
6 </Grid.RowDefinitions >
7 <Grid.ColumnDefinitions >
8 <ColumnDefinition Width="*" />
9 <ColumnDefinition Width="*" />
221
CHAPITRE 17. MVVM
10 </Grid.ColumnDefinitions >
11 <TextBlock Text="Prnom : " />
12 <TextBlock Grid.Column="1" Text="{Binding Prenom}" />
13 <TextBlock Grid.Row="1" Text="Age : " />
14 <TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding Age}
" />
15 <Button Grid.Row="2" Grid.ColumnSpan="2" Content="Charger
client" Tap="Button_Tap" />
16 </Grid >
Voyons prsent comment rsoudre simplement ce problme. Il sut dutiliser lv-
nement Tap et de faire quelque chose comme ceci dans le code-behind de la page, dans
la mthode associe lvnement de clic :
1 public partial class VoirClientView : PhoneApplicationPage
2 {
3 public VoirClientView ()
4 {
5 InitializeComponent ();
6 }
7
8 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
9 {
10 (( IVoirClientViewModel)DataContext).ChargeClient ();
11 }
12 }
On utilise la proprit DataContext pour rcuprer linstance du view-model. En eet,
noubliez pas que nous avons li la vue au view-model via la proprit DataContext.
Cela implique de rajouter une mthode ChargeClient() dans linterface et de la dnir
dans notre view-model ainsi que dans celui de design :
1 public interface IVoirClientViewModel
2 {
3 string Prenom { get; set; }
4 int Age { get; set; }
5 SolidColorBrush BonClient { get; set; }
6 void ChargeClient ();
7 }
8
9 public class DesignVoirClientViewModel : IVoirClientViewModel
10 {
11 public string Prenom
12 {
13 get { return "Nico"; }
14 set { }
15 }
16
17 public int Age
18 {
222
LES COMMANDES
19 get { return 30; }
20 set { }
21 }
22
23 public SolidColorBrush BonClient
24 {
25 get { return new SolidColorBrush(Color.FromArgb(100 , 0,
255 , 0)); }
26 set { }
27 }
28
29 public void ChargeClient ()
30 {
31 }
32 }
33
34 public class VoirClientViewModel : ViewModelBase ,
IVoirClientViewModel
35 {
36 [... code supprim pour plus de clart...]
37
38 public VoirClientViewModel ()
39 {
40 }
41
42 public void ChargeClient ()
43 {
44 ServiceClient service = new ServiceClient ();
45 Client client = service.Charger ();
46
47 Prenom = client.Prenom;
48 Age = client.Age;
49 if (client.EstBonClient)
50 BonClient = new SolidColorBrush(Color.FromArgb(100 ,
0, 255 , 0));
51 else
52 BonClient = new SolidColorBrush(Color.FromArgb(100 ,
255 , 0, 0));
53 }
54 }
Vous pouvez tester cette solution, cela fonctionne. Cependant, elle est imparfaite car
cela cre un couplage entre la vue et le view-model, cest--dire que la vue connait
linstance du view-model car cest eectivement elle qui linstancie avec la dclaration
que nous avons vue dans le XAML. Mais bien quimparfaite, ncartez pas non plus
compltement cette solution de votre esprit, elle reste bien pratique et ne rajoute pas
tant de code que a dans la vue (de plus, ce code ne fait pas de traitement, il fonctionne
juste comme un relai du traitement).
223
CHAPITRE 17. MVVM
Pour rsoudre plus proprement ce problme, il y a une autre solution : les
commandes. Les commandes correspondent des actions faites sur la vue.
Le XAML dispose dun mcanisme lger de gestion de commandes via lin-
terface ICommand - http://msdn.microsoft.com/fr-fr/library/system.
windows.input.icommand(v=vs.95).aspx. Par exemple, le contrle bou-
ton possde (par hritage) une proprit Command du type ICommand -
http://msdn.microsoft.com/fr-fr/library/system.windows.controls.
primitives.buttonbase.command(v=vs.95).aspx permettant dinvoquer une
commande lorsque le bouton est appuy.
Ainsi, il sera possible de remplacer :
1 <Button Grid.Row="2" Grid.ColumnSpan="2" Content="Charger
client" Tap="Button_Tap" />
par :
1 <Button Grid.Row="2" Grid.ColumnSpan="2" Content="Charger
client" Command="{Binding ChargerClientCommand}" />
Ici, nous avons enlev lvnement Tap et la mthode associe (vous pouvez donc sup-
primer cette mthode dans le code behind) pour la remplacer par un binding dune
commande. Cette commande devra tre dnie dans le view-model :
1 public ICommand ChargerClientCommand { get; private set; }
Noubliez pas dinclure :
1 using System.Windows.Input;
Elle sera du type ICommand et videmment en lecture seule an que seul le view-
model puisse instancier la commande. Cette commande doit ensuite tre relie une
mthode et pour faire cela, nous allons utiliser un dlgu et plus particulirement
un dlgu de type Action. Crons donc une classe qui implmente ICommand et qui
associe la commande une action. Nous pouvons placer cette classe dans le rper-
toire FrameworkMvvm et la nommer RelayCommand (ce nom nest pas choisi au hasard,
vous verrez plus loin pourquoi). Linterface ICommand impose de dnir la mthode
CanExecute qui permet dindiquer si la commande peut tre excute ou non. Nous
allons renvoyer vrai dans tous les cas pour cet exemple. Elle oblige galement d-
nir un vnement CanExecuteChanged que nous nallons pas utiliser et une mthode
Execute qui appellera la mthode associe la commande. La classe RelayCommand
pourra donc tre :
1 public class RelayCommand : ICommand
2 {
3 private readonly Action actionAExecuter;
4
5 public RelayCommand(Action action)
6 {
7 actionAExecuter = action;
8 }
224
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
9
10 public bool CanExecute(object parameter)
11 {
12 return true;
13 }
14
15 public event EventHandler CanExecuteChanged;
16
17 public void Execute(object parameter)
18 {
19 actionAExecuter ();
20 }
21 }
Ce qui fait que nous allons pouvoir instancier un objet du type RelayCommand que
nous stockerons dans la proprit ChargerClientCommand dans notre view-model, par
exemple depuis le constructeur :
1 public VoirClientViewModel ()
2 {
3 ChargerClientCommand = new RelayCommand(ChargeClient);
4 }
Et voil, la mthode ChargeClilent() reste la mme que prcdemment. Vous pouvez
donc la supprimer de linterface, du view-model de design et mme si vous le souhaitez,
vous pouvez la passer en prive dans le view-model. En ce qui concerne la proprit
ChargerClientCommand, vous pouvez la dclarer dans linterface mais ce nest pas
forcment utile car le view-model de design na pas besoin de connaitre la commande
et ne saura dailleurs pas quoi mettre comme mthode dedans.
Super ces commandes sauf que la proprit Command que nous avons vu est prsente sur
le contrle ButtonBase, dont hrite le contrle Button ainsi que le contrle de case
cocher, CheckBox. Elle nest pas prsente par contre sur tous les autres contrles. Nous
allons tre bloqus pour associer une commande un autre vnement, par exemple la
slection dun lment dune ListBox. Nous allons voir plus loin comment rsoudre ce
problme.
Les frameworks la rescousse : MVVM-Light
Entre la classe ViewModelBase et la classe RelayCommand, nous sommes en train
dcrire un vrai mini framework pour nous aider implmenter MVVM. Alors, je
vous le dis tout de suite, nous allons nous arrter l dans limplmentation de ce
framework. . . car dautres lont dj fait ; et en mieux ! Il existe beaucoup de frame-
work pour utiliser MVVM et certains sont utilisables avec Windows Phone, comme
par exemple le populaire MVVM Light Toolkit, que vous pouvez trouver ici - http:
//mvvmlight.codeplex.com/.
Malgr sa dnomination, il nest en fait pas si light que a car il est utilisable avec
WPF, Silverlight, Windows Phone et Windows 8. Je ne vais pas faire un cours entier
225
CHAPITRE 17. MVVM
sur ce toolkit, car cela demanderait beaucoup trop de pages. Nous allons cependant
regarder quelques points intressants qui pourraient vous servir dans une application
Windows Phone. Aprs, vous de voir si vous avez besoin dembarquer la totalit du
framework ou si vous pouvez simplement vous inspirer de quelques ides. . .
Toujours est-il quil y a beaucoup de bonnes choses dans ce toolkit. Vous vous rappelez
de nos deux classes ViewModelBase et RelayCommand ? Et bien, MVVM Light possde
galement ces deux classes. . . et en plus fournies ! Par exemple la classe RelayCommand.
Nous en avons crit une version ultra simplie. Celle de ce toolkit est complte et per-
met mme dy associer un paramtre. Cela peut-tre utile lorsque la mme commande
est associe plusieurs boutons et que chaque bouton possde un paramtre dirent.
De mme, ce toolkit propose une solution au problme que jvoquais plus haut,
savoir de pouvoir relier nimporte quel vnement une commande.
Il propose galement une solution pour rsoudre le problme de couplage entre la vue et
le view-model que nous avons rencontr prcdemment. Il utilise en eet un patron de
conception prvu pour ce genre de cas, le service locator, qui est un patron de conception
dinversion de dpendance. Je ne parlerai pas en dtail de ce patron de conception ici,
vous pouvez trouver plus dinformations en anglais sur ce site : http://martinfowler.
com/articles/injection.html#UsingAServiceLocator. Sachez simplement que le
principe gnral est davoir un gros objet contenant une liste de services et qui sait
en retrouver un partir dune cl. Cette cl peut tre de plusieurs sortes, comme une
chane de caractre, un type (en gnral une interface), etc. Pour viter le couplage
entre la vue et le view-model, ce patron de conception permettra de faire en sorte
que la vue connaisse simplement une cl an dobtenir son view-model, sans forcment
connatre linstance et le type du view-model.
Remarquez que pour moi, ce couplage fort entre la vue et le view-model nest pas un
vrai problme, au risque de faire hurler les puristes. Le but premier thorique est de
pouvoir ventuellement changer facilement de view-model pour une mme vue, sans
avoir tout modier. En pratique, il savre quil existe toujours un et un seul view-
model associ une vue, et que cest toujours le mme. Cest pourquoi je trouve que
la liaison du view-model depuis le XAML propose dans le chapitre prcdent est bien
souvent susante.
Installation du toolkit
Voyons prsent comment crer une application MVVM Light. Nous allons instal-
ler la dernire version stable du framework lheure o jcris ces lignes, savoir la
version 4.1.25. Le plus simple pour tlcharger les bibliothques est de passer par Nu-
Get, qui est un gestionnaire de package .NET open source permettant de tlcharger
des bibliothques externes trs facilement. Pour cela, allez dans le menu outils, puis
gestionnaire de package de bibliothques, puis Grer les packages NuGet pour la
solution, comme indiqu la gure 17.4.
Vous arrivez dans NuGet o vous allez pouvoir cliquer sur En ligne gauche et com-
mencer rechercher le MVVM Light Toolkit (voir la gure 17.5).
226
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
Figure 17.4 Dmarrer NuGet
Figure 17.5 Installation du Mvvm Light Toolkit via NuGet
227
CHAPITRE 17. MVVM
Vous devez bien sr tre connects internet pour utiliser NuGet.
Vous pouvez choisir dinstaller la version complte ou uniquement la bibliothque. La
version complte contient les binaires du toolkit, les templates et les snippets.
Les binaires sont indispensables pour utiliser le toolkit. Il sagit des assemblys conte-
nant le code du toolkit. Les templates sont des modles de projet permettant de crer
facilement une application utilisant MVVM Light. Le projet ainsi cr contient dj les
bonnes rfrences, un premier exemple de vue, de locator, etc. Les snippets sont des
extraits de code qui sont utiliss pour pouvoir crer plus rapidement des applications
MVVM.
Comme je ne souhaite pas vous prsenter tout MVVM Light et que je veux me concen-
trer sur la comprhension des lments du patron de conception, je vais simplement
installer les binaires en choisissant MVVM Light Libraries only. Cliquez sur Installer.
Aprs tlchargement (rapide) il me propose de linstaller dans ma solution en cours,
comme vous pouvez le voir sur la gure 17.6.
Figure 17.6 Installation de Mvvm Light Toolkit
Faites Ok et acceptez galement la licence. Et voil, cest install !
Vous pouvez aussi tout classiquement tlcharger linstalleur sur le site.
Vous pouvez voir que dans votre projet, les assemblys suivantes ont automatiquement
t rfrences :
228
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
GalaSoft.MvvmLight.Extras.WP8.dll
GalaSoft.MvvmLight.WP8.dll
Microsoft.Practices.ServiceLocation
System.Windows.Interactivity.dll
sachant que la dernire est une assembly de Blend et que lavant dernire permet
dutiliser le service locator.
Recrez alors un rpertoire View pour y mettre votre page VoirClientView.xaml,
un rpertoire Model avec la classe Client et un rpertoire ViewModel avec une classe
VoirClientViewModel. La classe Client est la mme que prcdemment, le service
aussi. Nous allons simplement lui rajouter une interface en plus :
1 public class Client
2 {
3 public string Prenom { get; set; }
4 public int Age { get; set; }
5 public bool EstBonClient { get; set; }
6 }
7
8 public interface IServiceClient
9 {
10 Client Charger ();
11 }
12
13 public class ServiceClient : IServiceClient
14 {
15 public Client Charger ()
16 {
17 return new Client { Prenom = "Nico", Age = 30,
EstBonClient = true };
18 }
19 }
Puis nous allons rajouter une classe de design pour notre service. Au contraire de ce
que nous avons fait dans le chapitre prcdent, ce nest pas ici le view-model qui sera
en mode design, mais le model :
1 public class DesignServiceClient : IServiceClient
2 {
3 public Client Charger ()
4 {
5 return new Client { Prenom = "Nico", Age = 30,
EstBonClient = true };
6 }
7 }
Ici, la classe ServiceClient et la classe DesignServiceClient sont iden-
tiques, mais dans une vraie application, la classe ServiceClient irait
srement chercher les donnes en base ou autre. . .
229
CHAPITRE 17. MVVM
Puis notre view-model va hriter de ViewModelBase qui se situe dans lespace de nom
GalaSoft.MvvmLight :
1 using GalaSoft.MvvmLight;
2
3 public class VoirClientViewModel : ViewModelBase
4 {
5 }
Le service locator
Il est temps de crer le service locator an de bncier dun couplage faible entre
notre vue et le view-model, mais galement entre le view-model et le service, ce qui
nest pas indispensable mais ne fait pas de mal. Pour cela, crons une nouvelle classe
ViewModelLocator, je la place la racine du projet :
1 public class ViewModelLocator
2 {
3 static ViewModelLocator ()
4 {
5 ServiceLocator.SetLocatorProvider (() => SimpleIoc.
Default);
6
7 if (ViewModelBase.IsInDesignModeStatic)
8 SimpleIoc.Default.Register <IServiceClient ,
DesignServiceClient >();
9 else
10 SimpleIoc.Default.Register <IServiceClient ,
ServiceClient >();
11
12 SimpleIoc.Default.Register <VoirClientViewModel >();
13 }
14
15 public VoirClientViewModel VoirClientVM
16 {
17 get { return ServiceLocator.Current.GetInstance <
VoirClientViewModel >(); }
18 }
19 }
Noubliez pas dimporter les espaces de nom
Microsoft.Practices.ServiceLocation, GalaSoft.MvvmLight.Ioc et
GalaSoft.MvvmLight.
Elle contient un constructeur statique qui soccupe de linversion de dpendance en elle-
mme, savoir associer le service client de design avec linterface lorsquon est en mode
design, et le vrai service sinon. De mme, il enregistre une instance du view-model. Il
230
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
possde galement une proprit permettant daccder linstance du ViewModel :
VoirClientVM.
Jai choisi dappeler la proprit VoirClientVM alors que je laurai naturel-
lement appele VoirClientViewModel, an de bien voir la dirence entre
la proprit et la classe du view-model.
Ce locator devra tre dclar dans les ressources de lapplication, ainsi il sera accessible
depuis nimporte quelle vue. Modiez-donc le chier App.xaml pour avoir :
1 <Application.Resources >
2 <... />
3
4 <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="true"
/>
5 </Application.Resources >
Sans oublier de dclarer lespace de nom :
1 xmlns:vm="clr -namespace:DemoMvvmLight"
et dinclure les dclarations suivantes, quil nest pas ncessaire de comprendre :
1 xmlns:mc="http :// schemas.openxmlformats.org/markup -
compatibility/2006"
2 xmlns:d="http :// schemas.microsoft.com/expression/blend/2008"
3 mc:Ignorable="d"
Ceci correspond limplmentation du locator fourni dans les exemples du toolkit. Il
existe plusieurs implmentations possibles de ce locator, plus ou moins parfaites.
Lier la vue au view-model
Maintenant, pour lier le modle la vue il sura de modier la proprit Datacontext
de votre page pour avoir :
1 <phone:PhoneApplicationPage
2 x:Class="DemoMvvmLight.View.VoirClientView"
3 ...
4 DataContext="{Binding VoirClientVM , Source ={ StaticResource
Locator }}">
La liaison seectue donc sur la proprit publique VoirClientVM du locator, trouv
en ressource. Modions notre vue pour acher notre client :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="auto"/>
5 </Grid.RowDefinitions >
6
231
CHAPITRE 17. MVVM
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12 ,17,
0,28">
8 <TextBlock x:Name="PageTitle" Text="Fiche client"
Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
9 </StackPanel >
10
11 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
Background="{Binding BonClient}">
12 <Grid.RowDefinitions >
13 <RowDefinition Height="auto" />
14 <RowDefinition Height="auto" />
15 </Grid.RowDefinitions >
16 <Grid.ColumnDefinitions >
17 <ColumnDefinition Width="*" />
18 <ColumnDefinition Width="*" />
19 </Grid.ColumnDefinitions >
20 <TextBlock Text="Prnom : " />
21 <TextBlock Grid.Column="1" Text="{Binding Prenom}" />
22 <TextBlock Grid.Row="1" Text="Age : " />
23 <TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding
Age}" />
24 </Grid >
25 </Grid >
Maintenant, passons au view-model. Il ressemble beaucoup notre prcdent view-
model :
1 public class VoirClientViewModel : ViewModelBase
2 {
3 private readonly IServiceClient serviceClient;
4
5 private string prenom;
6 public string Prenom
7 {
8 get { return prenom; }
9 set { NotifyPropertyChanged(ref prenom , value); }
10 }
11
12 private int age;
13 public int Age
14 {
15 get { return age; }
16 set { NotifyPropertyChanged(ref age , value); }
17 }
18
19 private SolidColorBrush bonClient;
20 public SolidColorBrush BonClient
21 {
22 get { return bonClient; }
23 set { NotifyPropertyChanged(ref bonClient , value); }
232
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
24 }
25
26 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
27 {
28 if (object.Equals(variable , valeur)) return false;
29
30 variable = valeur;
31 RaisePropertyChanged(nomPropriete);
32 return true;
33 }
34
35 public VoirClientViewModel(IServiceClient service)
36 {
37 serviceClient = service;
38
39 Client client = serviceClient.Charger ();
40 Prenom = client.Prenom;
41 Age = client.Age;
42 if (client.EstBonClient)
43 BonClient = new SolidColorBrush(Color.FromArgb(100 ,
0, 255 , 0));
44 else
45 BonClient = new SolidColorBrush(Color.FromArgb(100 ,
255 , 0, 0));
46 }
47 }
La dirence vient bien sr en premier lieu de lhritage ViewModelBase mais surtout
de lapplication de linversion de dpendance dans le constructeur du view-model. Ainsi,
notre view-model rcupre automatiquement une instance de notre service. Notons
aussi la dirence dans la mthode NotifyPropertyChanged qui doit appeler mainte-
nant la mthode RaisePropertyChanged de la classe de base, ViewModelBase. Cette
mthode correspond notre mthode NotifyPropertyChanged mais on se demande
pourquoi le crateur du toolkit na pas crit de surcharge de cette mthode utilisant
les nouveauts du framework 4.5 et notamment lattribut CallerMemberName, du coup
nous sommes toujours obligs dutiliser une variation de la mthode NotifyPropertyChanged.
Noubliez pas de faire en sorte que ce soit la bonne vue qui sache lors du dmarrage
de lapplication et vous pourrez observer votre application qui fonctionne grce au
toolkit MVVM Light. Bravo !
Vous aurez galement constat quen mode design, nous pouvons aussi voir
des donnes.
Jusque-l, nous ne sommes pas trop dpayss part dans lutilisation du service locator.
233
CHAPITRE 17. MVVM
Les commandes
Passons maintenant aux commandes sur le bouton. Je vous ai indiqu quil est possible
de passer un paramtre un bouton. Pour illustrer ce fonctionnement, nous allons crer
une nouvelle page qui achera une liste de clients. Modions notre service pour avoir
la mthode suivante :
1 public interface IServiceClient
2 {
3 Client Charger ();
4 List <Client > ChargerTout ();
5 }
6
7 public class ServiceClient : IServiceClient
8 {
9 public Client Charger ()
10 {
11 return new Client { Prenom = "Nico", Age = 30,
EstBonClient = true };
12 }
13
14 public List <Client > ChargerTout ()
15 {
16 return new List <Client >
17 {
18 new Client { Age = 30, EstBonClient = true , Prenom
= "Nico"},
19 new Client { Age = 20, EstBonClient = false , Prenom
= "Jrmie"},
20 new Client { Age = 30, EstBonClient = true , Prenom
= "Delphine"}
21 };
22 }
23 }
Et pareil dans la classe DesignServiceClient.
Rajoutons une nouvelle vue dans le rpertoire View que nous allons appeler ListeClientsView.xaml.
Et enn, crons un nouveau view-model que nous appellerons ListeClientsViewModel
et qui hritera de ViewModelBase. Noubliez pas de dclarer le nouveau view-model
dans le locator :
1 public class ViewModelLocator
2 {
3 static ViewModelLocator ()
4 {
5 ServiceLocator.SetLocatorProvider (() => SimpleIoc.
Default);
6
7 if (ViewModelBase.IsInDesignModeStatic)
234
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
8 SimpleIoc.Default.Register <IServiceClient ,
DesignServiceClient >();
9 else
10 SimpleIoc.Default.Register <IServiceClient ,
ServiceClient >();
11
12 SimpleIoc.Default.Register <VoirClientViewModel >();
13 SimpleIoc.Default.Register <ListeClientsViewModel >();
14 }
15
16 public VoirClientViewModel VoirClientVM
17 {
18 get { return ServiceLocator.Current.GetInstance <
VoirClientViewModel >(); }
19 }
20
21 public ListeClientsViewModel ListeClientsVM
22 {
23 get { return ServiceLocator.Current.GetInstance <
ListeClientsViewModel >(); }
24 }
25 }
Votre vue va possder une ListBox dont le template contiendra un bouton :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <ListBox ItemsSource="{Binding ListeClients}">
3 <ListBox.ItemTemplate >
4 <DataTemplate >
5 <Button Content="Qui suis -je ?" Command="{
Binding QuiSuisJeCommand}" CommandParameter=
"{Binding}" />
6 </DataTemplate >
7 </ListBox.ItemTemplate >
8 </ListBox >
9 </Grid >
Le code XAML prcdent contient volontairement une erreur que nous corri-
gerons un peu plus loin.
Nous voyons que notre ListBox est lie une proprit ListeClients qui devra tre
prsente dans notre view-model. Le bouton prsent dans le template possde une com-
mande lie la commande QuiSuisJeCommand. Remarquons la proprit CommandParameter
qui permet de positionner llment en cours comme paramtre de la commande. Liez
ensuite le view-model la vue en modiant la proprit Datacontext avec notre nou-
velle proprit dans le locator :
1 DataContext="{Binding ListeClientsVM , Source ={ StaticResource
Locator }}">
235
CHAPITRE 17. MVVM
Passons notre view-model dsormais :
1 public class ListeClientsViewModel : ViewModelBase
2 {
3 private List <Client > listeClients;
4 public List <Client > ListeClients
5 {
6 get { return listeClients; }
7 set { NotifyPropertyChanged(ref listeClients , value); }
8 }
9
10 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
11 {
12 if (object.Equals(variable , valeur)) return false;
13
14 variable = valeur;
15 RaisePropertyChanged(nomPropriete);
16 return true;
17 }
18
19 public ICommand QuiSuisJeCommand { get; set; }
20
21 public ListeClientsViewModel(IServiceClient service)
22 {
23 ListeClients = service.ChargerTout ();
24
25 QuiSuisJeCommand = new RelayCommand <Client >( QuiSuisJe);
26 }
27
28 private void QuiSuisJe(Client client)
29 {
30 MessageBox.Show("Je suis " + client.Prenom);
31 }
32 }
Remarque, la classe RelayCommand ncessite limport suivant :
1 using GalaSoft.MvvmLight.Command;
Nous avons cr la proprit ListeClients que nous avons alimente dans le construc-
teur grce au modle. Puis nous voyons comment dnir une commande qui accepte
un paramtre. En loccurrence, ici le paramtre sera du type Client car cest le type
que nous passons dans :
1 CommandParameter="{Binding}"
Lextension de balisage {Binding} prend ici llment courant de la proprit nu-
mrable ListeClients qui est bien de type Client. Une fois le bouton cliqu, nous
pourrons alors acher le client slectionn grce la boite de message MessageBox.
Vrions cela en dmarrant lapplication. Noubliez pas de changer le point den-
tre de lapplication dans le chier WMAppManifest.xml an quil dmarre sur la vue
236
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
ListeClientsView.xaml. Sauf que. . . cela ne marche pas. Le clic sur le bouton ne fait
rien ! Si vous observez bien la fentre de sortie de Visual Studio, vous pouvez constater
lerreur suivante, erreur que vous aurez loccasion de souvent voir :
1 System.Windows.Data Error: BindingExpression path error: '
QuiSuisJeCommand ' property not found on 'DemoMvvmLight.Model
.Client ' 'DemoMvvmLight.Model.Client '
2 (HashCode=23288300). BindingExpression: Path='QuiSuisJeCommand '
DataItem='DemoMvvmLight.Model.Client ' (HashCode=23288300);
target element is 'System.Windows.Controls.Button '
3 (Name=''); target property is 'Command ' (type 'System.Windows.
Input.ICommand ')..
Une erreur de binding. . . Argh! On nous indique que la proprit QuiSuisJeCommand
est introuvable sur lobjet Client. Ce qui est vrai en soit, notre classe Client ne
possde pas cette commande ! Mais nous, ce que nous voulions cest que la commande
QuiSuisJeCommand soit celle du view-model. Comme ce que nous avions fait prcdem-
ment. Cest rageant, on fait pareil, mais cela ne fonctionne pas ! Essayons de comprendre
pourquoi.
Je vous donne un indice : Datacontext.
En eet, dans notre exemple prcdent, notre commande est lie un bouton dont le
contexte est celui hrit de celui de la page, car il na pas t chang. Nous avions li la
proprit Datacontext de la page au view-model et tous les Datacontext des objets
de la page ont hrit de ce contexte. Ici, nous avons chang le contexte de la ListBox
pour lui fournir une liste de clients. Dans chaque template des lments de la ListBox,
nous sommes sur un objet Client et plus sur le view-model. Cest pour cela quil ne
trouve pas la proprit QuiSuisJeCommand et quil ne peut pas faire correctement le
binding. Cest une erreur trs classique que lon peut rsoudre de plusieurs faons. La
premire est de faire en sorte que le contexte courant puisse connatre le view-model.
En loccurrence, on pourrait ajouter une proprit pointant sur le view-model lobjet
Client ou mme mieux crer un nouvel objet ddi au binding qui contient cette
proprit. Crons donc une classe ClientBinding :
1 public class ClientBinding
2 {
3 public string Prenom { get; set; }
4 public int Age { get; set; }
5 public bool EstBonClient { get; set; }
6 public ListeClientsViewModel ViewModel { get; set; }
7 }
Puis changeons le type de la proprit ListeClient pour avoir une List<ClientBinding>.
Et modions le constructeur pour avoir :
1 public ListeClientsViewModel(IServiceClient service)
2 {
3 ListeClients = service.ChargerTout ().Select(c => new
ClientBinding { Age = c.Age , EstBonClient = c.
EstBonClient , Prenom = c.Prenom , ViewModel = this }).
ToList ();
237
CHAPITRE 17. MVVM
4
5 QuiSuisJeCommand = new RelayCommand <ClientBinding >(
QuiSuisJe);
6 }
Remarquez que jai aussi chang le type gnrique de RelayCommand pour avoir un
ClientBinding vu que dsormais, cest un objet de ce type qui est li au paramtre
de la commande. Ce qui implique galement de changer le type du paramtre de la
mthode QuiSuisJe() :
1 private void QuiSuisJe(ClientBinding client)
2 {
3 MessageBox.Show("Je suis " + client.Prenom);
4 }
(noubliez pas de rajouter le using de lespace de nom System.Linq;).
Chaque client possde donc une proprit ViewModel contenant le view-model en cours
grce this. Il ne reste plus qu modier lextension de balisage pour avoir :
1 <Button Content="Qui suis -je ?" Command="{Binding ViewModel.
QuiSuisJeCommand}" CommandParameter="{Binding}" />
Et voil, cela fonctionne. Mais cela implique pas mal de changement. . . Lautre solution
est de lier directement la proprit Command la proprit QuiSuisJeCommand de la
proprit du locator pour accder au view-model. Plus besoin de classe intermdiaire
qui contient une rfrence vers le view-model. Il sut dcrire :
1 <Button Content="Qui suis -je ?" Command="{Binding Source ={
StaticResource Locator}, Path=ListeClientsVM.
QuiSuisJeCommand}" CommandParameter="{Binding}" />
Et le rsultat est le mme, ainsi que vous pouvez le constater sur la gure 17.7.
Pouvoir passer un paramtre une commande est trs pratique dans ce genre de situa-
tion. La classe RelayCommand du toolkit nous aide bien pour rcuprer ce paramtre,
que lon retrouve en paramtre de la mthode QuiSuisJe(). Elle sait faire encore une
chose intressante, savoir de permettre de savoir si la commande est utilisable ou
pas. Rappelez-vous, cest ce que nous avions vu plus haut. Il sagissait de la mthode
CanExecute de linterface ICommand. Javais dcid arbitrairement que cette mthode
renverrait toujours vrai. La classe RelayCommand de MVVM Light permet dassocier
une condition la possibilit dexcuter une commande. Par exemple, on pourrait ima-
giner quon ne puisse cliquer sur le bouton que des clients qui sont des bons clients. Cest
de la sgrgation, mais cest comme a. Les mauvais clients resteront inconnus ! Pour
ce faire, on utilisera le deuxime paramtre du constructeur de la classe RelayCommand
qui permet de dnir une mthode qui servira de prdicat permettant dindiquer si la
commande peut tre excute ou non. Ici, nous aurons simplement besoin de renvoyer la
valeur du boolen EstBonClient, mais cela pourrait tre une mthode plus complexe.
Notre instanciation de commande devient donc :
1 QuiSuisJeCommand = new RelayCommand <Client >(QuiSuisJe ,
CanExecuteQuiSuisJe);
238
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
Figure 17.7 Achage dun message suite lactivation de la commande
avec :
1 private bool CanExecuteQuiSuisJe(Client client)
2 {
3 if (client == null)
4 return false;
5 return client.EstBonClient;
6 }
Ainsi, non seulement il ne sera pas possible dexcuter la commande en cliquant sur le
bouton, mais le bouton est galement gris, signe de son tat dsactiv (voir la gure
17.8).
Plutt pratique quand un bouton doit tre dsactiv. Juste avant de terminer ce point,
remarquons que le prdicat associ la possibilit dexcution dune commande est
excut une unique fois. Si jamais notre client venait devenir un bon client, notre
bouton resterait dans un tat dsactiv car il naura pas t mis au courant de ce
changement. ce moment-l, MVVM Light fournit une mthode qui permet ce
prdicat de se rvaluer et ainsi modier ventuellement ltat du bouton. Il sagit de
la mthode RaiseCanExecuteChanged. On pourra lutiliser ainsi :
1 (( RelayCommand)QuiSuisJeCommand).RaiseCanExecuteChanged ();
Continuons cet aperu de MVVM Light et de ses commandes en vous indiquant com-
ment relier nimporte quel vnement une commande. Par exemple, lvnement de
239
CHAPITRE 17. MVVM
Figure 17.8 Le bouton est gris quand la commande nest pas utilisable
slection dun lment dans une ListBox. Premire chose faire, modier ma vue pour
ne plus avoir ce bouton, mais simplement pour avoir le prnom du client an quil soit
facilement slectionnable :
1 <ListBox ItemsSource="{Binding ListeClients}">
2 <ListBox.ItemTemplate >
3 <DataTemplate >
4 <TextBlock Text="{Binding Prenom}" Margin="10 30 0
0" />
5 </DataTemplate >
6 </ListBox.ItemTemplate >
7 </ListBox >
Avant, pour savoir quand un lment dun ListBox est slectionn, on se serait abonn
lvnement SelectionChanged. Grce MVVM Light, on peut utiliser laction
EventToCommand :
1 <ListBox ItemsSource="{Binding ListeClients}">
2 <Interactivity:Interaction.Triggers >
3 <Interactivity:EventTrigger EventName="SelectionChanged
" >
4 <Command:EventToCommand Command="{Binding
SelectionElementCommand}" PassEventArgsToCommand
="True"/>
5 </Interactivity:EventTrigger >
240
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
6 </Interactivity:Interaction.Triggers >
7 <ListBox.ItemTemplate >
8 <DataTemplate >
9 <TextBlock Text="{Binding Prenom}" Margin="10 30 0
0" />
10 </DataTemplate >
11 </ListBox.ItemTemplate >
12 </ListBox >
Sachant quil faudra importer les espaces de noms suivants :
1 xmlns:Command="clr -namespace:GalaSoft.MvvmLight.Command;
assembly=GalaSoft.MvvmLight.Extras.WP8"
2 xmlns:Interactivity="clr -namespace:System.Windows.Interactivity
;assembly=System.Windows.Interactivity"
Le XAML est un peu plus verbeux, je vous le concde. Le principe est dutiliser les
triggers de Blend qui correspondent au dclenchement dun vnement, de prciser
lvnement choisi dans la proprit EventName et on pourra alors se brancher sur
nimporte quel vnement, ici lvnement SelectionChanged.
Reste dnir la commande dans le view-model :
1 public ICommand SelectionElementCommand { get; set; }
et linstancier, par exemple dans le constructeur :
1 SelectionElementCommand = new RelayCommand <
SelectionChangedEventArgs >( OnSelectionElement);
Avec la mthode associe :
1 private void OnSelectionElement(SelectionChangedEventArgs args)
2 {
3 }
Remarquez que nous avons positionn la proprit PassEventArgsToCommand de EventToCommand
true et que nous pouvons ainsi obtenir largument de lvnement en paramtre de la
commande. En loccurrence, pour lvnement SelectionChanged, nous obtenons un
paramtre du type SelectionChangedEventArgs.
La messagerie
a commence ressembler quelque chose, mais quest-ce quon pourrait bien faire
une fois un client slectionn ? Vous me voyez venir. . . on pourrait naviguer sur la vue
VoirClientView.xaml et acher le dtail du client. Rien de plus simple, nous savons
naviguer dans notre application, on la vu dans la partie prcdente. . . sauf que nous
nous heurtons un problme de taille. Vous devinez ?
Le service de navigation est une proprit de la PhoneApplicationPage. cause de
notre sparation des responsabilits, la mthode associe la commande se trouve dans
le view-model qui na aucune connaissance de la vue.
241
CHAPITRE 17. MVVM
Aie. Comment retrouver notre service de navigation ?
Ceci fait partie dun problme plus gnral, savoir : comment faire pour que le view-
model puisse agir sur la prsentation part en utilisant les mcanismes du binding ?
La navigation se retrouve exactement dans ce cas-l. Cest le code-behind qui aurait
normalement pris en charge cette navigation, sauf que l, cest impossible. On retrouve
un cas similaire lorsque lon cherche acher une boite de dialogue, autre que la
MessageBox.
MVVM Light propose une solution pour rsoudre cet pineux problme travers son
systme de messagerie. Ce systme ore la possibilit de pouvoir communiquer de
manire dcouple entre un view-model et sa vue ou entres view-models. Le principe
est que lmetteur envoie un message au systme de messagerie, qui le diuse ceux qui
sy sont abonn. Dans notre cas, il faut donc que le code-behind sabonne au message :
1 public partial class ListeClientsView : PhoneApplicationPage
2 {
3 public ListeClientsView ()
4 {
5 InitializeComponent ();
6 Messenger.Default.Register <Client >(this , AfficheClient)
;
7 }
8
9 private void AfficheClient(Client client)
10 {
11 PhoneApplicationService.Current.State["Client"] =
client;
12 NavigationService.Navigate(new Uri("/View/
VoirClientView.xaml", UriKind.Relative));
13 }
14 }
Cela se fait grce la mthode Register du Messenger, qui se trouve dans lespace
de nom GalaSoft.MvvmLight.Messaging. On indique que lon sabonne aux messages
qui prendront un client en paramtre et que dans ce cas, la mthode AfficheClient
est appele. La mthode AfficheClient fait une navigation toute simple, comme on
la dj vu.
Il faut maintenant que le view-model mette le message, mais avant a, nous allons
ajouter une liaison de donnes pour rcuprer llment slectionn de la ListBox.
Remarque, on pourrait le faire avec la valeur de largument, mais cest plus propre
de faire comme a. Donc changeons notre ListBox pour avoir la liaison sur llment
slectionn :
1 <ListBox ItemsSource="{Binding ListeClients}" SelectedItem="{
Binding Selection , Mode=TwoWay}">
242
LES FRAMEWORKS LA RESCOUSSE : MVVM-LIGHT
tant donn que notre proprit sera mise jour partir de linterface, le binding doit
tre dans les deux sens, do le mode TwoWay. Ajoutons la proprit Selection dans
le view-model :
1 private Client selection = null;
2 public Client Selection
3 {
4 get { return selection; }
5 set { NotifyPropertyChanged(ref selection , value); }
6 }
Il ny a plus qu envoyer le message depuis la commande de slection. On utilise pour
cela la mthode Send du Messenger :
1 private void OnSelectionElement(SelectionChangedEventArgs args)
2 {
3 Messenger.Default.Send(Selection);
4 }
Rsumons.
Lutilisateur slectionne un lment de la ListBox
La commande associe lvnement est dclenche sur le view-model
Le view-model met un message avec le client slectionn
Le code-behind de la vue, qui sest abonn ce type de message, reoit le message
mit par le view-model et dclenche la navigation
Pour terminer proprement la petite application, il faudrait que la vue qui ache un
client utilise les donnes positionnes dans le dictionnaire dtat. Alors, comment feriez-
vous ?
Il y a plusieurs solutions, je vous propose la plus simple. Nous allons proter quun
message est dius chaque slection dun lment pour mettre jour les proprits
du view-model :
1 public VoirClientViewModel ()
2 {
3 Messenger.Default.Register <Client >(this , MetAJourClient);
4 Client client = (Client)PhoneApplicationService.Current.
State["Client"];
5 MetAJourClient(client);
6 }
7
8 private void MetAJourClient(Client client)
9 {
10 Prenom = client.Prenom;
11 Age = client.Age;
12 if (client.EstBonClient)
13 BonClient = new SolidColorBrush(Color.FromArgb(100 , 0,
255 , 0));
14 else
15 BonClient = new SolidColorBrush(Color.FromArgb(100 , 255
, 0, 0));
243
CHAPITRE 17. MVVM
16 }
Il sut de sabonner galement la rception de ce message an de mettre jour
les proprits avec le nouveau client courant. Ce message est bien celui mit par le
view-model de la liste des clients et cest le view-model qui permet de voir un client
qui le reoit aprs sy tre abonn. Il faudra faire attention linitialisation o nous
utiliserons le dictionnaire dtat pour rcuprer la premire slection.
Notons enn que vous devez rinitialiser la proprit Selection an que la ListBox ne
conserve pas la slection lors du retour arrire sur la page :
1 private void OnSelectionElement(SelectionChangedEventArgs args)
2 {
3 if (Selection == null)
4 return;
5 Messenger.Default.Send(Selection);
6 Selection = null;
7 }
Voil pour ce petit tour de MVVM Light. Nous avons vu lessentiel de ce toolkit qui
propose des solutions pour aider la mise en place du patron de conception MVVM.
Noubliez pas que malgr sa dnomination de light, cest un framework complet qui
prend sa place (110 ko). Il est en fait light par rapport dautres framework, comme
PRISM qui est utilis avec WPF. A utiliser en connaissance de cause.
Dautres frameworks MVVM
MVVM Light nest pas le seul framework aidant la mise en place de MVVM. Cest
assurment lun des plus connus, mais dautres existent respectant plus ou moins bien
le patron de conception et apportant des outils dirents. Citons par exemple :
Calcium - http://calcium.codeplex.com/
Caliburn Micro - http://caliburnmicro.codeplex.com/
Catel - http://catel.codeplex.com/
nRoute - http://nroute.codeplex.com/
Simple MVVM Toolkit - http://simplemvvmtoolkit.codeplex.com/
UltraLight.mvvm - http://ultralightmvvm.codeplex.com/
Je ne peux pas bien sur tous les prsenter et dailleurs je ne les ai pas tous tests :-
. Jaime bien lUltraLight.mvvm qui, via son locator, ore une liaison avec la page ce
qui permet facilement de dmarrer une navigation sans passer par lutilisation dune
messagerie. Nhsitez pas les tester pour vous faire votre propre opinion et pour vous
permettre de voir ce que vous souhaitez garder de MVVM et ce dont vous pouvez vous
passer.
244
FAUT-IL UTILISER SYSTMATIQUEMENT MVVM?
Faut-il utiliser systmatiquement MVVM?
MVVM est complexe apprhender. Pour bien le comprendre, il faut pratiquer. Ce
nest que petit petit que vous verrez vraiment de quoi vous avez besoin et quel
moment. Jimagine que pour linstant, vous avez limpression que MVVM pose plus
de problmes quil nen rsout et quon se complique la vie pour pas grand-chose.
Franchement, le coup de la navigation et de la messagerie, cest cens nous simplier la
vie ? Il est vrai que lorsque lon ralise des petites applications, respecter parfaitement le
patron de conception MVVM est sans doute un peu dmesur. Cela implique toute une
mcanique qui est plutt longue mettre en place et parfois ennuyeuse, pour un gain
pas forcment vident. Noubliez cependant pas que le but premier de MVVM est de
sparer les responsabilits, notamment en sparant les donnes de la vue. Cela facilite
les oprations de maintenance en limitant lternel problme du plat de spaghetti o
la moindre correction a des impacts sur un autre bout de code. Mon avis sur MVVM
est que peu importe si vous ne respectez pas parfaitement MVVM, le principe de ce
pattern est de vous aider dans la ralisation de votre application et surtout dans sa
maintenabilit.
Lintrt galement est quil devient possible de faire des tests unitaires sur le view-
model, sans avoir besoin de charger lapplication et de cliquer partout. Cela permet
de tester chaque fonctionnalit, dans un processus automatis, ce qui dans une grosse
application est un atout considrable pour viter les rgressions. En tous cas, nayez
crainte. Vous ntes pas obligs de pratiquer MVVM tout de suite. En tant que d-
butant, vous aurez plutt intrt commencer crer des applications et ensuite
chercher appliquer des bonnes pratiques. Dans ce cas, nhsitez pas revenir lire ce
chapitre .
Remarque : par souci de simplicit et de concision, je ne respecterai pas
MVVM dans la suite de ce cours.
En rsum
MVVM est un patron de conception qui aide la ralisation dapplications
denvergure utilisant le XAML.
Des frameworks gratuits nous aident la mise en place de ce patron de concep-
tion en fournissant des bibliothques remplies de classes prouves.
Le respect et lutilit de MVVM se dcouvrent en pratiquant. Ne soyez pas
forcment trop presss de respecter parfaitement MVVM.
245
CHAPITRE 17. MVVM
246
Chapitre 18
Gestion des tats visuels
Dicult :
Maintenant que nous connaissons les templates, nous allons revenir sur un point qui vous
sera srement utile dans le dveloppement de vos applications. Il sagit de la gestion des
tats visuels. Mais quest-ce donc ? Prenons un bouton par exemple, il possde plusieurs
tats visuels. Il y a ltat quand il est cliqu, ltat quand il est dsactiv et ltat lorsquil
est au repos.
Cest la mme chose pour une ListBox, nous avons par exemple vu un tat o un lment
est slectionn, qui est dailleurs mis en avant grce la couleur daccentuation du tl-
phone. Tous les contrles ont potentiellement plusieurs reprsentations visuelles en fonction
de leurs tats. Voyons voir comment cela fonctionne.
247
CHAPITRE 18. GESTION DES TATS VISUELS
Les tats dun contrle
Observons les tats de notre bouton plus en dtail. la gure 18.1, vous pouvez le voir
dans son tat normal, au repos.
Figure 18.1 Etat du bouton au repos
la gure 18.2, vous voyez son tat quand il est cliqu.
Figure 18.2 Etat du bouton cliqu
Et sur la gure 18.3, lorsquil est dsactiv et donc non cliquable.
Figure 18.3 Etat du bouton dsactiv
Ils correspondent respectivement aux tats :
Normal
Pressed
Disabled
248
LES TATS DUN CONTRLE
Chaque contrle dispose de dirents tats. Les tats changent automatiquement en
fonction dune action utilisateur ou dune proprit. Par exemple, cest en cliquant sur
le bouton que celui-ci passe de ltat Normal Pressed et en relchant le clic que
celui-ci passe de Pressed Normal, changeant au passage lapparence du contrle.
Pour ltat dsactiv, ce changement se fait quand on passe la proprit IsEnabled
false. Le bouton possde dautres tats qui ne sont pas utiliss pour Windows Phone,
comme ltat Focused et ltat Unfocused qui correspondent au fait que le bouton ait
le focus ou pas, ce qui ne sert pas vraiment dans une application pour Windows Phone,
ainsi que ltat MouseOver qui correspond au passage de la souris sur le bouton.
On dit quun contrle possde le focus quand il est la cible des actions de
saisie de lutilisateur, comme le clavier. Cest trs valable pour une application
PC, mais beaucoup moins pour une application de tlphone.
Ces trois tats du bouton sont un hritage de Silverlight pour PC, ils ne servent pas
avec le XAML pour Windows Phone. Un contrle peut tre dans plusieurs tats
la fois, par exemple si ctait valable on pourrait envisager quil soit dans un tat
Pressed et un tat o il ait le focus. Par contre, dautres tats sont exclusifs, il nest
bien sr pas possible que le bouton soit dans ltat Pressed et dans ltat Normal. . .
Pour reprsenter ceci, les tats appartiennent des groupes. Le bouton ne peut avoir
quun seul tat par groupe. En loccurrence, notre bouton possde deux groupes avec
les tats suivants :
Groupe FocusStates :
Focused
Unfocused
Groupe CommonStates :
Pressed
Disabled
Normal
MouseOver
chaque tat donc son apparence. . . ce qui implique que nous pouvons modier les
apparences de chaque tat via des templates que nous allons dnir dans un style.
Pour comprendre, le plus simple est dutiliser Blend. Ajoutons un bouton dans notre
XAML :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <StackPanel >
3 <Button x:Name="But" Content="Cliquez -moi !" />
4 </StackPanel >
5 </Grid >
Puis dmarrons Blend en faisant un clic droit sur le projet, puis ouvrir dans expression
blend. Une fois ouvert, cliquez sur le bouton pour le slectionner et faites un clic droit
pour modier une copie du modle, comme indiqu la gure 18.4.
Cela permet de crer un style automatiquement (voir la gure 18.5).
249
CHAPITRE 18. GESTION DES TATS VISUELS
Figure 18.4 Modication du modle du bouton dans Blend
Figure 18.5 Cration du style par dfaut du bouton
250
LES TATS DUN CONTRLE
Maintenant, nous pouvons voir dans longlet Etats, les dirents tats du bouton,
comme vous pouvez le constater sur la gure 18.6.
Figure 18.6 Les dirents tats du bouton
Remarquons que le XAML est dsormais :
1 <phone:PhoneApplicationPage
2 x:Class="DemoEtatVisuel.MainPage"
3 ...>
4 <phone:PhoneApplicationPage.Resources >
5 <Style x:Key="ButtonStyle1" TargetType="Button"
>
6 <Setter Property="Background" Value="
Transparent"/>
7 <Setter Property="BorderBrush" Value="{
StaticResource PhoneForegroundBrush}"/>
8 <Setter Property="Foreground" Value="{
StaticResource PhoneForegroundBrush}"/>
9 <Setter Property="BorderThickness" Value="{
StaticResource PhoneBorderThickness}"/>
10 <Setter Property="FontFamily" Value="{
StaticResource PhoneFontFamilySemiBold}"/>
11 <Setter Property="FontSize" Value="{
StaticResource PhoneFontSizeMedium}"/>
12 <Setter Property="Padding" Value="10 ,5,10,6"/>
13 <Setter Property="Template">
14 <Setter.Value >
15 <ControlTemplate TargetType="Button">
16 <Grid Background="Transparent">
17 <VisualStateManager.VisualStateGroups >
18 <VisualStateGroup x:Name="CommonStates"
>
19 <VisualState x:Name="Normal"/>
20 <VisualState x:Name="MouseOver"/>
21 <VisualState x:Name="Pressed">
251
CHAPITRE 18. GESTION DES TATS VISUELS
22 <Storyboard >
23 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="
Foreground" Storyboard.TargetName="
ContentContainer">
24 <DiscreteObjectKeyFrame KeyTime="0"
Value="{StaticResource
PhoneButtonBasePressedForegroundBrush
}"/>
25 </ObjectAnimationUsingKeyFrames >
26 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="
Background" Storyboard.TargetName="
ButtonBackground">
27 <DiscreteObjectKeyFrame KeyTime="0"
Value="{StaticResource
PhoneAccentBrush}"/>
28 </ObjectAnimationUsingKeyFrames >
29 </Storyboard >
30 </VisualState >
31 <VisualState x:Name="Disabled">
32 <Storyboard >
33 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="
Foreground" Storyboard.TargetName="
ContentContainer">
34 <DiscreteObjectKeyFrame KeyTime="0"
Value="{StaticResource
PhoneDisabledBrush}"/>
35 </ObjectAnimationUsingKeyFrames >
36 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="
BorderBrush" Storyboard.TargetName="
ButtonBackground">
37 <DiscreteObjectKeyFrame KeyTime="0"
Value="{StaticResource
PhoneDisabledBrush}"/>
38 </ObjectAnimationUsingKeyFrames >
39 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="
Background" Storyboard.TargetName="
ButtonBackground">
40 <DiscreteObjectKeyFrame KeyTime="0"
Value="Transparent"/>
41 </ObjectAnimationUsingKeyFrames >
42 </Storyboard >
43 </VisualState >
44 </VisualStateGroup >
45 <VisualStateGroup x:Name="FocusStates"
/>
252
LES TATS DUN CONTRLE
46 </VisualStateManager.VisualStateGroups >
47 <Border x:Name="ButtonBackground"
BorderBrush="{TemplateBinding
BorderBrush}" BorderThickness="{
TemplateBinding BorderThickness}"
Background="{TemplateBinding
Background}" CornerRadius="0" Margin
="{StaticResource
PhoneTouchTargetOverhang}">
48 <ContentControl x:Name="
ContentContainer" ContentTemplate="{
TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Foreground="{TemplateBinding
Foreground}"
HorizontalContentAlignment="{
TemplateBinding
HorizontalContentAlignment}" Padding
="{TemplateBinding Padding}"
VerticalContentAlignment="{
TemplateBinding
VerticalContentAlignment}"/>
49 </Border >
50 </Grid >
51 </ControlTemplate >
52 </Setter.Value >
53 </Setter >
54 </Style >
55 </phone:PhoneApplicationPage.Resources >
56
57 <Grid x:Name="LayoutRoot" Background="Transparent">
58 <Grid.RowDefinitions >
59 <RowDefinition Height="Auto"/>
60 <RowDefinition Height="*"/>
61 </Grid.RowDefinitions >
62
63 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12
,17 ,0,28">
64 <TextBlock Text="MON APPLICATION" Style="{
StaticResource PhoneTextNormalStyle}" Margin="12
,0"/>
65 <TextBlock Text="nom de la page" Margin="9,-7,0,0"
Style="{StaticResource PhoneTextTitle1Style}"/>
66 </StackPanel >
67
68 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,
12 ,0">
69 <StackPanel >
70 <Button x:Name="But" Content="Cliquez -moi !"
Style="{StaticResource ButtonStyle1}" />
253
CHAPITRE 18. GESTION DES TATS VISUELS
71 </StackPanel >
72 </Grid >
73 </Grid >
74 </phone:PhoneApplicationPage >
Beaucoup de choses, mais ce quil faut regarder prcisment cest que Blend a dclar
un nouveau template du bouton, celui-ci est simplement :
1 <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding
BorderBrush}" BorderThickness="{TemplateBinding
BorderThickness}" Background="{TemplateBinding Background}"
CornerRadius="0" Margin="{StaticResource
PhoneTouchTargetOverhang}">
2 <ContentControl x:Name="ContentContainer"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}" Foreground="{
TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding
HorizontalContentAlignment}" Padding="{
TemplateBinding Padding}" VerticalContentAlignment="
{TemplateBinding VerticalContentAlignment}"/>
3 </Border >
Bref, un contrle Border contenant un contrle ContentControl, ce qui est prcisment
le look du bouton tel que nous le connaissons.
Lextension de balisage TemplateBinding permet de lier la valeur dune
proprit dans un modle an de la dnir comme valeur dune autre proprit
expose dans le contrle. Typiquement ici, le fait de dnir par exemple la
proprit Foreground sur le contrle Button va en fait appliquer cette valeur
au contrle ContentControl.
Ensuite, il faut regarder lintrieur de la balise <VisualStateManager.VisualStateGroups>.
lintrieur sont dnis tous les groupes dtats du contrle :
1 <VisualStateManager.VisualStateGroups >
2 <VisualStateGroup x:Name="CommonStates">
3 <VisualState x:Name="Normal"/>
4 <VisualState x:Name="MouseOver"/>
5 <VisualState x:Name="Pressed">
6 <Storyboard >
7 ...
8 </Storyboard >
9 </VisualState >
10 <VisualState x:Name="Disabled">
11 <Storyboard >
12 ...
13 </Storyboard >
14 </VisualState >
15 </VisualStateGroup >
254
MODIFIER UN TAT
16 <VisualStateGroup x:Name="FocusStates"/>
17 </VisualStateManager.VisualStateGroups >
Ce quon peut voir cest que les tats dnissent une animation qui permet de changer
la valeur de certaines proprits lorsque le contrle change dtat. Par exemple, en
passant ltat Pressed, nous pouvons constater que la proprit Foreground passe
la valeur de PhoneButtonBasePressedForegroundBrush.
Voil comment sont dnis les tats, dans des modles.
Modier un tat
Ceci nous permet de faire ce que nous voulons avec les tats des contrles an damlio-
rer le look de nos boutons. Rappelez-vous dans la premire partie, nous avions modi
lapparence dun bouton en modiant sa proprit Content :
1 <Button x:Name="But">
2 <Button.Content >
3 <StackPanel >
4 <Image Source="rouge.png" Width="100" Height="100"
/>
5 <TextBlock Text="Cliquez -moi !" />
6 </StackPanel >
7 </Button.Content >
8 </Button >
Comme on peut sen rendre compte maintenant que nous avons vu le modle original du
contrle, nous navons modi que ce qui correspondait au contenu du ContentControl.
Le cadre est donc conserv, mais plus encore, la mme animation sur le fond du cadre
existe toujours. Ceci ne correspond peut-tre pas ce que nous souhaitons avoir lorsque
le bouton est cliqu. En loccurrence, moi ce que je voudrais, cest que le rond rouge
devienne vert et que le texte passe cliqu . Pour cela, il sut de modier le template
de ltat Pressed de notre contrle. . . Reprenons donc notre bouton :
1 <Button x:Name="But" Content="Cliquez -moi !" Style="{
StaticResource ButtonStyle1}" />
et modions ses templates lintrieur de son style :
1 <ControlTemplate TargetType="Button">
2 <Grid Background="Transparent">
3 <VisualStateManager.VisualStateGroups >
4 <VisualStateGroup x:Name="CommonStates">
5 <VisualState x:Name="Normal"/>
6 <VisualState x:Name="MouseOver"/>
7 <VisualState x:Name="Pressed">
8 <Storyboard >
9 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="Source"
Storyboard.TargetName="MonRond">
255
CHAPITRE 18. GESTION DES TATS VISUELS
10 <DiscreteObjectKeyFrame KeyTime="0"
Value="vert.png"/>
11 </ObjectAnimationUsingKeyFrames >
12 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="Text"
Storyboard.TargetName="MonTexte">
13 <DiscreteObjectKeyFrame KeyTime="0"
Value="Cliqu :)"/>
14 </ObjectAnimationUsingKeyFrames >
15 </Storyboard >
16 </VisualState >
17 <VisualState x:Name="Disabled">
18 <Storyboard >
19 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="
Visibility" Storyboard.TargetName="
MonRond">
20 <DiscreteObjectKeyFrame KeyTime="0"
Value="Collapsed"/>
21 </ObjectAnimationUsingKeyFrames >
22 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="Text"
Storyboard.TargetName="MonTexte">
23 <DiscreteObjectKeyFrame KeyTime="0"
Value="Pas touche ..."/>
24 </ObjectAnimationUsingKeyFrames >
25 </Storyboard >
26 </VisualState >
27 </VisualStateGroup >
28 </VisualStateManager.VisualStateGroups >
29 <Border x:Name="ButtonBackground" BorderBrush="{
TemplateBinding BorderBrush}" BorderThickness="{
TemplateBinding BorderThickness}" Background="{
TemplateBinding Background}" CornerRadius="0" Margin
="{StaticResource PhoneTouchTargetOverhang}">
30 <StackPanel >
31 <Image x:Name="MonRond" Source="rouge.png"
Width="100" Height="100" />
32 <TextBlock x:Name="MonTexte" Text="Cliquez -moi
!" />
33 </StackPanel >
34 </Border >
35 </Grid >
36 </ControlTemplate >
Vous pouvez voir que jai modi lapparence du contrle pour quil contienne notre
image et notre texte :
1 <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding
BorderBrush}" BorderThickness="{TemplateBinding
BorderThickness}" Background="{TemplateBinding Background}"
256
MODIFIER UN TAT
CornerRadius="0" Margin="{StaticResource
PhoneTouchTargetOverhang}">
2 <StackPanel >
3 <Image x:Name="MonRond" Source="rouge.png" Width="100"
Height="100" />
4 <TextBlock x:Name="MonTexte" Text="Cliquez -moi !" />
5 </StackPanel >
6 </Border >
Puis, dans ltat Pressed, jai anim les proprits Source de limage et Text du
TextBlock pour charger une nouvelle image et changer le texte :
1 <VisualState x:Name="Pressed">
2 <Storyboard >
3 <ObjectAnimationUsingKeyFrames Storyboard.
TargetProperty="Source" Storyboard.TargetName="
MonRond">
4 <DiscreteObjectKeyFrame KeyTime="0" Value="vert.png
"/>
5 </ObjectAnimationUsingKeyFrames >
6 <ObjectAnimationUsingKeyFrames Storyboard.
TargetProperty="Text" Storyboard.TargetName="
MonTexte">
7 <DiscreteObjectKeyFrame KeyTime="0" Value="Cliqu
:)"/>
8 </ObjectAnimationUsingKeyFrames >
9 </Storyboard >
10 </VisualState >
Bien sr, il faudra rajouter les images rouge.png et vert.png la solution. De la mme
faon, dans ltat Disabled, jai chang la visibilit de limage pour la faire disparaitre,
puis jai anim le texte pour le changer :
1 <VisualState x:Name="Disabled">
2 <Storyboard >
3 <ObjectAnimationUsingKeyFrames Storyboard.
TargetProperty="Visibility" Storyboard.TargetName="
MonRond">
4 <DiscreteObjectKeyFrame KeyTime="0" Value="
Collapsed"/>
5 </ObjectAnimationUsingKeyFrames >
6 <ObjectAnimationUsingKeyFrames Storyboard.
TargetProperty="Text" Storyboard.TargetName="
MonTexte">
7 <DiscreteObjectKeyFrame KeyTime="0" Value="Pas
touche ..."/>
8 </ObjectAnimationUsingKeyFrames >
9 </Storyboard >
10 </VisualState >
Du coup, dans mon XAML, je me retrouve avec mon bouton :
257
CHAPITRE 18. GESTION DES TATS VISUELS
1 <Button x:Name="But" Content="Cliquez -moi !" Style="{
StaticResource ButtonStyle1}" />
Qui, lorsquil est au repos, ressemble ce que vous pouvez voir sur la gure 18.7.
Figure 18.7 Etat du bouton modi au repos
Lorsquil est cliqu, il est plutt ainsi (voir la gure 18.8).
Et lorsquil est dsactiv, il est comme vous pouvez le voir la gure 18.9.
Ici, nous avons fait les modications des animations des dirents tats direc-
tement en XAML, mais il aurait t tout fait possible dutiliser Blend pour le
faire. Cest notamment plus pratique lorsquil y a des animations complexes.
Changer dtat
Bon. . . javoue ! Dans le chapitre prcdent jai trich ! Mais ne le dites personne. Pour
faire mes copies dcrans, je nai pas cherch appuyer sur la touche de copie dcran
tout en maintenant le clic sur le bouton. . . trop compliqu, je fais attention ltat. . .
de mes doigts. :- Jai donc pour loccasion chang ltat du bouton par code. Et oui,
il ny a pas que les actions de lutilisateur qui peuvent changer ltat dun contrle. Il
est trs simple de changer ltat dun contrle avec une ligne de code. On utilise pour
cela le VisualStateManager - http://msdn.microsoft.com/fr-fr/library/system.
258
CHANGER DTAT
Figure 18.8 Etat du bouton modi lorsquil est cliqu
Figure 18.9 Etat du bouton modi lorsquil est dsactiv
259
CHAPITRE 18. GESTION DES TATS VISUELS
windows.visualstatemanager(v=vs.95).aspx. Par exemple, pour passer sur ltat
Pressed, je peux utiliser :
1 VisualStateManager.GoToState(But , "Pressed", true);
Il sut de connatre le nom de ltat atteindre et le tour est jou.
Crer un nouvel tat
Et vous savez quoi ? Il est mme possible de rajouter des tats un contrle. Imaginons
par exemple que je souhaite que mon bouton puisse tre dans un tat TailleReduite
et un autre TailleNormale o vous laurez compris notre bouton pourra avoir deux
apparences direntes en fonction de son tat. Ce nouvel tat sera bien sr cumulatif
aux autres tats, comme Pressed ou Disabled. Comme nous lavons vu, il va falloir
commencer par crer un nouveau groupe dtat. Pour le rajouter, il sut de se pla-
cer lintrieur de la proprit <VisualStateManager.VisualStateGroups>. Et nous
aurons par exemple :
1 <VisualStateManager.VisualStateGroups >
2 <VisualStateGroup x:Name="TailleStates">
3 <VisualState x:Name="TailleNormale"/>
4 <VisualState x:Name="TailleReduite">
5 <Storyboard >
6 <ObjectAnimationUsingKeyFrames Storyboard.
TargetProperty="Width" Storyboard.TargetName
="ButtonBackground">
7 <DiscreteObjectKeyFrame KeyTime="0" Value="
100"/>
8 </ObjectAnimationUsingKeyFrames >
9 </Storyboard >
10 </VisualState >
11 </VisualStateGroup >
12 <VisualStateGroup x:Name="CommonStates">
13 <VisualState x:Name="Normal"/>
14 <VisualState x:Name="MouseOver"/>
15 <VisualState x:Name="Pressed">
16 ...
17 </VisualState >
18 </VisualStateGroup >
19 </VisualStateManager.VisualStateGroups >
Ici, jai simplement choisi de rduire la taille de la proprit Width du contrle Border
an de rduire la taille du bouton. Le voici la gure 18.10 donc dans un tat Pressed
et TailleReduite.
Pour obtenir cela, dans le XAML, jaurai toujours mon bouton, mais jai galement
rajout une case cocher pour pouvoir positionner ltat rduit :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0">
260
CRER UN NOUVEL TAT
Figure 18.10 Le bouton est dans ltat Pressed et TailleReduite
2 <StackPanel >
3 <Button x:Name="But" Content="Cliquez -moi !" Style="{
StaticResource ButtonStyle1}" />
4 <CheckBox Margin="0 100 0 0" Content="Taille rduite ?"
Checked="CheckBox_Checked" Unchecked="
CheckBox_Unchecked" />
5 </StackPanel >
6 </Grid >
Avec dans le code-behind :
1 private void CheckBox_Checked(object sender , RoutedEventArgs e)
2 {
3 VisualStateManager.GoToState(But , "TailleReduite", true);
4 }
5
6 private void CheckBox_Unchecked(object sender , RoutedEventArgs
e)
7 {
8 VisualStateManager.GoToState(But , "TailleNormale", true);
9 }
261
CHAPITRE 18. GESTION DES TATS VISUELS
On peut galement facilement ajouter un nouvel tat grce Blend, nous le
verrons dans la partie suivante lors de la gestion de lorientation.
En rsum
Un contrle peut possder plusieurs tats, comme un bouton qui peut tre cliqu
ou non cliqu.
chaque tat est associe une reprsentation visuelle dirente, quil est possible
de modier grce aux templates.
Il est possible de crer un nouvel tat ou un nouveau groupe dtat pour un
contrle.
On change un tat par code grce la classe VisualStateManager.
Blend peut se rvler trs utile dans la cration ou la modication dtats.
262
Chapitre 19
Le traitement des donnes
Dicult :
Gnralement, dans nos applications, nous allons avoir besoin de traiter des donnes. Des
clients, des commandes ou tout autre chose qui a toute sa place dans une ListBox ou dans
dautres contrles. Nous venons en plus de parler de modle dans le chapitre sur MVVM en
simulant un peu maladroitement un chargement de donnes, avec des donnes en dur dans
le code. Dans une application de gestion, les donnes voluent au fur et mesure. La liste
de clients sagrandit, le nombre de produits du catalogue augmente, les prix changent, etc.
Bref, nous allons avoir besoin de grer des donnes, aussi nous allons nous attarder dans
ce chapitre considrer direntes solutions pour rcuprer des donnes et les manipuler.
263
CHAPITRE 19. LE TRAITEMENT DES DONNES
HttpRequest & WebClient
Dans une application pour mobile, il y a souvent beaucoup doccasions pour rcuprer
des informations disponibles sur internet, notamment avec la prsence de plus en plus
importante du cloud. Rcuprer des donnes sur internet consiste gnralement en trois
choses :
Demander la rcupration de donnes.
Attendre la n du tlchargement.
Interprter ces donnes.
Dans nos applications Windows Phone, la rcupration de donnes est obligatoirement
asynchrone pour viter de bloquer lapplication et garder une interface fonctionnelle.
Cela veut dire quon va lancer le tlchargement et tre noti de la n par un vne-
ment. Cest ce moment-l que lon pourra interprter les donnes. Il y a plusieurs fa-
ons de faire des appels, la premire est dutiliser les classes WebClient - http://msdn.
microsoft.com/fr-fr/library/system.net.webclient.aspx et HttpWebRequest -
http://msdn.microsoft.com/fr-fr/library/system.net.httpwebrequest.aspx.
Si vous avez simplement besoin de rcuprer une chane (ou du XML brut) le plus simple
est dutiliser la classe WebClient. Par exemple, la page internet suivante - http://fr.
openclassrooms.com/uploads/fr/ftp/windows_phone/script_nico.php renvoie la
chane Bonjour tout le monde . Pour y accder, nous pouvons crire le code suivant :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6
7 WebClient client = new WebClient ();
8 client.DownloadStringCompleted +=
client_DownloadStringCompleted;
9 client.DownloadStringAsync(new Uri("http ://fr.
openclassrooms.com/uploads/fr/ftp/windows_phone/
script_nico.php"));
10 }
11
12 private void client_DownloadStringCompleted(object sender ,
DownloadStringCompletedEventArgs e)
13 {
14 if (e.Error == null)
15 {
16 string texte = e.Result;
17 MessageBox.Show(texte);
18 }
19 else
20 {
21 MessageBox.Show("Impossible de rcuprer les donn
es sur internet : " + e.Error);
22 }
264
HTTPREQUEST & WEBCLIENT
23 }
24 }
Ce qui donne le rsultat de la gure 19.1.
Figure 19.1 Achage dune donne rcupre sur internet
Le principe est de sabonner lvnement de n de tlchargement, de dclencher le
tlchargement asynchrone et de rcuprer le rsultat. Ici, il ny a pas de traitement
faire pour interprter les donnes, vu que nous souhaitons acher directement la
chane rcupre.
La mthode DownloadStringAsync fonctionne trs bien pour tout ce qui est texte
brut. Si vous voulez tlcharger des donnes binaires, vous pourrez utiliser la m-
thode OpenReadAsync. La classe WebClient est parfaite pour faire des tlchargements
simples mais elle devient vite limite lorsque nous devons faire des oprations plus
pointues sur les requtes, comme modier les enttes HTTP ou envoyer des donnes
en POST, etc. Cest l que nous allons utiliser la classe HttpWebRequest. Elle ore
un contrle plus n sur la requte web. Nous allons illustrer ceci en faisant une re-
qute sur le formulaire PHP du cours PHP du site OpenClassrooms, disponible cet
emplacement : http://fr.openclassrooms.com/uploads/formulaire.php
Le principe est denvoyer des donnes en POST, notamment la donne : "prenom=Nicolas".
Le code est le suivant :
1 <TextBlock x:Name="Resultat" TextWrapping="Wrap"/>
Avec le code behind qui suit :
265
CHAPITRE 19. LE TRAITEMENT DES DONNES
1 public MainPage ()
2 {
3 InitializeComponent ();
4
5 HttpWebRequest requete = (HttpWebRequest)HttpWebRequest.
Create("http ://fr.openclassrooms.com/uploads/fr/ftp/
mateo21/php/form_text/formulaire.php");
6 requete.Method = "POST";
7 requete.ContentType = "application/x-www -form -urlencoded";
8
9 requete.BeginGetRequestStream(DebutReponse , requete);
10 }
11
12 private void DebutReponse(IAsyncResult resultatAsynchrone)
13 {
14 HttpWebRequest requete = (HttpWebRequest)resultatAsynchrone
.AsyncState;
15 Stream postStream = requete.EndGetRequestStream(
resultatAsynchrone);
16 string donneesAEnvoyer = "prenom=Nicolas";
17
18 byte[] tableau = Encoding.UTF8.GetBytes(donneesAEnvoyer);
19 postStream.Write(tableau , 0, donneesAEnvoyer.Length);
20 postStream.Close ();
21 requete.BeginGetResponse(FinReponse , requete);
22 }
23
24 private void FinReponse(IAsyncResult resultatAsynchrone)
25 {
26 HttpWebRequest requete = (HttpWebRequest)resultatAsynchrone
.AsyncState;
27 WebResponse webResponse = requete.EndGetResponse(
resultatAsynchrone);
28 Stream stream = webResponse.GetResponseStream ();
29
30 StreamReader streamReader = new StreamReader(stream);
31 string reponse = streamReader.ReadToEnd ();
32 stream.Close();
33 streamReader.Close();
34 webResponse.Close ();
35
36 Dispatcher.BeginInvoke (() => Resultat.Text = reponse);
37 }
Stream et StreamReader sont dans lespace de nom System.IO. Encoding
est dans lespace de nom System.Text.
266
HTTPREQUEST & WEBCLIENT
Ce code peut paratre un peu compliqu, mais cest toujours le mme pour faire ce genre
de requte. On commence par crer la requte en lui indiquant la mthode POST.
Ensuite dans la premire mthode on crit les donnes envoyer dans le ux et on
invoque la requte asynchrone. Dans la deuxime mthode, on rcupre le retour (voir
la gure 19.2).
Figure 19.2 Envoi dun formulaire POST une page PHP et achage du retour
Ici, le retour est du HTML, ce qui est normal vu que ce formulaire a t prvu pour
une page web. Il aurait pu tre judicieux dinterprter le rsultat, en retirant les balises
HTML par exemple. . .
Attention, un tlchargement fait avec HttpWebRequest sexcute sur un
thread en arrire-plan, cela veut dire que si nous voulons mettre jour linter-
face, nous aurons besoin dutiliser le dispatcher pour re-basculer sur le thread
de linterface.
Cest ce que nous avons fait ici avec :
1 Dispatcher.BeginInvoke (() => resultat.Text = reponse);
Ce qui permet de mettre jour la proprit Text du TextBlock.
267
CHAPITRE 19. LE TRAITEMENT DES DONNES
Remarquons que si nous utilisons la classe WebClient dans un thread dirent
de celui permettant de mettre jour linterface, le rsultat sera aussi dans un
thread dirent, il faudra donc utiliser un dispatcher dans ce cas aussi. Nous
reviendrons sur ces notions de Thread et de Dispatcher dans une prochaine
partie.
Nous pouvons galement consommer facilement des services web avec une application
Windows Phone. Un service web est une espce dapplication web qui rpond des
requtes permettant dappeler une mthode avec des paramtres et de recevoir en
rponse le retour de la mthode.
Mais comment appeler un service web ? Quelle adresse ? Comment connait-
on le nom des mthodes appeler ? Comment indiquer les paramtres et les
valeurs que lon souhaite passer ?
Eh oui, il faut une syntaxe dnie, sinon on peut faire ce que lon veut. Cest l quinter-
viennent les organismes de standardisation. Ils ont dni plusieurs normes permettant
de dcrire le format des changes. Cest le cas par exemple du protocole SOAP - http:
//fr.wikipedia.org/wiki/SOAP qui est bas sur du XML. Il est associ au WSDL -
http://fr.wikipedia.org/wiki/Web_Services_Description_Language qui permet
de dcrire le service web. Nous avons notre disposition galement les services web de
type REST - http://fr.wikipedia.org/wiki/Representational_State_Transfer
qui exposent les fonctionnalits comme des URL.
Pour illustrer ce fonctionnement, nous allons utiliser un service web gratuit qui permet
de transformer des tempratures, par exemple de degrs Celsuis en degr Fahrenheit.
Ce service web est disponible ladresse suivante : http://www.webservicex.net/
ConvertTemperature.asmx, et plus prcisment, sa description est accessible sur http:
//www.webservicex.net/ConvertTemperature.asmx?WSDL.
Nous devons ensuite ajouter une rfrence web, pour cela faites un clic droit sur les
rfrences et ajoutez une rfrence de service, comme indiqu sur la gure 19.3.
Figure 19.3 Ajout dune rfrence de service
Ensuite, il faut saisir ladresse du WSDL http://www.webservicex.net/ConvertTemperature.
asmx?WSDL et cliquer sur Aller (voir la gure 19.4).
268
HTTPREQUEST & WEBCLIENT
Figure 19.4 Fentre dajout de la rfrence de service
Remarquez que je laisse lespace de noms la valeur ServiceReference1, mais nhsitez
pas le changer si besoin. Vous aurez alors besoin dinclure cet espace de nom an
de pouvoir appeler le service web. Une fois valid, Visual Studio nous gnre un proxy
en se basant sur le WSDL du service web. Ce proxy va soccuper dencapsuler tout la
logique dappel du web service pour nous simplier la tche.
Remarque : un proxy est une ou plusieurs classes qui se placent entre deux
autres pour faciliter ou surveiller leurs changes. Le proxy est en fait un
patron de conception que lon peut dcrire assez facilement avec un exemple
du monde rel, dans le cas o deux personnes qui ne parlent pas la mme
langue vont recourir un interprte pour les faire communiquer entre elles.
Cet interprte, cest le proxy.
Cela veut dire concrtement que Visual Studio travaille pour nous. partir de lURL
de nos services web, il va analyser le type des donnes qui doivent tre passes en
paramtres ainsi que les donnes que lon obtient en retour et gnrer des classes qui
leurs correspondent. De mme, il gnre tout une classe qui encapsule les dirents
appels aux direntes mthodes du service web. Cest cette classe que lon appelle un
proxy car elle sert de point dentre pour tous les appels des mthodes du service web.
Toutes ces classes ont t cres dans lespace de nom que nous avons indiqu.
Nous pourrons alors simplement lutiliser comme ceci :
269
CHAPITRE 19. LE TRAITEMENT DES DONNES
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6
7 TemperatureService.ConvertTemperatureSoapClient client
= new TemperatureService.
ConvertTemperatureSoapClient ();
8 client.ConvertTempCompleted +=
client_ConvertTempCompleted;
9 client.ConvertTempAsync(25, TemperatureService.
TemperatureUnit.degreeCelsius , TemperatureService.
TemperatureUnit.degreeFahrenheit);
10 }
11
12 private void client_ConvertTempCompleted(object sender ,
TemperatureService.ConvertTempCompletedEventArgs e)
13 {
14 if (e.Error == null)
15 {
16 MessageBox.Show(e.Result.ToString ());
17 }
18 }
19 }
Ce qui donnera la gure 19.5.
Et voil, 25 degr Celsuis font 77 degr Fahrenheit !
Linq-To-Json
Parlons prsent un peu des services REST. Je ne prsenterai pas comment faire
un appel REST parce que vous savez dj le faire, dans la mesure o il sagit dune
simple requte HTTP. Par contre, ce quil est intressant dtudier ce sont les solu-
tions pour interprter le rsultat dun appel REST. De plus en plus, les services REST
renvoient du JSON car cest un format de description de donnes beaucoup moins
verbeux que le XML. .NET sait interprter le JSON mais malheureusement lassem-
bly Silverlight System.Json.dll nest pas porte pour Windows Phone. Nous pou-
vons quand mme lutiliser mais cest nos risques et prils. Elle a t installe avec
le SDK de Silverlight, chez moi cet emplacement : C:\Program Files\Microsoft
SDKs\Silverlight\v4.0\Libraries\Client\System.Json.dll.
Cette assemby nous permet de faire du Linq To Json et davoir accs aux objets JsonOb-
ject - http://msdn.microsoft.com/fr-fr/library/system.json.jsonobject(v=vs.
95).aspx et JsonArray - http://msdn.microsoft.com/fr-fr/library/system.json.
jsonarray(v=vs.95).aspx. Lorsque vous allez rfrencer cette assembly, vous aurez
le message davertissement prsent dans la gure 19.6 :
270
LINQ-TO-JSON
Figure 19.5 Rsultat de la conversion degr Celsuis en degr Fahrenheit
Figure 19.6 Fentre davertissement lors de la rfrence System.Json.dll
271
CHAPITRE 19. LE TRAITEMENT DES DONNES
Vous pouvez cliquer sur oui pour continuer. Nous allons illustrer le fonctionnement de
ces objets travers un appel REST qui consistera raliser une recherche avec le moteur
de recherche Google. Par exemple, si je veux chercher la chane openclassrooms sur
Google, je pourrai utiliser le service web REST suivant : http://ajax.googleapis.
com/ajax/services/search/web?v=1.0&q=openclassrooms Qui me renverra quelque
chose comme :
1 {
2 "responseData":{
3 "results":[
4 {
5 "GsearchResultClass":"GwebSearch",
6 "unescapedUrl":"http ://fr.openclassrooms.com/",
7 "url":"http ://fr.openclassrooms.com/",
8 "visibleUrl":"fr.openclassrooms.com",
9 "cacheUrl":"http ://www.google.com/search?q\
u003dcache:Wy40FwwsrHMJ:fr.openclassrooms.com",
10 "title":"\u003cb\u003eOpenClassrooms\u003c/b\u003e ,
Le Site du Zro - Les cours les plus ouverts du
Web",
11 [...]
12 },
13 {
14 "GsearchResultClass":"GwebSearch",
15 "unescapedUrl":"http ://fr.openclassrooms.com/
informatique/cours",
16 "url":"http ://fr.openclassrooms.com/informatique/
cours",
17 [...]
18 },
19 [...]
20 ],
21 "cursor":{
22 "resultCount":"119 000",
23 "pages":[
24 {
25 "start":"0",
26 "label":1
27 },
28 [...]
29 ],
30 "estimatedResultCount":"119000",
31 "currentPageIndex":0,
32 [...]
33 "searchResultTime":"0,21"
34 }
35 },
36 "responseDetails":null ,
37 "responseStatus":200
38 }
272
LINQ-TO-JSON
Le format JSON est relativement comprhensible lil nu, mais sa lecture fait un peu
mal aux yeux. Nous pouvons quand mme dcrypter que le rsultat contient une srie de
valeurs correspondant la recherche. Construisons une mini application qui eectuera
le tlchargement des donnes, vous savez faire, on utilise la classe WebClient :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6 WebClient client = new WebClient ();
7 client.DownloadStringCompleted +=
client_DownloadStringCompleted;
8 client.DownloadStringAsync(new Uri("http :// ajax.
googleapis.com/ajax/services/search/web?v=1.0&q=
openclassrooms"));
9 }
10
11 private void client_DownloadStringCompleted(object sender ,
DownloadStringCompletedEventArgs e)
12 {
13 if (e.Error == null)
14 {
15 JsonObject json = (JsonObject)JsonObject.Parse(e.
Result);
16 }
17 }
18 }
Nous allons pouvoir obtenir un objet JsonObject grce la mthode statique Parse.
Le JsonObject est en fait une espce de dictionnaire o nous pouvons accder des
valeurs partir de leur cl. Par exemple, vous pouvez voir que le json rcupr possde
la proprit responseData qui contient une sous proprit cursor, contenant elle-
mme la proprit resultCount fournissant le nombre de rsultats de la requte. Nous
pouvons y accder de cette faon :
1 JsonObject json = (JsonObject)JsonObject.Parse(e.Result);
2 string nombreResultat = json["responseData"]["cursor"]["
resultCount"];
Dans ce cas, chaque JsonObject renvoie un nouvel JsonObject qui est lui-mme tou-
jours cette espce de dictionnaire. En eet, responseData, cursor et resultCount
sont des proprits simples. Ce nest pas le cas par contre de la proprit results qui
est un tableau. On utilisera alors un JsonArray pour pouvoir le parcourir. Et cest l
que Linq To Json rentre en action, nous allons pouvoir requter sur ce tableau. Par
exemple :
1 List <string > resultats = new List <string >();
2 JsonObject json = (JsonObject)JsonObject.Parse(e.Result);
3 string nombreResultat = json["responseData"]["cursor"]["
resultCount"];
273
CHAPITRE 19. LE TRAITEMENT DES DONNES
4 var listeResultat =
5 from resultat in (JsonArray)(json["responseData"]["
results"])
6 where (( string)resultat["content"]).IndexOf("cours",
StringComparison.CurrentCultureIgnoreCase) >= 0
7 select resultat;
8
9 foreach (var resultat in listeResultat)
10 {
11 resultats.Add(resultat["titleNoFormatting"]);
12 }
Ici, je rcupre les titres de chaque rsultats dont le contenu contient le mot cours, sans
faire attention la casse. Ainsi, avec une ListBox :
1 <ListBox x:Name="MaListeBox" />
Je pourrai les acher :
1 MaListeBox.ItemsSource = resultats;
Et obtenir le rsultat illustr dans la gure 19.7.
Figure 19.7 Rsultat de la recherche google dans la ListBox
Vous aurez remarqu que traiter du JSON de cette faon nest pas formidable. Cest plu-
tt lourd mettre en place. Heureusement, il y a une autre solution plus intressante et
qui na pas besoin daller chercher lassembly System.Json.dll. Il sagit de transformer
274
LINQ-TO-JSON
le JSON obtenu en objet. Cela peut se faire avec le DataContractJsonSerializer - http:
//msdn.microsoft.com/fr-fr/library/system.runtime.serialization.json.datacontractjsonserializer.
aspx du framework.NET, qui se trouve dans lassembly System.Servicemodel.Web.
Celui-ci soure cependant de quelques limitations. On pourra le remplacer avec la
bibliothque open-source JSON.NET que lon peut tlcharger sur codeplex - http:
//json.codeplex.com/. Tlchargez la dernire version et rfrencez lassembly dans
votre projet, la version Windows Phone bien sr ou alors utilisez NuGet (voir gure
19.8).
Figure 19.8 Installation de Json.NET via NuGet
La premire chose faire est de regarder la rponse renvoye car nous allons avoir besoin
de construire un ou plusieurs objets mappant ce rsultat. Nous pouvons les construire
la main ou bien proter du fait que certaines personnes ont ralis des outils pour
nous simplier la vie. Allons par exemple sur le site - http://json2csharp.com/, o
nous pouvons copier le rsultat de la requte. Ce site nous gnre les classes suivantes :
1 public class Page
2 {
3 public int label { get; set; }
4 public string start { get; set; }
5 }
6
7 public class Cursor
8 {
9 public int currentPageIndex { get; set; }
10 public string estimatedResultCount { get; set; }
11 public string moreResultsUrl { get; set; }
275
CHAPITRE 19. LE TRAITEMENT DES DONNES
12 public List <Page > pages { get; set; }
13 public string resultCount { get; set; }
14 public string searchResultTime { get; set; }
15 }
16
17 public class Result
18 {
19 public string GsearchResultClass { get; set; }
20 public string cacheUrl { get; set; }
21 public string content { get; set; }
22 public string title { get; set; }
23 public string titleNoFormatting { get; set; }
24 public string unescapedUrl { get; set; }
25 public string url { get; set; }
26 public string visibleUrl { get; set; }
27 }
28
29 public class ResponseData
30 {
31 public Cursor cursor { get; set; }
32 public List <Result > results { get; set; }
33 }
34
35 public class RootObject
36 {
37 public ResponseData responseData { get; set; }
38 public object responseDetails { get; set; }
39 public int responseStatus { get; set; }
40 }
que nous pouvons inclure dans notre projet. Ces classes reprsentent exactement le
rsultat de la requte sous la forme de plusieurs objets. Il ne reste plus qu faire un
appel web comme on la vu :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 WebClient client = new WebClient ();
5 client.DownloadStringCompleted +=
client_DownloadStringCompleted;
6 client.DownloadStringAsync(new Uri("http :// ajax.googleapis.
com/ajax/services/search/web?v=1.0&q=openclassrooms"));
7 }
8
9 private void client_DownloadStringCompleted(object sender ,
DownloadStringCompletedEventArgs e)
10 {
11 if (e.Error == null)
12 {
13 RootObject resultat = JsonConvert.DeserializeObject <
RootObject >(e.Result);
276
LA BIBLIOTHQUE DE SYNDICATION
14 MaListeBox.ItemsSource = resultat.responseData.results.
Select(r => r.titleNoFormatting);
15 }
16 }
et utiliser la classe JsonConvert pour dsrialiser le JSON rcupr et le mettre dans
les classes qui ont t gnres.
Srialis signie que linstance dun objet subit une transformation an
de pouvoir tre stocke au format texte, ou binaire. Inversement, la dsriali-
sation permet de reconstruire une instance dun objet partir de ce texte ou
de binaire.
Ensuite, jextraie uniquement le titre pour lacher dans ma ListBox. Et le tour est
jou ! Grce la bibliothque JSON.NET, nous pouvons facilement interprter des
donnes JSON venant dinternet an dtre ecace dans nos applications. Remarquez
que maintenant que nous avons des objets, nous pouvons utiliser les extensions Linq
pour requter sur les informations issues du JSON.
La bibliothque de Syndication
Maintenant que nous savons rcuprer des donnes depuis internet, pourquoi ne pas
essayer den faire quelque chose dun peu intressant ? Comme un lecteur de ux RSS
par exemple. . . Vous connaissez sans doute tous le RSS - http://fr.wikipedia.org/
wiki/RSS, cest ce format qui nous permet de nous abonner nos blogs favoris an
dtre avertis des nouveaux articles publis. Le ux RSS est produit sous forme de XML
standardis, contenant des informations sur le nom du site, les billets qui le composent,
le titre du billet, la description, etc. Le site OpenClassrooms possde bien videmment
des ux RSS, comme le ux dactualit de son blog disponible cet emplacement :
http://www.simple-it.fr/blog/feed/. Si vous naviguez sur ce lien, vous pouvez
facilement voir le titre du site, la description, ainsi que les direntes actualits ; et
tout a au format XML.
Prenons un autre site pour lexemple, le blog de lquipe Windows Phone. Le ux
RSS est accessible via cette page : http://blogs.windows.com/windows_phone/b/
windowsphone/rss.aspx.
Vous savez dj rcuprer du XML grce la classe WebClient. Je vais en proter
pour vous communiquer une petite astuce dont je nai pas parl dans les chapitres
prcdents. Il est possible de fournir un objet de contexte la requte de tlchargement
et ainsi pouvoir utiliser la mme mthode pour lvnement de n de tlchargement
et identier ainsi direntes requtes. Il sut de lui passer en paramtre de lappel la
mthode DownloadStringAsync. Cet objet de contexte sera rcupr dans lvnement
de n de tlchargement, dans la proprit UserState de lobjet rsultat :
1 public partial class MainPage : PhoneApplicationPage
2 {
277
CHAPITRE 19. LE TRAITEMENT DES DONNES
3 private WebClient client;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8
9 client = new WebClient ();
10 client.DownloadStringCompleted +=
client_DownloadStringCompleted;
11 client.DownloadStringAsync(new Uri("http :// www.simple -
it.fr/blog/feed/"), "OC");
12 }
13
14 private void client_DownloadStringCompleted(object sender ,
DownloadStringCompletedEventArgs e)
15 {
16 if (e.Error == null)
17 {
18 if (( string)e.UserState == "OC")
19 {
20 // ce sont les donnes venant du flux du blog
OpenClassrooms
21
22 // lancer le tlchargement suivant
23 client.DownloadStringAsync(new Uri("http ://
windowsteamblog.com/windows_phone/b/
windowsphone/rss.aspx"), "WP");
24 }
25 if (( string)e.UserState == "WP")
26 {
27 // ce sont les donnes venant du flux blog de l
'quipe windows phone
28 }
29 }
30 }
31 }
Ceci nous permettra dutiliser la mme mthode pour lvnement de n de tlcharge-
ment. Nous avons maintenant besoin dinterprter les donnes du ux XML retourn.
tant donn que les ux RSS sont standards, il existe une bibliothque Silverlight qui
permet de travailler avec ce genre de ux. Cest la bibliothque System.ServiceModel.Syndication.dll.
Encore une fois, cette assembly na pas t crite pour Windows Phone, mais elle est
quand mme utilisable avec nos applications Windows Phone. Pour lutiliser, nous
devons ajouter une rfrence celle-ci. Elle se trouve dans le rpertoire suivant :
C:\Program Files\Microsoft SDKs\Silverlight\v4.0\Libraries\Client.
Comme pour System.Json.dll, vous aurez une boite de dialogue davertissement o
vous pouvez cliquer sur Oui (voir la gure 19.9).
Nous allons donc pouvoir charger lobjet de Syndication partir du rsultat, cet ob-
278
LA BIBLIOTHQUE DE SYNDICATION
Figure 19.9 Fentre davertissement lors de la rfrence Sys-
tem.ServiceModel.Syndication.dll
jet sera du type SyndicationFeed - http://msdn.microsoft.com/fr-fr/library/
system.servicemodel.syndication.syndicationfeed(v=vs.95).aspx. Pour com-
mencer, je me rajoute une variable prive :
1 private List <SyndicationFeed > listeFlux;
que jinitialise dans le constructeur :
1 listeFlux = new List <SyndicationFeed >();
Noubliez pas de rajouter le using qui va bien :
1 using System.ServiceModel.Syndication;
puis je consolide ma liste partir du retour de lappel web :
1 private void client_DownloadStringCompleted(object sender ,
DownloadStringCompletedEventArgs e)
2 {
3 if (e.Error == null)
4 {
5 if (( string)e.UserState == "OC")
6 {
7 // ce sont les donnes venant du flux du blog
OpenClassrooms
8 AjouteFlux(e.Result);
9
10 // lancer le tlchargement suivant
11 client.DownloadStringAsync(new Uri("http ://
windowsteamblog.com/windows_phone/b/windowsphone
/rss.aspx"), "WP");
12 }
13 if (( string)e.UserState == "WP")
14 {
15 // ce sont les donnes venant du flux blog de l'
quipe windows phone
16 AjouteFlux(e.Result);
17 }
279
CHAPITRE 19. LE TRAITEMENT DES DONNES
18 }
19 }
20
21 private void AjouteFlux(string flux)
22 {
23 StringReader stringReader = new StringReader(flux);
24 XmlReader xmlReader = XmlReader.Create(stringReader);
25 SyndicationFeed feed = SyndicationFeed.Load(xmlReader);
26 listeFlux.Add(feed);
27 }
Pour charger un ux de syndication, il sut dutiliser la mthode Load de la classe
SyndicationFeed en lui passant un XmlReader, prsent dans lespace de nom System.Xml.
Lobjet StringReader permet de lire un ux et de lexploiter en tant que
conteur de caractres. De mme, lobjet XmlReader permet de traiter ce ux
sous la forme de donnes XML.
Et voil, nous avons cr une liste dobjet SyndicationFeed qui possde les lments du
ux RSS du blog OpenClassrooms ainsi que ceux du blog de lquipe Windows Phone.
Chaque objet SyndicationFeed contient une liste de billets, sous la forme dobjets Syn-
dicationItem - http://msdn.microsoft.com/fr-fr/library/system.servicemodel.
syndication.syndicationitem(v=vs.95).aspx. Par exemple, la date de publication
est accessible via la proprit PublishDate dun SyndicationItem. Le titre du billet
est accessible via la proprit Title.Text. . .
Nous pourrons par exemple acher le titre de chaque post, ainsi que sa date dans une
ListBox :
1 <ListBox x:Name="LaListeBox">
2 <ListBox.ItemTemplate >
3 <DataTemplate >
4 <StackPanel Orientation="Horizontal">
5 <TextBlock Text="{Binding PublishDate}" />
6 <TextBlock Text="{Binding Title.Text}" />
7 </StackPanel >
8 </DataTemplate >
9 </ListBox.ItemTemplate >
10 </ListBox >
Il nous faudra lier la proprit ItemsSource de la ListBox , par exemple une ObservableCollection
que nous construisons une fois le dernier ux reu, et qui sera trie par ordre de date
de publication de la plus rcente la plus ancienne :
1 if (( string)e.UserState == "WP")
2 {
3 // ce sont les donnes venant du flux blog de l'quipe
windows phone
4 AjouteFlux(e.Result);
5 ObservableCollection <SyndicationItem > listeBillets = new
ObservableCollection <SyndicationItem >();
280
ASYNCHRONISME AVANC
6 foreach (SyndicationFeed flux in listeFlux)
7 {
8 foreach (SyndicationItem billet in flux.Items)
9 {
10 listeBillets.Add(billet);
11 }
12 }
13 LaListeBox.ItemsSource = listeBillets.OrderByDescending(
billet => billet.PublishDate);
14 }
Ce qui donnera le rsultat prsent dans la gure 19.10.
Figure 19.10 Achage du ux RSS dans la ListBox
La prsentation laisse dsirer, mais cest fait exprs. Nous en restons l pour linstant,
mais ne vous inquitez pas, vous allez y revenir bientt.
Asynchronisme avanc
Bon, cest trs bien les mthodes asynchrones, mais cest une gymnastique un peu
complique. On sabonne un vnement de n de tlchargement puis on dmarre
le tlchargement et quand le tlchargement est termin, on exploite le rsultat dans
une autre mthode perdant au passage le contexte de lappel. Alors oui. . . il y a des
281
CHAPITRE 19. LE TRAITEMENT DES DONNES
astuces, comme celle que nous venons de voir. . . mais je vous dis pas les nuds au
cerveau lorsquil y a des appels dans tous les sens !
Bonne nouvelle, avec Windows Phone 8 il est possible de se simplier grandement
lasynchronisme. En fait, cest surtout le framework 4.5 quil faut remercier, mais peu
importe, si vous crez une application pour Windows Phone 8, vous pourrez bncier
de 2 formidables nouveaux petits mot-cls : async et await.
Certaines API de Windows Phone 8 ont t rcrites pour tirer parti de ces nouveaux
mots cls, cest le cas par exemple de certaines oprations sur les chiers qui peuvent
prendre du temps et que nous allons voir juste aprs. a aurait galement pu tre le
cas pour les classes daccs Internet comme WebClient et HttpWebRequest, mais
malheureusement celles-ci nont pas t rcrites. Heureusement, nous pouvons crire
un wrapper pour bncier de ces lments avec la classe WebClient. Ceci va nous
permettre de nous simplier grandement lasynchronisme.
Je ne vais pas rentrer dans le dtail des Task car il ne sagit pas dun cours
sur le C# et au fond ce nest pas vraiment ce qui nous intresse ici.
Ce qui va nous intresser cest la construction suivante, que nous avons vue au tout
dbut de ce chapitre :
1 public MainPage ()
2 {
3 InitializeComponent ();
4
5 WebClient client = new WebClient ();
6 client.DownloadStringCompleted +=
client_DownloadStringCompleted;
7 client.DownloadStringAsync(new Uri("http ://fr.
openclassrooms.com/uploads/fr/ftp/windows_phone/
script_nico.php"));
8 }
9
10 private void client_DownloadStringCompleted(object sender ,
DownloadStringCompletedEventArgs e)
11 {
12 if (e.Error == null)
13 {
14 string texte = e.Result;
15 MessageBox.Show(texte);
16 }
17 else
18 {
19 MessageBox.Show("Impossible de rcuprer les donnes
sur internet : " + e.Error);
20 }
21 }
282
ASYNCHRONISME AVANC
Commenons par utiliser la classe TaskCompletionSource - http://msdn.microsoft.
com/fr-fr/library/vstudio/dd449174.aspx dans une mthode dextension :
1 public static class Extensions
2 {
3 public static Task <string > DownloadStringTaskAsync(this
WebClient webClient , Uri uri)
4 {
5 TaskCompletionSource <string > taskCompletionSource = new
TaskCompletionSource <string >();
6 DownloadStringCompletedEventHandler
downloadCompletedHandler = null;
7 downloadCompletedHandler = (s, e) =>
8 {
9 webClient.DownloadStringCompleted -=
downloadCompletedHandler;
10 if (e.Error != null)
11 taskCompletionSource.TrySetException(e.Error);
12 else
13 taskCompletionSource.TrySetResult(e.Result);
14 };
15
16 webClient.DownloadStringCompleted +=
downloadCompletedHandler;
17 webClient.DownloadStringAsync(uri);
18
19 return taskCompletionSource.Task;
20 }
21 }
Le principe est dencapsuler lappel DownloadStringAsync et de renvoyer un objet
de type Task<string>, string tant le type de ce que lon rcupre en rsultat de
lappel. Ainsi, nous allons pouvoir remplacer lappel du dbut par :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 LanceTelechargementAsync ();
5 }
6
7 private async void LanceTelechargementAsync ()
8 {
9 WebClient client = new WebClient ();
10 string texte = await client.DownloadStringTaskAsync(new Uri
("http ://fr.openclassrooms.com/uploads/fr/ftp/
windows_phone/script_nico.php"));
11 MessageBox.Show(texte);
12 }
La mthode LanceTelechargementAsync doit possder le mot-cl async avant son
type de retour pour indiquer quelle est asynchrone et doit galement par conven-
283
CHAPITRE 19. LE TRAITEMENT DES DONNES
tion avoir son nom qui se termine par Async. Nous appelons la mthode dextension
DownloadStringTaskAsync et nous attendons son rsultat de manire asynchrone grce
au mot-cl await. Pas de mthode appele une fois le tlchargement termin. . . Juste
un mot-cl qui nous permet dattendre le rsultat de manire asynchrone.
Plutt simpli comme construction, non ?
Allez, pour le plaisir, on se simplie le tlchargement des ux RSS que lon a fait juste
au dessus ? Gardons toujours la mme classe dextension et crivons dsormais :
1 public MainPage ()
2 {
3 InitializeComponent ();
4
5 LanceLeTelechargementAsync ();
6 }
7
8 private async void LanceLeTelechargementAsync ()
9 {
10 listeFlux = new List <SyndicationFeed >();
11
12 client = new WebClient ();
13 string rss = await client.DownloadStringTaskAsync(new Uri("
http ://www.simple -it.fr/blog/feed/"));
14 AjouteFlux(rss);
15 rss = await client.DownloadStringTaskAsync(new Uri("http ://
windowsteamblog.com/windows_phone/b/windowsphone/rss.
aspx"));
16 AjouteFlux(rss);
17
18 ObservableCollection <SyndicationItem > listeBillets = new
ObservableCollection <SyndicationItem >();
19 foreach (SyndicationFeed flux in listeFlux)
20 {
21 foreach (SyndicationItem billet in flux.Items)
22 {
23 listeBillets.Add(billet);
24 }
25 }
26 LaListeBox.ItemsSource = listeBillets.OrderByDescending(
billet => billet.PublishDate);
27 }
Cest quand mme bien plus clair !
Il ny a plus de traitement derreur dans la construction prcdente. Vous
pourrez alors encadrer lappel dans un try/catch.
284
LE RPERTOIRE LOCAL
Le rpertoire local
Il nest pas toujours possible daccder internet pour rcuprer des infos ou les mettre
jour. Nous avons encore notre disposition un emplacement pour faire persister de
linformation : lintrieur du tlphone.
On appelle cet emplacement le rpertoire local (local folder en anglais ou anciennement
isolated storage) dans la mesure o nous navons pas accs directement au systme
de chiers, mais plutt un emplacement mmoire isol dont nous pouvons ignorer
le fonctionnement. Tout ce quil faut savoir cest quil est possible dy stocker des
informations, comme du texte mais aussi des objets srialiss.
Il y a deux grandes faons dutiliser le rpertoire local. La plus simple est dutiliser le
dictionnaire ApplicationSettings. On peut y ranger des objets qui seront associs
une chane de caractres. Par exemple, en imaginant que lon cre une application
o lon demande le nom de notre utilisateur, il pourra tre judicieux dviter de le
redemander chaque ouverture de lapplication. . . Pour cela, nous pouvons le faire
persister dans le rpertoire local. On utilisera alors :
1 IsolatedStorageSettings.ApplicationSettings["prenom"] = "
Nicolas";
Nb : pour utiliser la classe IsolatedStorageSettings, nous devons inclure :
1 using System.IO.IsolatedStorage;
Jassocie ici la chane de caractres prenom la chane de caractres Nicolas .
Au prochain dmarrage de lapplication, on pourra vrier si le prnom existe dj en
tentant daccder sa cl prenom . Sil y a quelque chose dassoci cette cl, on
pourra le rcuprer pour viter de demander re-saisir le prnom de lutilisateur :
1 if (IsolatedStorageSettings.ApplicationSettings.Contains("
prenom"))
2 prenom = (string)IsolatedStorageSettings.
ApplicationSettings["prenom"];
Nous pouvons mettre des objets complexes dans le rpertoire local, pas seulement des
chanes de caractres :
1 public class Utilisateur
2 {
3 public int Age { get; set; }
4 public string Prenom { get; set; }
5 }
6
7 Utilisateur nicolas = new Utilisateur { Age = 30, Prenom = "
Nicolas" };
8 IsolatedStorageSettings.ApplicationSettings["utilisateur"] =
nicolas;
Et de la mme faon, on pourra rcuprer cette valeur trs facilement :
285
CHAPITRE 19. LE TRAITEMENT DES DONNES
1 if (IsolatedStorageSettings.ApplicationSettings.Contains("
utilisateur"))
2 nicolas = (Utilisateur)IsolatedStorageSettings.
ApplicationSettings["utilisateur"];
Attention, le rpertoire local fonctionne trs bien avec lmulateur la seule
condition de ne pas fermer brutalement votre application, en arrtant le dbo-
gueur par exemple, en fermant lmulateur ou en ayant une exception. Pour
que le rpertoire local persiste dune utilisation lautre, il faut que vous
conserviez lmulateur ouvert et que vous terminiez lapplication en cliquant
sur le bouton retour, jusqu ce quil ny ait plus rien dans la pile des pages
et que lapplication se termine. Sinon, vous devrez appeler la mthode de
sauvegarde explicite suivante :
1 IsolatedStorageSettings.ApplicationSettings.Save();
Le stockage dobjets dans le rpertoire local est quand mme trs pratique. Vous vous
servirez trs souvent de ce fonctionnement simple et ecace. Parfois vous aurez peut-
tre besoin dun peu plus de contrle sur ce que vous voulez stocker. ce moment-l,
on peut se servir du rpertoire local comme dun ux classique, comme lorsque lon
souhaite enregistrer des donnes dans un chier.
Regardons lenregistrement :
1 using (IsolatedStorageFileStream stream = new
IsolatedStorageFileStream("sauvegarde.txt", FileMode.Create ,
IsolatedStorageFile.GetUserStoreForApplication ()))
2 {
3 using (StreamWriter writer = new StreamWriter(stream))
4 {
5 writer.WriteLine(30);
6 writer.WriteLine("Nicolas");
7 }
8 }
Puis la lecture :
1 using (IsolatedStorageFileStream stream = new
IsolatedStorageFileStream("sauvegarde.txt", FileMode.Open ,
IsolatedStorageFile.GetUserStoreForApplication ()))
2 {
3 using (StreamReader reader = new StreamReader(stream))
4 {
5 int age = Convert.ToInt32(reader.ReadLine ());
6 string prenom = reader.ReadLine ();
7 }
8 }
Cela ressemble beaucoup des oprations dcriture et de lecture dans un chier clas-
sique. . . Enn, si besoin, on pourra supprimer le chier :
286
LE RPERTOIRE LOCAL
1 IsolatedStorageFile racine = IsolatedStorageFile.
GetUserStoreForApplication ();
2 if (racine.FileExists("sauvegarde.txt"))
3 racine.DeleteFile("sauvegarde.txt");
Lobjet IsolatedStorageFile que lon rcupre avec la mthode GetUserStoreForApplication
permet de crer un chier, un rpertoire, de le supprimer, etc. Bref, quasiment tout ce
que permet un systme de chier classique.
noter que cette technique est tout fait approprie pour stocker des images par
exemple, pour viter davoir les re-tlcharger chaque fois.
Remarquez quau contraire dune application Silverlight sexcutant dans un
navigateur, le rpertoire local dans une application Windows Phone na pas
de limite de taille. Tant que le tlphone dispose encore de mmoire, celle-ci
est toute vous.
Enn, avec Windows Phone 8 nous pouvons tirer parti des nouvelles API de stockages
asynchrones. Celles-ci nous permettent de ne pas bloquer le thread courant lorsque
nous avons besoin de lire et crire potentiellement de grosses donnes dans le rpertoire
local. Voici par exemple comment crire des donnes dans le rpertoire local de manire
asynchrone :
1 private async void SauvegardeAsync ()
2 {
3 IStorageFolder applicationFolder = ApplicationData.Current.
LocalFolder;
4
5 IStorageFile storageFile = await applicationFolder.
CreateFileAsync("sauvegarde.txt",
CreationCollisionOption.ReplaceExisting);
6 using (Stream stream = await storageFile.
OpenStreamForWriteAsync ())
7 {
8 byte[] bytes = Encoding.UTF8.GetBytes("30;Nicolas");
9 await stream.WriteAsync(bytes , 0, bytes.Length);
10 }
11 }
Et voici comment lire les donnes prcdemment sauvegardes :
1 private async void LectureAsync ()
2 {
3 IStorageFolder applicationFolder = ApplicationData.Current.
LocalFolder;
4
5 IStorageFile storageFile = await applicationFolder.
GetFileAsync("sauvegarde.txt");
6 IRandomAccessStream accessStream = await storageFile.
OpenReadAsync ();
7
287
CHAPITRE 19. LE TRAITEMENT DES DONNES
8 using (Stream stream = accessStream.AsStreamForRead ((int)
accessStream.Size))
9 {
10 byte[] bytes = new byte[stream.Length ];
11 await stream.ReadAsync(bytes , 0, bytes.Length);
12 string chaine = Encoding.UTF8.GetString(bytes , 0, bytes
.Length);
13 string [] tableau = chaine.Split(';');
14 int age = int.Parse(tableau[0]);
15 string prenom = tableau[1];
16 }
17 }
Ici, jai choisi de stocker mes donnes sous la forme de texte spars par des points
virgules, mais libre vous de spcier le format de chier de votre choix. Nous remar-
quons lutilisation des mots-cls async et await, dignes tmoins de lasynchronisme de
ces mthodes.
En rsum
Le XAML/C# pour Windows Phone dispose de toute une gamme de solutions
pour utiliser des donnes depuis internet ou en local sur le tlphone.
Les classes HttpRequest et WebClient permettent de faire des requtes sur le
protocole HTTP.
On utilise la bibliothque open-source JSON.NET pour interprter les donnes
au format JSON.
Il est trs facile dexploiter des ux RSS grce la bibliothque de syndication.
Lasynchronisme est grandement facilit dans Windows Phone 8 grce aux mots-
cls async et await.
Le rpertoire local correspond un emplacement sur le tlphone, ddi notre
application, o lon peut faire persister de linformation entre les divers lance-
ments dune application.
288
Troisime partie
Une bibliothque de contrles
289
Chapitre 20
Panorama et Pivot
Dicult :
Nous avons vu dans la partie prcdente que nous pouvions naviguer entre les pages,
cest bien ! Mais sachez que nous pouvons galement naviguer entre les donnes. Cest
encore mieux. Cest l quinterviennent deux contrles trs utiles qui permettent de naviguer
naturellement entre des donnes : le contrle Panorama et le contrle Pivot. Le contrle
Panorama sert en gnral voir un petit bout dun plus gros cran, qui ne rentre pas dans
lcran du tlphone. Le principe est quon peut mettre beaucoup dinformations sur une
grosse page et la mcanique du contrle Panorama incite lutilisateur se dplacer avec
le doigt sur le reste du plus gros cran. Le contrle Pivot quant lui permet plutt de
voir la mme donne sur plusieurs pages. La navigation entre les pages se fait en faisant
glisser le doigt, comme si lon tournait une page. Par exemple pour une application mto,
la premire page permet dacher la mto du jour, la page suivante permet dacher la
mto de demain, etc.
Dcouvrons prsent ces deux contrles.
291
CHAPITRE 20. PANORAMA ET PIVOT
Panorama
Le panorama est donc un contrle qui sert voir un petit bout dun plus gros cran
dont la taille dpasse celle de lcran du tlphone. On lillustre souvent avec une image
de ce genre (voir la gure 20.1).
Figure 20.1 Reprsentation du contrle Panorama
Vous vous rappelez lintroduction du cours et le passage sur les hubs ? Ce contrle est
exactement le mme. Nous pouvons lintgrer dans nos applications et tirer parti de
son lgance et de ses fonctionnalits. Pour dcouvrir le panorama, le plus simple est de
crer un nouveau projet. Vous avez srement constat que Visual Studio nous proposait
de crer dirents modles de projet, dont un projet sappelant Application Pano-
rama Windows Phone et un autre sappelant Application Pivot Windows Phone .
Choisissons le projet Application Panorama Windows Phone , ainsi quindiqu la
gure 20.2.
Si nous dmarrons immdiatement lapplication, nous pouvons voir quelle contient
un panorama existant. Wahou. . . bon ok, passons sur la relative traduction des divers
lments.
Ce quil faut remarquer ici, cest quil est possible de faire glisser lcran en cours de
gauche droite, achant trois lments en tout, et en boucle, sachant que le troisime
lment occupe plus despace quun cran (voir la gure 20.3).
Il faut galement remarquer que lachage de chaque cran incite lutilisateur aller
voir ce quil y a droite. En eet, on peut voir que le titre nest pas complet. Pareil
292
PANORAMA
Figure 20.2 Cration dun projet Panorama
Figure 20.3 La panorama du projet exemple, compos de 3 crans
293
CHAPITRE 20. PANORAMA ET PIVOT
pour le carr jaune, on se doute quil doit y avoir quelque chose ct. . . Bref, tout est
fait pour donner envie daller voir ce quil y a plus loin. Cest le principe du panorama.
Voyons prsent le XAML qui a t gnr pour obtenir cet cran :
1 <phone:Panorama Title="mon application">
2 <phone:Panorama.Background >
3 <ImageBrush ImageSource="/DemoPanorama;component/Assets
/PanoramaBackground.png"/>
4 </phone:Panorama.Background >
5
6 <!--lment un de panorama -->
7 <phone:PanoramaItem Header="first item">
8 <!--Liste simple trait avec habillage du texte -->
9 <phone:LongListSelector Margin="0,0,-22 ,0" ItemsSource=
"{Binding Items}">
10 [...]
11 </phone:LongListSelector >
12 </phone:PanoramaItem >
13
14 <!--lment deux de panorama -->
15 <phone:PanoramaItem >
16 <!--Liste double trait avec espace rserv pour une
image et habillage du texte utilisant un en-tte
flottant qui dfile avec le contenu -->
17 <phone:LongListSelector Margin="0,-38 ,-22,2"
ItemsSource="{Binding Items}">
18 [...]
19 </phone:LongListSelector >
20 </phone:PanoramaItem >
21
22 <!--lment trois de panorama -->
23 <phone:PanoramaItem Header="third item" Orientation="
Horizontal">
24 <!--Double largeur de panorama avec espaces rservs
pour grandes images -->
25 <Grid >
26 [...]
27 </Grid >
28 </phone:PanoramaItem >
29 </phone:Panorama >
Ce quon peut constater dj cest quil est compos de trois parties qui sont toutes
les trois des PanoramaItem. Un PanoramaItem - http://msdn.microsoft.com/fr-fr/
library/microsoft.phone.controls.panoramaitem(v=vs.92).aspx correspond donc
une vue de la totalit du Panorama. La navigation se passe entre ces trois lments.
Nous pouvons dailleurs voir dans le designer le rendu du premier PanoramaItem. Vous
pouvez galement voir le second en allant vous positionner dans le XAML au niveau
du second PanoramaItem, et de mme pour le troisime. Plutt pas mal, le rendu est
assez dle.
294
PANORAMA
Nous pouvons galement constater que le contrle Panorama - http://msdn.microsoft.
com/fr-fr/library/microsoft.phone.controls.panorama(v=vs.92).aspx est d-
ni dans un espace de noms dirent de ceux que nous avons dj utiliss, on voit
notamment quil est prx par phone qui correspond :
1 xmlns:phone="clr -namespace:Microsoft.Phone.Controls;assembly=
Microsoft.Phone"
Ce contrle se situe donc dans lespace de noms Microsoft.Phone.Controls et dans
lassembly Microsoft.Phone.
Pour les utilisateurs du SDK pour Windows Phone 7, le contrle panorama se
situe dans lassembly Microsoft.Phone.Controls et doit tre explicitement
rfrence.
Le panorama possde un titre qui est ach tout en haut du contrle, ici, en haut de la
page. On le remplit via la proprit Title. Vous pouvez dailleurs constater que ce titre
nest pas ach en entier et que cela nous incite encore aller voir plus droite sil ny
a pas autre chose. Ce titre est une proprit de contenu que nous pouvons remplacer
par nimporte quoi, comme avec le bouton. titre dexemple, remplacez la proprit
Title par :
1 <phone:Panorama >
2 <phone:Panorama.Title >
3 <Image Source="/Assets/ApplicationIcon.png" Margin="150
60 0 -30" />
4 </phone:Panorama.Title >
5 ...
Vous pouvez voir le rsultat la gure 20.4.
Figure 20.4 Le titre est un contrle de contenu
De la mme faon, vous pouvez mettre un fond dcran au panorama via la pro-
prit BackGround. Notez que limage doit absolument avoir son action de gnration
Resource, sinon elle risque de ne pas apparatre immdiatement et dtre charge de
manire asynchrone.
Chaque lment du panorama a un titre, reprsent par la proprit Header. Dans le
deuxime, on peut remarquer que le titre commence par un s et quil dpasse du
295
CHAPITRE 20. PANORAMA ET PIVOT
premier lment. Tout ceci est fait automatiquement sans que lon ait faire quoi que
ce soit de supplmentaire.
Nous pouvons crer autant de PanoramaItem que nous le voulons et y mettre ce que
nous voulons. Ici, il a t mis des listes de type LongListSelector, et dans le troisime
lment une grille mais cela pourrait tre nimporte quoi dautre vu que le Panorama fait
oce de conteneur. Soyez vigilant quant lutilisation du contrle Panorama. Il doit tre
utilis des emplacements judicieux an de ne pas perturber lutilisateur. Bien souvent,
il est utilis comme page daccueil dune application. Vous vous doutez bien quon peut
faire beaucoup de choses avec ce panorama. Il est par exemple possible de sabonner
lvnement de changement de PanoramaItem, ou se positionner directement sur un
lment prcis du panorama. Illustrons ceci avec le XAML suivant :
1 <phone:Panorama x:Name="MonPanorama" Title="Mes tches" Loaded=
"Panorama_Loaded" SelectionChanged="
Panorama_SelectionChanged">
2 <phone:PanoramaItem Header="Accueil">
3 <StackPanel >
4 <TextBlock Text="Blablabla" HorizontalAlignment="
Center" />
5 <Button Content="Allez aujourd 'hui" Tap="
Button_Tap" Margin="0 50 0 0" />
6 </StackPanel >
7 </phone:PanoramaItem >
8 <phone:PanoramaItem Header="Aujourd 'hui">
9 <ListBox >
10 <ListBoxItem >Tondre la pelouse </ ListBoxItem >
11 <ListBoxItem >Arroser les plantes </ ListBoxItem >
12 </ListBox >
13 </phone:PanoramaItem >
14 <phone:PanoramaItem Header="Demain">
15 <StackPanel >
16 <TextBlock Text="Passer l'aspirateur" Margin="30 50
0 60" />
17 <TextBlock Text="Laver la voiture" Margin="30 50 0
60" />
18 </StackPanel >
19 </phone:PanoramaItem >
20 </phone:Panorama >
Mon panorama contient trois lments, un accueil, des tches pour aujourdhui et des
tches pour demain. Je me suis abonn lvnement de chargement du panorama ainsi
qu lvnement de changement de slection. Ici, cela fonctionne un peu comme une
ListBox. Notons galement que lcran daccueil possde un bouton avec un vnement
de clic. Passons au code-behind prsent :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
296
PANORAMA
6 }
7
8 private void Panorama_Loaded(object sender , RoutedEventArgs
e)
9 {
10 if (IsolatedStorageSettings.ApplicationSettings.
Contains("PageCourante"))
11 {
12 MonPanorama.DefaultItem = MonPanorama.Items[(int)
IsolatedStorageSettings.ApplicationSettings["
PageCourante"]];
13 }
14 }
15
16 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
17 {
18 MonPanorama.DefaultItem = MonPanorama.Items[1];
19 }
20
21 private void Panorama_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
22 {
23 IsolatedStorageSettings.ApplicationSettings["
PageCourante"] = MonPanorama.SelectedIndex;
24 }
25 }
La mthode Panorama_SelectionChanged est appele chaque changement de s-
lection. Dans cette mthode, je stocke dans le rpertoire local lindex de la page en
cours, obtenu comme pour la ListBox avec la proprit SelectedIndex. Ce qui me
permet, au chargement du panorama, de me repositionner sur la dernire page visite
sil y en a une. Cela se fait grce la proprit DefaultItem que je renseigne avec le
PanoramaItem trouv lindice de la proprit Items, indice qui est celui stock dans le
rpertoire local. De la mme faon, je peux me positionner sur un PanoramaItem choisi
lorsque je clique sur le bouton. Mme si cest un peu plus rare, il est possible dutiliser
le binding avec le contrle Panorama. Reproduisons plus ou moins notre exemple pr-
cdent en utilisant un contexte de donnes (je retire la page accueil et le bouton, ce
sera plus simple). Tout dabord le XAML :
1 <phone:Panorama x:Name="MonPanorama" Title="Mes tches" Loaded=
"Panorama_Loaded" SelectionChanged="
Panorama_SelectionChanged" ItemsSource="{Binding ListeEcrans
}">
2 <phone:Panorama.HeaderTemplate >
3 <DataTemplate >
4 <TextBlock Text="{Binding Titre}" />
5 </DataTemplate >
6 </phone:Panorama.HeaderTemplate >
7 <phone:Panorama.ItemTemplate >
297
CHAPITRE 20. PANORAMA ET PIVOT
8 <DataTemplate >
9 <ListBox ItemsSource="{Binding ListeDesTaches}">
10 <ListBox.ItemTemplate >
11 <DataTemplate >
12 <TextBlock Text="{Binding}" Margin="0
20 0 0" />
13 </DataTemplate >
14 </ListBox.ItemTemplate >
15 </ListBox >
16 </DataTemplate >
17 </controls:Panorama.ItemTemplate >
18 </controls:Panorama >
Ici, cest comme pour la ListBox. Le contrle Panorama possde aussi des modles,
que nous pouvons utiliser. Il y a le modle HeaderTemplate qui nous permet de dnir
un titre et le modle ItemTemplate qui nous permet de grer le contenu. Le contrle
Panorama a sa proprit ItemsSource qui est lie la proprit ListeEcrans que nous
retrouvons dans le code-behind :
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 public event PropertyChangedEventHandler PropertyChanged;
4
5 private void NotifyPropertyChanged(String propertyName)
6 {
7 PropertyChangedEventHandler handler = PropertyChanged;
8 if (null != handler)
9 {
10 handler(this , new PropertyChangedEventArgs(
propertyName));
11 }
12 }
13
14 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
15 {
16 if (object.Equals(variable , valeur)) return false;
17
18 variable = valeur;
19 NotifyPropertyChanged(nomPropriete);
20 return true;
21 }
22
23 private List <Ecran > _listeEcrans;
24 public List <Ecran > ListeEcrans
25 {
26 get { return _listeEcrans; }
27 set { NotifyPropertyChanged(ref _listeEcrans , value); }
28 }
298
PANORAMA
29
30 public MainPage ()
31 {
32 InitializeComponent ();
33
34 ListeEcrans = new List <Ecran >
35 {
36 new Ecran
37 {
38 Titre = "Aujourd 'hui",
39 ListeDesTaches = new List <string > { "Tondre
la pelouse", "Arroser les plantes"}
40 },
41 new Ecran
42 {
43 Titre = "Demain",
44 ListeDesTaches = new List <string > { "Passer
l'aspirateur", "Laver la voiture"}
45 }
46 };
47
48 DataContext = this;
49 }
50
51 private void Panorama_Loaded(object sender , RoutedEventArgs
e)
52 {
53 if (IsolatedStorageSettings.ApplicationSettings.
Contains("PageCourante"))
54 {
55 MonPanorama.DefaultItem = MonPanorama.Items[(int)
IsolatedStorageSettings.ApplicationSettings["
PageCourante"]];
56 }
57 }
58
59 private void Panorama_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
60 {
61 IsolatedStorageSettings.ApplicationSettings["
PageCourante"] = MonPanorama.SelectedIndex;
62 }
63 }
Avec la classe Ecran suivante :
1 public class Ecran
2 {
3 public string Titre { get; set; }
4 public List <string > ListeDesTaches { get; set; }
5 }
299
CHAPITRE 20. PANORAMA ET PIVOT
Et le tour est jou. Vous navez plus qu dmarrer lapplication pour obtenir ce rsultat
(voir la gure 20.5).
Figure 20.5 Contrle Panorama et Binding
Pivot
Passons maintenant lautre contrle trs pratique, le Pivot, qui est un peu le petit
frre du panorama. Il permet plutt de voir la mme donne sur plusieurs pages. La
navigation entre les pages se fait en faisant glisser le doigt, comme si lon tournait une
page. On pourrait le comparer un contrle de gestion donglets. On passe longlet
suivant en faisant glisser son doigt. . .
Voyons prsent comme fonctionne le contrle Pivot - http://msdn.microsoft.
com/fr-fr/library/microsoft.phone.controls.pivot(v=vs.92).aspx. Pour cela,
crez le deuxime type de projet que nous avons vu, savoir Application Pivot Win-
dows Phone et dmarrons lapplication exemple (voir la gure 20.6). On constate
quon peut galement naviguer en faisant glisser la page sur la droite ou sur la gauche
avec le doigt (ou la souris).
Ici, visuellement, il y a seulement le titre des pages qui nous renseigne sur la prsence
dun autre lment. Voyons prsent le code XAML :
1 <phone:Pivot Title="MON APPLICATION">
2 <!--lment un de tableau crois dynamique -->
300
PIVOT
Figure 20.6 Rendu du projet Pivot exemple
3 <phone:PivotItem Header="first">
4 <!--Liste double trait avec habillage du texte -->
5 <phone:LongListSelector Margin="0,0,-12,0" ItemsSource=
"{Binding Items}">
6 [... code supprim pour plus de clart...]
7 </phone:LongListSelector >
8 </phone:PivotItem >
9
10 <!--lment deux de tableau crois dynamique -->
11 <phone:PivotItem Header="second">
12 <!--Liste double trait , aucun habillage du texte -->
13 <phone:LongListSelector Margin="0,0,-12,0" ItemsSource=
"{Binding Items}">
14 [... code supprim pour plus de clart...]
15 </phone:LongListSelector >
16 </phone:PivotItem >
17 </phone:Pivot >
Ici, le principe est le mme que pour le Panorama. Le contrle Pivot est compos de
deux PivotItem - http://msdn.microsoft.com/fr-fr/library/microsoft.phone.
controls.pivotitem(v=vs.92).aspx, chacun faisant oce de container. Dedans il
y a un LongListSelector mais tout autre contrle y trouve sa place. Encore une
fois, cest la proprit Header qui va permettre de donner un titre la page. Vous
pouvez galement voir dans le designer les dirents rendus des PivotItem en vous
301
CHAPITRE 20. PANORAMA ET PIVOT
positionnant dans le XAML leurs niveaux. Tout comme pour le panorama, vous
pouvez allgrement modier les direntes proprits, Title, Background. . . an de
personnaliser ce contrle. De mme, il possde des vnements bien pratiques pour tre
noti dun changement de vue et galement de quoi se positionner sur celle que lon
veut. Il est galement possible dutiliser le binding avec ce contrle, et cest dailleurs ce
que vous aurez tendance souvent faire. Reprenons lexemple de la liste des tches qui
est particulirement adapt au contrle Pivot et amliorons cet exemple. Voici dans
un premier temps le XAML :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <phone:Pivot Title="Mes tches" SelectedIndex="{Binding
Index , Mode=TwoWay}" Loaded="Pivot_Loaded" ItemsSource="
{Binding ListeEcrans}">
3 <phone:Pivot.HeaderTemplate >
4 <DataTemplate >
5 <TextBlock Text="{Binding Titre}" />
6 </DataTemplate >
7 </phone:Pivot.HeaderTemplate >
8 <phone:Pivot.ItemTemplate >
9 <DataTemplate >
10 <ListBox ItemsSource="{Binding ListeDesTaches}"
>
11 <ListBox.ItemTemplate >
12 <DataTemplate >
13 <TextBlock Text="{Binding}" Margin=
"0 20 0 0" />
14 </DataTemplate >
15 </ListBox.ItemTemplate >
16 </ListBox >
17 </DataTemplate >
18 </phone:Pivot.ItemTemplate >
19 </phone:Pivot >
20 </Grid >
Cela ressemble beaucoup ce que nous avons fait pour le panorama. Une des premires
dirences vient de la proprit SelectedIndex du Pivot, qui fonctionne comme pour
la ListBox. Je lai lie une proprit Index en mode TwoWay an que la mise
jour de la proprit depuis le code-behind aecte le contrle mais quinversement, un
changement de valeur depuis le contrle mette jour la proprit. Du coup, je nai plus
besoin de lvnement de changement de slection qui existe galement sur le contrle
Pivot. Le reste du XAML est semblable au Panorama. Passons au code-behind :
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 public event PropertyChangedEventHandler PropertyChanged;
4
5 private void NotifyPropertyChanged(String propertyName)
6 {
7 PropertyChangedEventHandler handler = PropertyChanged;
302
PIVOT
8 if (null != handler)
9 {
10 handler(this , new PropertyChangedEventArgs(
propertyName));
11 }
12 }
13
14 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
15 {
16 if (object.Equals(variable , valeur)) return false;
17
18 variable = valeur;
19 NotifyPropertyChanged(nomPropriete);
20 return true;
21 }
22
23 private List <Ecran > _listeEcrans;
24 public List <Ecran > ListeEcrans
25 {
26 get { return _listeEcrans; }
27 set { NotifyPropertyChanged(ref _listeEcrans , value); }
28 }
29
30 private int _index;
31 public int Index
32 {
33 get { return _index; }
34 set
35 {
36 IsolatedStorageSettings.ApplicationSettings["
PageCourante"] = value;
37 NotifyPropertyChanged(ref _index , value);
38 }
39 }
40
41 public MainPage ()
42 {
43 InitializeComponent ();
44
45 ListeEcrans = new List <Ecran >
46 {
47 new Ecran
48 {
49 Titre = "Aujourd 'hui",
50 ListeDesTaches = new List <string > { "Tondre la
pelouse", "Arroser les plantes"}
51 },
52 new Ecran
53 {
303
CHAPITRE 20. PANORAMA ET PIVOT
54 Titre = "Demain",
55 ListeDesTaches = new List <string > { "Passer l'
aspirateur", "Laver la voiture"}
56 }
57 };
58
59 DataContext = this;
60 }
61
62 private void Pivot_Loaded(object sender , RoutedEventArgs e)
63 {
64 if (IsolatedStorageSettings.ApplicationSettings.
Contains("PageCourante"))
65 {
66 Index = (int)IsolatedStorageSettings.
ApplicationSettings["PageCourante"];
67 }
68 }
69 }
Nous voyons que jai rajout une proprit Index, et qu lintrieur de son modica-
teur, jenregistre dans le rpertoire local la valeur de la slection. Ensuite, au charge-
ment du pivot et lorsque la valeur existe, je positionne la proprit Index la valeur
enregistre lors dune visite prcdente. Et voil, vous pouvez admirer le rendu la
gure 20.7.
Vous pourriez trouver que les deux contrles se ressemblent, et ce nest pas complte-
ment faux. Je vous rappelle juste que le contrle Panorama permet dacher plusieurs
donnes sur une seule grosse page alors que le contrle Pivot est utilis pour prsenter
la mme donne sur plusieurs pages. Vous apprhenderez au fur et mesure la subtile
dirence entre ces deux contrles.
En rsum
Le Panorama et le Pivot permettent de naviguer lintrieur des donnes.
Le Panorama sert voir un petit bout dun plus gros cran dont la taille dpasse
celle de lcran du tlphone.
Le Pivot permet plutt de voir la mme donne sur plusieurs pages.
Chaque changement de vue se fait grce un glissement de doigt.
Le contrle Pivot est particulirement bien adapt au binding.
304
PIVOT
Figure 20.7 Le binding du contrle Pivot
305
CHAPITRE 20. PANORAMA ET PIVOT
306
Chapitre 21
Navigateur web
Dicult :
Malgr tous les superbes contrles dont dispose Windows Phone, vous allez parfois avoir
besoin dacher du HTML ou bien directement une page web. Cest ainsi que le SDK
de Windows Phone dispose dun contrle bien pratique : le WebBrowser - http://msdn.
microsoft.com/fr-fr/library/microsoft.phone.controls.webbrowser(v=vs.92)
.aspx. Vous pouvez le voir comme un mini Internet Explorer que lon peut mettre o on
veut dans une page et qui na pas toute la gestion des barres dadresses, des favoris, . . .
Si nos tlphones possdent dj un navigateur web, en loccurrence Internet Explorer,
quoi pourrait bien servir un tel contrle ?
Les scnarios sont divers, cela peut aller de lachage dun billet issu dun ux RSS une
authentication via un formulaire HTML, sur un rseau social par exemple. Ou pourquoi pas
un jeu en HTML5 ? De plus, il est galement possible de communiquer entre le Javascript
dune page web et notre page XAML. Regardons tout cela de plus prs.
307
CHAPITRE 21. NAVIGATEUR WEB
Naviguer sur une page web
Tout dabord, il nous faut ce fameux contrle. Vous pouvez le mettre dans votre XAML
via la boite outils, comme indiqu la gure 21.1.
Figure 21.1 Le contrle WebBrowser dans la boite outils
Ou comme nous en avons dsormais lhabitude, directement dans le XAML :
1 <phone:WebBrowser x:Name="MonWebBrowser" />
Il est ensuite possible de naviguer sur une page web grce la mthode Navigate()
qui prend une URI en paramtre :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 MonWebBrowser.Navigate(new Uri("http ://fr.openclassrooms.
com/informatique/cours/apprenez -a-developper -en-c",
UriKind.Absolute));
5 }
Ici, jeectue la navigation dans le constructeur de la page. La page internet sache
donc comme on peut le voir sur la gure 21.2.
(si bien sr vous tes connects internet !)
Evnements de navigation
Le contrle WebBrowser possde galement des vnements qui permettent de savoir
par exemple quand une page est charge, il sagit de lvnement Navigated. Ce qui est
pratique si lon souhaite acher un message dattente, ou si on veut nacher vraiment
le WebControl quune fois la page compltement charge. Il y a galement un autre
vnement intressant qui permet de savoir si la navigation a chou, par exemple si
lutilisateur ne capte plus internet. Il sagit de lvnement NavigationFailed. Cet
vnement nous fournit notamment une exception qui peut nous donner plus dinfor-
mations sur lerreur.
Il est toujours intressant dindiquer lutilisateur si la navigation a chou. Il est
308
NAVIGATION INTERNE
Figure 21.2 La page web sache dans le contrle
galement appropri de lui proposer un bouton lui permettant de retenter sa navigation,
si jamais il se trouve nouveau dans une zone de couverture.
Navigation interne
Mais nous pouvons galement crer notre propre HTML et lacher grce la mthode
NavigateToString :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 MonWebBrowser.NavigateToString(
5 @"<html >
6 <body >
7 <h3>Bonjour HTML !</h3>
8 </body >
9 </html >");
10 }
Qui donnera la gure 21.3.
309
CHAPITRE 21. NAVIGATEUR WEB
Figure 21.3 Achage direct de HTML
Le caractre @ est utilis ici pour pouvoir avoir une chane de caractres
dnie sur plusieurs lignes. Vous pouvez tout faire crire tout en ligne ou
faire des concatnations avec le caractre \n.
Vous avouerez que ce nest pas trs pratique de devoir saisir le HTML dans le code.
Cela serait plus pratique de pouvoir intgrer un chier HTML notre application et
de naviguer dessus. Pour ce faire, il va falloir dans un premier temps intgrer le chier
dans le rpertoire local. Commencez dj par ajouter un nouveau chier de type texte
au projet que vous nommez hello.html et qui possde le code suivant :
1 <html >
2 <body >
3 <h3>Bonjour HTML local!</h3>
4 </body >
5 </html >
Ensuite, dans les proprits du chier, vriez que laction de gnration est contenu .
Puis, on peut utiliser le code suivant pour ajouter un chier HTML dans le rpertoire
local :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 IntegreHtmlDansRepertoireLocalSiNonPresent("hello.html");
310
COMMUNIQUER ENTRE XAML ET HTML
5 MonWebBrowser.Navigate(new Uri("hello.html", UriKind.
Relative));
6 }
7
8 private void IntegreHtmlDansRepertoireLocalSiNonPresent(string
nomFichier)
9 {
10 IsolatedStorageFile systemeDeFichier = IsolatedStorageFile.
GetUserStoreForApplication ();
11
12 if (! systemeDeFichier.FileExists(nomFichier))
13 {
14 // lecture du fichier depuis les ressources
15 StreamResourceInfo sr = Application.GetResourceStream(
new Uri(nomFichier , UriKind.Relative));
16
17 using (StreamReader reader = new StreamReader(sr.Stream
))
18 {
19 string html = reader.ReadToEnd ();
20 using (IsolatedStorageFileStream stream = new
IsolatedStorageFileStream(nomFichier , FileMode.
Create , IsolatedStorageFile.
GetUserStoreForApplication ()))
21 {
22 using (StreamWriter writer = new StreamWriter(
stream))
23 {
24 writer.Write(html);
25 writer.Close();
26 }
27 }
28 }
29 }
30 }
Le principe est de vrier la prsence du chier. Sil nexiste pas alors on le lit depuis
les ressources comme on la dj vu, puis on crit le contenu dans le rpertoire local. Il
ne restera plus qu naviguer sur ce chier cr grce la mthode Navigate comme
on peut le voir plus haut.
Communiquer entre XAML et HTML
Le WebBrowser a aussi la capacit de faire communiquer la page web et la page
XAML. Plus particulirement, il est possible dinvoquer une mthode Javascript de-
puis notre page XAML et inversement, la page web peut dclencher un vnement
dans notre application. Pour que ceci soit possible, vous devez positionner la pro-
prit IsScriptEnabled true dans votre WebBrowser et vous abonner lvnement
311
CHAPITRE 21. NAVIGATEUR WEB
ScriptNotify :
1 <phone:WebBrowser x:Name="MonWebBrowser" IsScriptEnabled="True"
ScriptNotify="MonWebBrowser_ScriptNotify" />
Pour que cela soit plus simple, je vais illustrer le fonctionnement avec du HTML et du
Javascript que jembarquerai dans mon application avec la mthode montre prcdem-
ment. Mais il est bien sr possible de faire la mme chose avec une page sur internet.
Lvnement ScriptNotify est lev lorsque la page web invoque la mthode Javascript
window.external.notify(). Cette mthode accepte un paramtre sous la forme dune
chane de caractres qui pourra tre rcupre dans lvnement ScriptNotify. Pour
lillustrer, modions notre page hello.html pour avoir :
1 <!DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Transitional //EN"
"http :// www.w3.org/TR/xhtml1/DTD/xhtml1 -transitional.dtd">
2 <html xmlns="http :// www.w3.org/1999/xhtml">
3 <head >
4 <title >Demo javascript </title >
5 <script type="text/javascript">
6 function EnvoyerMessage ()
7 {
8 window.external.notify("Bonjour , je suis " + prenom.
value);
9 resultat.innerHTML = "Message bien envoy";
10 }
11 </script >
12 </head >
13 <body >
14 <h3>Communication entre page web et XAML </h3 >
15 <p>Saisissez votre prnom : </p>
16 <input type="text" id="prenom" />
17 <input type="button" value="Dire bonjour" onclick="
EnvoyerMessage ();" />
18 <div id="resultat" />
19 </body >
20 </html >
Cette page possde une zone de texte pour saisir un prnom et un bouton qui invoque
la mthode Javascript EnvoyerMessage(). Cette mthode rcupre la valeur du champ
saisi, la concatne la chane Bonjour, je suis et lenvoie notre application Win-
dows Phone via la mthode window.external.notify. Enn, elle ache un message
sur la page web pour indiquer que le message a bien t envoy. Ct code-behind,
nous avons juste naviguer sur notre page et rcuprer la valeur envoye :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6 IntegreHtmlDansRepertoireLocalSiNonPresent("hello.html"
, true);
312
COMMUNIQUER ENTRE XAML ET HTML
7 MonWebBrowser.Navigate(new Uri("hello.html", UriKind.
Relative));
8 }
9
10 private void IntegreHtmlDansRepertoireLocalSiNonPresent(
string nomFichier , bool force)
11 {
12 IsolatedStorageFile systemeDeFichier =
IsolatedStorageFile.GetUserStoreForApplication ();
13
14 if (! systemeDeFichier.FileExists(nomFichier) || force)
15 {
16 // lecture du fichier depuis les ressources
17 StreamResourceInfo sr = Application.
GetResourceStream(new Uri(nomFichier , UriKind.
Relative));
18
19 using (StreamReader reader = new StreamReader(sr.
Stream))
20 {
21 string html = reader.ReadToEnd ();
22 using (IsolatedStorageFileStream stream = new
IsolatedStorageFileStream(nomFichier ,
FileMode.Create , IsolatedStorageFile.
GetUserStoreForApplication ()))
23 {
24 using (StreamWriter writer = new
StreamWriter(stream))
25 {
26 writer.Write(html);
27 writer.Close();
28 }
29 }
30 }
31 }
32 }
33
34 private void MonWebBrowser_ScriptNotify(object sender ,
NotifyEventArgs e)
35 {
36 MessageBox.Show(e.Value);
37 }
38 }
Notez que jai rajout un paramtre la mthode permettant de stocker la page HTML
dans le rpertoire local, qui force lenregistrement an dtre sr davoir toujours la
dernire version. Rappelez-vous, nous recevons la valeur envoye par la page web grce
lvnement ScriptNotify. Lorsque cette chane est reue, on lache simplement
avec une boite de message. Dmarrons lapplication, la page web sache, comme vous
pouvez le voir la gure 21.4.
313
CHAPITRE 21. NAVIGATEUR WEB
Figure 21.4 La page web avant envoi du message
Notez que nous sommes un peu obligs de zoomer pour pouvoir voir le contenu de la
page web et cliquer sur le bouton. Pour rappel, le zoom seectue avec deux doigts, en
posant les doigts sur lcran et en les tirant vers lextrieur. Ce mouvement sappelle
le Pinch-to-zoom. Il est galement possible de double-cliquer dans lmulateur an de
produire le mme eet. Nous verrons comment corriger ce problme plus loin. Saisissez
une valeur et cliquez sur le bouton. Le message est bien envoy par la page HTML et
est bien reu par notre application, comme en tmoigne la gure 21.5.
Mais alors, cette page HTML illisible, on ne peut pas un peu lamliorer ? Il y a plusieurs
solutions pour ce faire. La premire est dutiliser un tag meta que le navigateur va
interprter. Cette balise se met lintrieur de la balise <head> :
1 <meta name="viewport" content="width=device -width , user -
scalable=no" />
Elle permet de dnir la taille de la fentre. On peut y mettre une valeur numrique
allant de 320 10000 ou lajuster directement la taille du tlphone avec la valeur
device-width. Remarquez, que la proprit user-scalable empchera lutilisateur de
pouvoir zoomer dans la page. Voici le rendu la gure 21.6.
Ce qui est beaucoup plus lisible ! Lautre solution est dutiliser une proprit CSS pour
ajuster la taille du texte :
1 <h3 style="-ms -text -size -adjust:300%">Communication entre page
web et XAML </h3 >
314
COMMUNIQUER ENTRE XAML ET HTML
Figure 21.5 Lapplication Windows Phone reoit un message de la page web
Figure 21.6 Le zoom est adapt la largeur de la page
315
CHAPITRE 21. NAVIGATEUR WEB
Ici, jaugmente la taille de cette balise de 300%. Remarquez que cette balise est incom-
patible avec la balise viewport.
Il est possible de faire communiquer nos deux lments galement dans lautre sens.
Ainsi, nous pouvons invoquer une mthode Javascript prsente sur la page web depuis
le code C#. Modions notre page pour quelle possde une mthode Javascript qui
accepte deux paramtres :
1 <!DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Transitional //EN"
"http :// www.w3.org/TR/xhtml1/DTD/xhtml1 -transitional.dtd">
2 <html xmlns="http :// www.w3.org/1999/xhtml">
3 <head >
4 <meta name="viewport" content="width=device -width , user -
scalable=no" />
5 <title >Demo javascript </title >
6 <script type="text/javascript">
7 function ReceptionMessage(texte , heure)
8 {
9 resultat.innerHTML = texte + ". Il est " + heure;
10 return "OK";
11 }
12 </script >
13 </head >
14 <body >
15 <h3>En attente d'un envoi ...</h3>
16 <div id="resultat" />
17 </body >
18 </html >
Rajoutons ensuite dans notre XAML un bouton qui va permettre denvoyer des infor-
mations la page web :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*" />
4 <RowDefinition Height="auto" />
5 </Grid.RowDefinitions >
6 <phone:WebBrowser x:Name="MonWebBrowser" IsScriptEnabled="
True" ScriptNotify="MonWebBrowser_ScriptNotify" />
7 <Button Content="Envoyer l'heure" Tap="Button_Tap" Grid.Row
="1" />
8 </Grid >
Et dans le code-behind nous aurons :
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 string retour = (string)MonWebBrowser.InvokeScript("
ReceptionMessage", "Bonjour depuis Windows Phone",
DateTime.Now.ToShortTimeString ());
4 }
316
COMMUNIQUER ENTRE XAML ET HTML
On utilise la mthode InvokeScript de lobjet WebBrowser en lui passant en paramtre
le nom de la mthode Javascript appeler. Puis nous pouvons passer ensuite autant
de paramtres que nous le souhaitons, sous la forme dune chane de caractres. Il faut
bien sr quil y ait autant de paramtres que peut accepter la mthode Javascript. Ce
qui donne la gure 21.7.
Figure 21.7 Rception par la page HTML du message envoy par lapplication
Windows Phone
Notez que le Javascript peut renvoyer une valeur au code C#. Ici je renvoie la chane
OK, que je stocke dans la variable retour pour une ventuelle interprtation. Remar-
quez quil est galement possible de passer des objets complexes grce au JSON. Le
principe consiste envoyer une version srialise dun objet la page web et la page
web dsrialise cet objet pour pouvoir lutiliser. Utilisons donc la bibliothque open-
source JSON.NET que nous avions prcdemment utilise an de srialiser un objet.
Rfrencez lassembly Newtonsoft.Json.dll et crez une classe avec des proprits :
1 public class Informations
2 {
3 public string Message { get; set; }
4 public DateTime Date { get; set; }
5 }
Puis, srialisez un objet pour lenvoyer notre mthode Javascript :
1 private void Button_Tap(object sender , System.Windows.Input.
GestureEventArgs e)
317
CHAPITRE 21. NAVIGATEUR WEB
2 {
3 Informations informations = new Informations { Message = "
Bonjour depuis Windows Phone", Date = DateTime.Now };
4 string objetSerialise = JsonConvert.SerializeObject(
informations);
5 Retour retour = JsonConvert.DeserializeObject <Retour >((
string)MonWebBrowser.InvokeScript("ReceptionMessage",
objetSerialise));
6 }
De la mme faon, on pourra dsrialiser le retour de la mthode, dans lobjet Retour
suivant :
1 public class Retour
2 {
3 public string Resultat { get; set; }
4 public bool Succes { get; set; }
5 }
Il ne reste plus qu modier le Javascript de la page :
1 <!DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Transitional //EN"
"http :// www.w3.org/TR/xhtml1/DTD/xhtml1 -transitional.dtd">
2 <html xmlns="http :// www.w3.org/1999/xhtml">
3 <head >
4 <meta name="viewport" content="width=device -width , user -
scalable=no" />
5 <title >Demo javascript </title >
6 <script type="text/javascript">
7 function ReceptionMessage(objet)
8 {
9 var infos = JSON.parse(objet);
10 var d = new Date(infos.Date);
11 resultat.innerHTML = infos.Message + ". Il est " + d.
getHours () + 'h' + d.getMinutes ();
12 var retour = {
13 Resultat : "OK",
14 Succes : true
15 }
16 return JSON.stringify(retour);
17 }
18 </script >
19 </head >
20 <body >
21 <h3>En attente d'un envoi ...</h3>
22 <div id="resultat" />
23 </body >
24 </html >
Pour dsrialiser du JSON cot javascript, on utilise la mthode JSON.parse et pour
srialiser, on utilisera JSON.stringify. Et voil. Plutt puissant nest-ce pas ?
318
COMMUNIQUER ENTRE XAML ET HTML
En rsum
Le contrle WebBrowser nous permet facilement dacher du HTML dans nos
applications Windows Phone.
Il est possible dinteragir entre lapplication et la page web grce du Javascript.
Grce au JSON, nous pourrons passer des paramtres complexes entre lappli-
cation et la page web.
319
CHAPITRE 21. NAVIGATEUR WEB
320
Chapitre 22
TP : Cration dun lecteur de ux RSS
simple
Dicult :
Oula, mais a fait longtemps quon a pas un peu test nos connaissances dans un contexte
bien concret. Il est temps dy remdier avec ce TP o nous allons mettre en pratique
les derniers lments que nous avons tudis. Avec la cl, un petit dbut dapplication
sympathique pour lire nos ux RSS. Allez, cest parti, vous de travailler.
321
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
Instructions pour raliser le TP
Vous lavez compris, nous allons raliser une petite application qui va nous permettre
de lire nos ux RSS prfrs. Voici ce que devra faire lapplication :
Lapplication possdera une page de menu qui permettra soit daller voir les ux
dj enregistrs dans lapplication, soit daller en ajouter de nouveaux.
La page de saisie de nouveau ux orira un moyen de saisir et de faire persister
des URL de ux RSS.
La page de consultation possdera une ListBox prsentant la liste de tous les
titres, image et description des ux.
Lors du clic sur un lment, elle renverra sur une nouvelle page contenant un
contrle Pivot, branch encore une fois sur la liste de tous les ux et automati-
quement positionn sur le ux slectionn dans la ListBox. Ce qui permettra de
naviguer de ux en ux grce un glissement de doigt. Ce pivot prsentera le
titre du blog ainsi quune ListBox contenant la liste des titres des billets classs
par ordre dcroissant de dernire mise jour.
La slection dun billet de cette ListBox renverra sur une page contenant un
WebBrowser et achant ce fameux billet
Voil pour lnonc de ce TP. Il va nous permettre de vrier que nous avons bien
compris comment accder des donnes sur internet, comment utiliser la bibliothque
de syndication, comment utiliser la ListBox et le Pivot avec le binding. Vous devrez
galement utiliser le rpertoire local - bien sr, nous nallons pas re-saisir nos ux RSS
chaque lancement dapplication -, la navigation et le contrle WebBrowser. Bref, que
des bonnes choses !
Vous vous sentez prt pour relever ce d ? Alors, nhsitez pas vous lancer. Petit
bonus ? Utiliser une solution pour marquer diremment les billets qui ont t lus des
billets qui ne lont pas encore t. . . Vous pouvez bien sr si vous le souhaitez respecter
le patron de conception MVVM, mais ceci nest pas une obligation.
Si cela vous eraie un peu (et a peut !), essayons de dcortiquer un peu les dirents
lments.
La page de menu ne devrait pas poser de problmes, il sut dutiliser le service
de navigation.
La page de saisie dURL de ux RSS ne devrait pas non plus poser de problmes.
Pensez juste faire persister toute modication dans le rpertoire local.
Passons la page qui ache la liste des ux RSS dans une ListBox. Le point
critique consiste charger les dirents ux RSS, mais a, vous devriez sa-
voir le faire car nous lavons vu dans la partie prcdente. Noubliez pas que
la classe WebClient ne peut tlcharger quun lment la fois, il va donc fal-
loir attendre que le tlchargement prcdent soit termin. Ensuite, tant donn
quon doit acher le titre, limage et la description, il est tout fait oppor-
tun de crer une classe ddie qui ne contiendra que les lments que nous
souhaitons acher. Le titre est disponible dans la proprit Title.Text dun
SyndicationFeed, limage via la proprit ImageUrl et la description via la pro-
prit Description.Text. Chaque ux possdera une liste de billets qui contien-
322
CORRECTION
dront la date de dernire publication (proprit LastUpdatedTime.DateTime),
le titre (proprit Title.Text) et lURL du billet (premier lment de la liste
Links, proprit Uri). Ensuite tout est une histoire de binding, ce qui nest pas
forcment le plus facile mais cest un point trs important o vous devez vous
entraner.
Enn, la page avec le WebBrowser ne devrait pas tre trop complique faire,
le chapitre sur le WebBrowser tant tout frachement lu.
Noubliez pas que vous pouvez utiliser le dictionnaire dtat pour communiquer entre
les pages. Allez, jen ai beaucoup dit. Pour le reste, cest vous de chercher un peu.
Bon courage.
Correction
Ahhhh, une premire vraie application. Enn ! Pas si facile nalement ? On se rend
compte quil y a plein de petites choses, plein de lgers bugs qui apparaissent au fur
et mesure de nos tests. . . Il faut avancer petit petit partir du moment o a se
complique un peu et lorsque lapplication commence grandir.
Il ny a pas une unique solution pour ce TP. Toute solution fonctionnelle est bonne.
Je vais vous prsenter la mienne. Jai port une attention quasi nulle la prsentation
histoire que cela soit assez simple. Jespre que de votre ct, vous en avez prot pour
faire quelque chose de joli !
Jai donc commenc par crer une nouvelle application, nomme TpFluxRss. tant
donn que nous avons besoin de manipuler des ux RSS, il faut rfrencer lassembly
System.ServiceModel.Syndication.dll. Voici la page de menu :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <!--TitlePanel contient le nom de l'application et le titre
de la page -->
8 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
9 <TextBlock x:Name="ApplicationTitle" Text="TP Lecteur
de flux RSS" Style="{StaticResource
PhoneTextNormalStyle}"/>
10 <TextBlock x:Name="PageTitle" Text="Menu" Margin="9,-7,
0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
11 </StackPanel >
12
13 <!--ContentPanel - placez tout contenu supplmentaire ici
-->
14 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0"
>
323
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
15 <StackPanel >
16 <Button Content="Voir les flux RSS" Tap="
VoirFluxTap" />
17 <Button Content="Ajouter un flux RSS" Tap="
AjouterFluxTap" />
18 </StackPanel >
19
20 </Grid >
21 </Grid >
Avec le code-behind suivant :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 // Constructeur
4 public MainPage ()
5 {
6 InitializeComponent ();
7
8 if (IsolatedStorageSettings.ApplicationSettings.
Contains("ListeUrl"))
9 {
10 PhoneApplicationService.Current.State["ListeUrl"] =
IsolatedStorageSettings.ApplicationSettings["
ListeUrl"];
11 }
12 }
13
14 private void VoirFluxTap(object sender , System.Windows.
Input.GestureEventArgs e)
15 {
16 NavigationService.Navigate(new Uri("/VoirFlux.xaml",
UriKind.Relative));
17 }
18
19 private void AjouterFluxTap(object sender , System.Windows.
Input.GestureEventArgs e)
20 {
21 NavigationService.Navigate(new Uri("/AjouterFlux.xaml",
UriKind.Relative));
22 }
23 }
On observe dans le constructeur quon commence par charger un objet que lon met
directement dans le dictionnaire dtat. Le nom de la cl nous fait pressentir quil sagit
de la liste des URL de ux RSS que notre utilisateur a saisi dans notre application. Ce
qui nous permet de les faire persister dun lancement lautre. Pour le reste, il sagit
dacher deux boutons qui nous renvoient sur dautres pages, les pages VoirFlux.xaml
et AjouterFlux.xaml (voir la gure 22.1).
Commenons par la page AjouterFlux.xaml qui, sans surprises, ache une page per-
324
CORRECTION
Figure 22.1 La page de menu du lecteur de ux RSS
mettant de saisir des URL de ux RSS. Le XAML de la page est encore trs simple :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
8 <TextBlock x:Name="ApplicationTitle" Text="TP Lecteur
de flux RSS" Style="{StaticResource
PhoneTextNormalStyle}"/>
9 <TextBlock x:Name="PageTitle" Text="Ajouter un flux"
Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0"
>
13 <StackPanel >
14 <TextBlock Text="Saisir une url" />
15 <TextBox x:Name="Url" InputScope="Url" />
16 <Button Content="Ajouter" Tap="AjouterTap" />
17 </StackPanel >
325
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
18 </Grid >
19 </Grid >
Il permet dacher une zone de texte, o le clavier sera adapt pour la saisie dURL
(InputScope="Url") et possdant un bouton pour faire lajout de lURL, comme vous
pouvez le voir sur la gure 22.2.
Figure 22.2 La page dajout des ux du lecteur de ux RSS
Cest dans le code-behind que tout se passe :
1 public partial class AjouterFlux : PhoneApplicationPage
2 {
3 private List <Uri > listeUrl;
4
5 public AjouterFlux ()
6 {
7 InitializeComponent ();
8 }
9
10 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
11 {
12 Url.Text = "http ://";
13 if (PhoneApplicationService.Current.State.ContainsKey("
ListeUrl"))
14 listeUrl = (List <Uri >) PhoneApplicationService.
Current.State["ListeUrl"];
326
CORRECTION
15 else
16 listeUrl = new List <Uri >();
17 base.OnNavigatedTo(e);
18 }
19
20 private void AjouterTap(object sender , System.Windows.Input
.GestureEventArgs e)
21 {
22 Uri uri;
23 if (!Uri.TryCreate(Url.Text , UriKind.Absolute , out uri)
)
24 MessageBox.Show("Le format de l'url est incorrect")
;
25 else
26 {
27 listeUrl.Add(uri);
28 IsolatedStorageSettings.ApplicationSettings["
ListeUrl"] = listeUrl;
29 PhoneApplicationService.Current.State["ListeUrl"] =
listeUrl;
30 MessageBox.Show("L'url a t correctement ajoute")
;
31 }
32 }
33 }
On commence par obtenir la liste des URL potentiellement dj charge, ensuite nous
lajoutons la liste si elle nexiste pas dj, puis nous mettons jour cette liste dans
le rpertoire local ainsi que dans le dictionnaire dtat.
Remarque : il pourrait tre judicieux de vrier ici si lURL correspond vrai-
ment un ux RSS.
Maintenant, il sagit de raliser la page VoirFlux.xaml, qui contient la liste des titres
des dirents ux. Pour lexemple, je men suis ajout quelques uns, comme vous pouvez
le voir sur la gure 22.3.
Ici le XAML intressant se situe dans la deuxime grille :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
8 <TextBlock x:Name="ApplicationTitle" Text="TP Lecteur
de flux RSS" Style="{StaticResource
327
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
Figure 22.3 La liste de tous les ux du lecteur de ux RSS
PhoneTextNormalStyle}"/>
9 <TextBlock x:Name="PageTitle" Text="Voir les flux"
Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
>
13 <Grid.RowDefinitions >
14 <RowDefinition Height="auto" />
15 <RowDefinition Height="*" />
16 </Grid.RowDefinitions >
17 <TextBlock x:Name="Chargement" HorizontalAlignment="
Center" Foreground="Red" FontSize="20" FontWeight="
Bold" />
18 <ListBox x:Name="ListBoxFlux" ItemsSource="{Binding
ListeFlux}" Grid.Row="1" SelectionChanged="
ListBox_SelectionChanged">
19 <ListBox.ItemTemplate >
20 <DataTemplate >
21 <Grid >
22 <Grid.ColumnDefinitions >
23 <ColumnDefinition Width="50" />
24 <ColumnDefinition Width="*" />
328
CORRECTION
25 </Grid.ColumnDefinitions >
26 <Grid.RowDefinitions >
27 <RowDefinition Height="auto" />
28 <RowDefinition Height="auto" />
29 <RowDefinition Height="auto" />
30 </Grid.RowDefinitions >
31 <Image Source="{Binding UrlImage}"
Height="50" Width="50" />
32 <TextBlock Grid.Column="1" Text="{
Binding Titre}" TextWrapping="Wrap"
Style="{StaticResource
PhoneTextTitle3Style}" />
33 <TextBlock Grid.ColumnSpan="2" Grid.Row
="1" Text="{Binding Description}"
TextWrapping="Wrap" Margin="0 0 0 20
" FontStyle="Italic" />
34 <Line X1="0" X2="480" Y1="0" Y2="0"
StrokeThickness="5" Stroke="Blue"
Grid.Row="2" Grid.ColumnSpan="2" />
35 </Grid >
36 </DataTemplate >
37 </ListBox.ItemTemplate >
38 </ListBox >
39 </Grid >
40 </Grid >
On y remarque un TextBlock qui servira dindicateur de chargement des ux, puis une
ListBox qui est lie la proprit ListeFlux. Le modle des lments de la ListBox
ache limage du ux, via la liaison la proprit UrlImage, le titre via la liaison
la proprit Titre ainsi que la description. . . Notons un unique eet desthtique
permettant de sparer deux ux, via une magnique ligne bleue. Passons au code
behind :
1 public partial class VoirFlux : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 private WebClient client;
4
5 private ObservableCollection <Flux > listeFlux;
6 public ObservableCollection <Flux > ListeFlux
7 {
8 get { return listeFlux; }
9 set { NotifyPropertyChanged(ref listeFlux , value); }
10 }
11
12 public event PropertyChangedEventHandler PropertyChanged;
13
14 public void NotifyPropertyChanged(string nomPropriete)
15 {
16 if (PropertyChanged != null)
329
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
17 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
18 }
19
20 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
21 {
22 if (object.Equals(variable , valeur)) return false;
23
24 variable = valeur;
25 NotifyPropertyChanged(nomPropriete);
26 return true;
27 }
28
29 public VoirFlux ()
30 {
31 InitializeComponent ();
32 DataContext = this;
33 }
34
35 protected override async void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
36 {
37 List <Uri > listeUrl;
38 if (PhoneApplicationService.Current.State.ContainsKey("
ListeUrl"))
39 listeUrl = (List <Uri >) PhoneApplicationService.
Current.State["ListeUrl"];
40 else
41 listeUrl = new List <Uri >();
42
43 if (listeUrl.Count == 0)
44 {
45 MessageBox.Show("Vous devez d'abord ajouter des
flux");
46 if (NavigationService.CanGoBack)
47 NavigationService.GoBack ();
48 }
49 else
50 {
51 Chargement.Text = "Chargement en cours ...";
52 Chargement.Visibility = Visibility.Visible;
53 ListeFlux = new ObservableCollection <Flux >();
54 client = new WebClient ();
55
56 queue = new Queue <Uri >();
57 foreach (Uri uri in listeUrl)
58 {
59 try
60 {
330
CORRECTION
61 string rss = await client.
DownloadStringTaskAsync(uri);
62 AjouteFlux(rss);
63 }
64 catch (Exception)
65 {
66 MessageBox.Show("Impossible de lire le flux
l'adresse : " + uri + "\nVrifiez
votre connexion internet");
67 }
68 }
69 Chargement.Text = string.Empty;
70 Chargement.Visibility = Visibility.Collapsed;
71 }
72 base.OnNavigatedTo(e);
73 }
74
75 private void AjouteFlux(string flux)
76 {
77 StringReader stringReader = new StringReader(flux);
78 XmlReader xmlReader = XmlReader.Create(stringReader);
79 SyndicationFeed feed = SyndicationFeed.Load(xmlReader);
80 listeFlux.Add(ConstruitFlux(feed));
81 PhoneApplicationService.Current.State["ListeFlux"] =
ListeFlux.ToList ();
82 }
83
84 private Flux ConstruitFlux(SyndicationFeed feed)
85 {
86 Flux flux = new Flux { Titre = feed.Title.Text ,
UrlImage = feed.ImageUrl , Description = feed.
Description == null ? string.Empty : feed.
Description.Text , ListeBillets = new List <Billet >()
};
87 foreach (SyndicationItem item in feed.Items.
OrderByDescending(e => e.LastUpdatedTime.DateTime))
88 {
89 Uri url = item.Links.Select(e => e.Uri).
FirstOrDefault ();
90 if (url != null)
91 {
92 Billet billet = new Billet { Id = url.
AbsolutePath , DatePublication = item.
LastUpdatedTime.DateTime , Titre = item.Title
.Text , EstDejaLu = EstDejaLu(url.
AbsolutePath), Url = url };
93 flux.ListeBillets.Add(billet);
94 }
95 }
96 return flux;
331
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
97 }
98
99 private bool EstDejaLu(string id)
100 {
101 if (IsolatedStorageSettings.ApplicationSettings.
Contains("ListeDejaLus"))
102 {
103 List <string > dejaLus = (List <string >)
IsolatedStorageSettings.ApplicationSettings["
ListeDejaLus"];
104 bool any = dejaLus.Any(e => e == id);
105 return any;
106 }
107 return false;
108 }
109
110 private void ListBox_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
111 {
112 if (ListBoxFlux.SelectedItem != null)
113 {
114 Flux flux = (Flux)ListBoxFlux.SelectedItem;
115 PhoneApplicationService.Current.State["FluxCourant"
] = flux;
116 NavigationService.Navigate(new Uri("/VoirFluxPivot.
xaml", UriKind.Relative));
117 ListBoxFlux.SelectedItem = null;
118 }
119 }
120 }
Cest le code-behind le plus long de lapplication. Nous voyons limplmentation clas-
sique de INotifyPropertyChanged ainsi quune proprit ListeFlux qui est une ObservableCollection
de Flux. Lobjet Flux contiendra toutes les proprits dun Flux que nous souhaitons
acher sur la prochaine page :
1 public class Flux
2 {
3 public string Titre { get; set; }
4 public Uri UrlImage { get; set; }
5 public string Description { get; set; }
6 public List <Billet > ListeBillets { get; set; }
7 }
Un titre, lURL de limage, la description ainsi quune liste de billets, sachant que la
classe Billet sera :
1 public class Billet
2 {
3 public string Id { get; set; }
4 public DateTime DatePublication { get; set; }
332
CORRECTION
5 public string Titre { get; set; }
6 public Uri Url { get; set; }
7 public bool EstDejaLu { get; set; }
8 }
Ensuite, il y a le chargement des ux. Voyez comme cest facile grce await, une
simple boucle et on nen parle plus.
La mthode AjouteFlux cre un objet SyndicationFeed comme on la dj vu puis
assemble un objet Flux partir du SyndicationFeed. La liste dobjets Flux est en-
suite mise jour dans le dictionnaire dtat. Notons que lors de lassemblage, je dois
dterminer si le billet a dj t lu ou non. Pour cela, je tente de lire dans le rpertoire
local la liste de tous les billets dj lus, identis par leur id. Si je le trouve, cest que
le billet est dj lu. Cette liste est alimente lorsquon visionne rellement le billet.
Il serait judicieux de ne lire quune unique fois la liste des billets dj lus
depuis le rpertoire local, par exemple dans la mthode OnNavigatedTo, an
damliorer les performances. Je ne lai pas fait ici pour que cela soit plus
clair, mais nhsitez pas le faire.
Enn, lvnement de slection dun ux soccupe de rcuprer le ux slectionn, de le
mettre dans le dictionnaire dtat et de naviguer sur la page VoirFluxPivot.xaml. Fi-
nalement, ce nest pas trs compliqu. Il faut juste enchaner tranquillement les actions
sans rien oublier.
Passons prsent la page VoirFluxPivot.xaml o le but est dacher dans un pivot
la liste des ux, en se positionnant sur celui choisi. Ce qui nous permettra de naviguer
de ux en ux en faisant un glissement de doigt. Chaque vue du pivot contiendra une
ListBox avec tous les billets du ux en cours. Notons au passage que jai choisi de
marquer les billets dj lus en italique (voir la gure 22.4).
Ici cest le XAML qui est sans doute le plus compliqu. Nous avons besoin du contrle
Pivot. Notre contrle Pivot est li la proprit ListeFlux :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <phone:Pivot x:Name="PivotFlux" ItemsSource="{Binding
ListeFlux}" Loaded="PivotFlux_Loaded">
3 <phone:Pivot.HeaderTemplate >
4 <DataTemplate >
5 <TextBlock Text="{Binding Titre}" />
6 </DataTemplate >
7 </controls:Pivot.HeaderTemplate >
8 <phone:Pivot.ItemTemplate >
9 <DataTemplate >
10 <StackPanel >
11 <TextBlock Text="{Binding Titre}"
FontWeight="Bold" FontSize="20" />
12 <ListBox ItemsSource="{Binding ListeBillets
}" SelectionChanged="
ListeBoxBillets_SelectionChanged">
333
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
Figure 22.4 La liste des billets dun ux du lecteur de ux RSS
13 <ListBox.ItemTemplate >
14 <DataTemplate >
15 <TextBlock Text="{Binding Titre
}" Margin="0 0 0 40"
FontStyle="{Binding
EstDejaLu , Converter ={
StaticResource
FontFamilyConverter }}" />
16 </DataTemplate >
17 </ListBox.ItemTemplate >
18 </ListBox >
19 </StackPanel >
20 </DataTemplate >
21 </controls:Pivot.ItemTemplate >
22 </controls:Pivot >
23 </Grid >
Nous nous abonnons galement lvnement de chargement de Pivot. Lentte du
Pivot est lie au titre du ux, via le modle dentte. Quant au corps du Pivot, il
possde un modle o il y a notamment une ListBox, lie la proprit ListeBillets.
Notons que nous nous sommes abonns lvnement de changement de slection de
la ListBox. Le corps de la ListBox consiste lier le titre du billet avec une subtilit
o jutilise un converter pour positionner le style de la police en fonction de si le billet
a dj t lu ou pas. Ce converter devra donc tre dclar dans les ressources :
334
CORRECTION
1 <phone:PhoneApplicationPage.Resources >
2 <converter:FontFamilyConverter x:Key="FontFamilyConverter"
/>
3 </phone:PhoneApplicationPage.Resources >
Avec lespace de nom qui va bien :
1 xmlns:converter="clr -namespace:TpFluxRss"
La classe de conversion devra donc convertir un boolen en FontStyle :
1 public class FontFamilyConverter : IValueConverter
2 {
3 public object Convert(object value , Type targetType , object
parameter , CultureInfo culture)
4 {
5 return (bool)value ? FontStyles.Italic : FontStyles.
Normal;
6 }
7
8 public object ConvertBack(object value , Type targetType ,
object parameter , CultureInfo culture)
9 {
10 throw new NotImplementedException ();
11 }
12 }
Ici, nul besoin dimplmenter la mthode de conversion de FontStyle vers boolen,
elle ne sera pas utilise. La conversion consiste avoir le style italique si le boolen est
vrai, normal sinon. Reste le code-behind :
1 public partial class VoirFluxPivot : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 private ObservableCollection <Flux > listeFlux;
4 public ObservableCollection <Flux > ListeFlux
5 {
6 get { return listeFlux; }
7 set { NotifyPropertyChanged(ref listeFlux , value); }
8 }
9
10 public event PropertyChangedEventHandler PropertyChanged;
11
12 public void NotifyPropertyChanged(string nomPropriete)
13 {
14 if (PropertyChanged != null)
15 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
16 }
17
18 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
335
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
19 {
20 if (object.Equals(variable , valeur)) return false;
21
22 variable = valeur;
23 NotifyPropertyChanged(nomPropriete);
24 return true;
25 }
26
27 public VoirFluxPivot ()
28 {
29 InitializeComponent ();
30 DataContext = this;
31 }
32
33 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
34 {
35 ListeFlux = new ObservableCollection <Flux >((List <Flux >)
PhoneApplicationService.Current.State["ListeFlux"]);
36
37 base.OnNavigatedTo(e);
38 }
39
40 private void PivotFlux_Loaded(object sender ,
RoutedEventArgs e)
41 {
42 PivotFlux.SelectedItem = (Flux)PhoneApplicationService.
Current.State["FluxCourant"];
43 PivotFlux.SelectionChanged +=
PivotFlux_SelectionChanged;
44 }
45
46 private void ListeBoxBillets_SelectionChanged(object sender
, SelectionChangedEventArgs e)
47 {
48 ListBox listBox = (ListBox)sender;
49 if (listBox.SelectedItem != null)
50 {
51 Billet billet = (Billet)listBox.SelectedItem;
52 PhoneApplicationService.Current.State["
BilletCourrant"] = billet;
53 NavigationService.Navigate(new Uri("/VoirBillet.
xaml", UriKind.Relative));
54 listBox.SelectedItem = null;
55 }
56 }
57
58 private void PivotFlux_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
59 {
336
CORRECTION
60 PhoneApplicationService.Current.State["FluxCourant"] =
PivotFlux.SelectedItem;
61 }
62 }
On retrouve notre proprit ListeFlux, ainsi que son implmentation classique. On
peut voir que lors de larrive sur la page, je rcupre dans le dictionnaire dtat la
liste des ux et que je construis une ObservableCollection avec, pour la mettre
dans la proprit ListeFlux. Dans lvnement de chargement du Pivot, jen prote
pour rcuprer le ux courant et ainsi positionner le pivot sur le ux prcdemment
slectionn dans la ListBox. Enn, lors de la slection dun billet dans la ListBox, il
ne me reste plus qu positionner le billet dans le dictionnaire dtat et de naviguer sur
la page VoirBillet.xaml. Sachant que la ListBox est dans un contrle qui possde
plusieurs vues, il nest pas possible dobtenir la ListBox en cours par son nom. En
eet, en fait il y a autant de ListBox que de ux. On utilisera donc le paramtre
sender de lvnement de slection qui nous donne la ListBox concerne. Remarquons
que nous devons modier le ux courant lorsque nous changeons dlment dans le
Pivot. On utilise lvnement de changement de slection auquel on sabonne la n
du chargement du Pivot. On fait ceci une fois que llment en cours est positionn,
an que lvnement ne soit pas lev.
Il ne reste plus que la page VoirBillet.xaml, qui est plutt simple. En tous cas, le
XAML ne contient que le contrle WebBrowser :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
8 <TextBlock x:Name="ApplicationTitle" Text="TP Lecteur
de flux RSS" Style="{StaticResource
PhoneTextNormalStyle}"/>
9 </StackPanel >
10
11 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0"
>
12 <phone:WebBrowser x:Name="PageBillet" NavigationFailed=
"PageBillet_NavigationFailed" />
13 </Grid >
14 </Grid >
Nous nous sommes quand mme abonns lvnement derreur de navigation pour
acher un petit message, au cas o. . . Dans le code-behind, nous aurons juste besoin
de dmarrer la navigation et de marquer le billet comme lu :
1 public partial class VoirBillet : PhoneApplicationPage
2 {
337
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
3 private Billet billet;
4
5 public VoirBillet ()
6 {
7 InitializeComponent ();
8 }
9
10 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
11 {
12 billet = (Billet)PhoneApplicationService.Current.State[
"BilletCourrant"];
13 billet.EstDejaLu = true;
14
15 List <string > dejaLus;
16 if (IsolatedStorageSettings.ApplicationSettings.
Contains("ListeDejaLus"))
17 dejaLus = (List <string >) IsolatedStorageSettings.
ApplicationSettings["ListeDejaLus"];
18 else
19 dejaLus = new List <string >();
20 if (! dejaLus.Any(elt => elt == billet.Id))
21 dejaLus.Add(billet.Id);
22
23 IsolatedStorageSettings.ApplicationSettings["
ListeDejaLus"] = dejaLus;
24 PageBillet.Navigate(billet.Url);
25 base.OnNavigatedTo(e);
26 }
27
28 private void PageBillet_NavigationFailed(object sender ,
System.Windows.Navigation.NavigationFailedEventArgs e)
29 {
30 MessageBox.Show("Impossible de charger la page , v
rifiez votre connexion internet");
31 }
32 }
Noublions pas de faire persister la liste des billets lus dans le rpertoire local. . . Et
voici le rsultat la gure 22.5.
Et voil, notre application commence tre fonctionnelle. Jespre que vous aurez
russi matriser notamment les histoires de binding et de slection dlments. Cest
un travail trs classique dans la cration dapplication Windows Phone avec le XAML.
Ce sont des lments que vous devez matriser. Nhsitez pas refaire ce TP si vous ne
lavez pas compltement russi. Vous pouvez aussi complter cette application qui est
loin dtre parfaite, vous entraner faire des jolies interfaces dans le style Modern UI,
rajouter des transitions, des animations, etc.
338
ALLER PLUS LOIN
Figure 22.5 Achage dun billet dans le lecteur de ux RSS
Aller plus loin
Vous avez remarqu que dans la correction, je ne stocke dans le dictionnaire dtat que
les objets que jai moi-mme crs, savoir les objets Flux et Billet. Vous me direz,
pourquoi ne pas mettre directement les objets SyndicationFeed et SyndicationItem ?
Eh bien pour une bonne raison, ceci introduit un bug pas forcment visible du pre-
mier coup. Ce bug survient lorsque notre application est dsactive, par exemple si
lon reoit un coup de l ou si on ache le menu. Cela vient du fait que les objets
SyndicationFeed et SyndicationItem ne sont pas srialisables, ce qui fait que lors-
quon passe en dsactiv, la srialisation choue et fait planter lapplication. En eet,
le dictionnaire dtat est un emplacement qui est disponible tant que notre application
est dsactive. Il est plus rapide daccs que le rpertoire local, mais ceci implique que
les objets quon y stocke soient srialisables. Pour rsoudre ce point, il sut de ne pas
mettre ces objets dans le dictionnaire dtat et par exemple de mettre plutt direc-
tement nos objets Flux et Billet, comme ce que jai propos en correction. Ceci est
dailleurs plus logique.
Lautre solution est de vider le dictionnaire dtat dans lvnement de dsactivation
de lapplication, avec par exemple :
1 private void Application_Deactivated(object sender ,
DeactivatedEventArgs e)
2 {
3 PhoneApplicationService.Current.State["ListeFlux"] = null;
339
CHAPITRE 22. TP : CRATION DUN LECTEUR DE FLUX RSS SIMPLE
4 }
videmment, il faut re-remplir le dictionnaire dtat dans la mthode dactivation de
lapplication :
1 private void Application_Activated(object sender ,
ActivatedEventArgs e)
2 {
3 // code faire , utilisation du WebClient pour recharger
tous les flux
4 }
Ou alors renvoyer lutilisateur sur la page o seectue ce chargement, en utilisant le
service de navigation.
Vous serez aussi daccord avec moi, lajout de lURL dun ux nest pas des plus
commodes. Si vous voulez approfondir lapplication, vous pouvez galement essayer
dimporter des ux partir dune autre source. . . depuis un autre syndicateur de ux,
partir dun chier OPML - http://fr.wikipedia.org/wiki/Outline_Processor_
Markup_Language.
340
Chapitre 23
Grer lorientation
Dicult :
Jusqu prsent, nous avons toujours utilis notre tlphone (enn, surtout lmulateur)
dans sa position portrait, o les boutons sont orients vers le bas, le tlphone ayant son
ct le plus long dans le sens vertical, droit devant nous. Il peut se tenir aussi horizonta-
lement, en mode paysage. Suivant les cas, les applications sont ges et ne peuvent se
tenir que dans un sens. Dans dautres cas, elles orent la possibilit de tenir son tlphone
dans plusieurs modes, rvlant au passage une interface lgrement dirente. Si on tient le
tlphone en mode paysage, il y a plus de place en largeur, il peut tre pertinent dacher
plus dinformations. . .
341
CHAPITRE 23. GRER LORIENTATION
Les direntes orientations
Lorientation portrait est particulirement adapte la visualisation des listes drou-
lantes pouvant contenir beaucoup dlments. Il devient galement naturel de faire
dler les lments vers le bas. Par contre, en mode paysage, il y a plus de place en
largeur. Si on garde le mme type dachage, il risque dy avoir un gros trou sur la
droite, et la liste dlments deviendra sans doute un peu moins visible. De plus, dans
ce mode-l, il semble plus naturel de faire dler les lments de gauche droite. Et
quel mode portrait adopter quand on tourne son tlphone vers la droite, pour avoir
les boutons gauche ou quand on tourne le tlphone vers la gauche et ainsi avoir les
boutons droite ?
Un tlphone Windows Phone sait dtecter quand il change dorientation. Il est capable
de lever un vnement nous permettant de ragir ce changement dorientation. . . mais
nanticipons pas et revenons la base, la page. Si nous regardons en haut dans les
proprits de la page, nous pouvons voir que nous avons rgulirement cr des pages
qui possdent ces proprits :
1 SupportedOrientations="Portrait" Orientation="Portrait"
Cela indique que lapplication supporte le mode portrait et que la page dmarre en
mode portrait. Il est possible de changer les valeurs de ces proprits. On peut par
exemple aecter les valeurs suivantes la proprit SupportedOrientation :
Portrait
Landscape
PortraitOrLandscape
qui signient respectivement portrait, paysage et portrait-ou-paysage. Ainsi, si lon po-
sitionne cette dernire valeur, lapplication va automatiquement ragir au changement
dorientation. Modions donc cette proprit pour utiliser le mode portrait et paysage :
1 SupportedOrientations="PortraitOrLandscape" Orientation="
Portrait"
et utilisons par exemple le code XAML suivant :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12 ,17,
0,28">
8 <TextBlock x:Name="ApplicationTitle" Text="MON
APPLICATION" Style="{StaticResource
PhoneTextNormalStyle}"/>
9 <TextBlock x:Name="PageTitle" Text="Hello World" Margin
="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
342
LES DIFFRENTES ORIENTATIONS
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0"
>
13 <StackPanel >
14 <TextBlock Text="Bonjour tous" />
15 <Button Content="Cliquez -moi" />
16 </StackPanel >
17 </Grid >
18 </Grid >
Si nous dmarrons lapplication nous obtenons la gure 23.1.
Figure 23.1 Emulateur en mode portrait avec les boutons de lmulateur pour le
faire pivoter
Il est possible de simuler un changement dorientation avec lmulateur, il sut de
cliquer sur les boutons disponibles dans la barre en haut droite de lmulateur, comme
indiqu sur limage du dessus. Lcran est retourn et linterface est automatiquement
adapte la nouvelle orientation, comme vous pouvez le voir la gure 23.2.
Ceci est possible grce la proprit que nous avons ajoute. Les contrles se redes-
sinent automatiquement lors du changement dorientation. Remarquez que lorsquon
retourne le tlphone dans lautre mode paysage, le principe reste le mme.
Ici, le changement dorientation reste globalement lgant. Mais si nous avions utilis
un contrle en positionnement absolu grce un Canvas par exemple, il est fort possible
343
CHAPITRE 23. GRER LORIENTATION
Figure 23.2 Lmulateur en mode paysage
quil se retrouve un emplacement non voulu lors du changement dorientation. Cest
la mme chose avec un StackPanel, peut tre que tous les lments tiennent dans
la hauteur en mode portrait, mais il faudra srement rajouter un ScrollViewer en
mode paysage. . . Par exemple, le XAML suivant en mode portrait semble avoir ses
composants centrs :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12 ,17,
0,28">
8 <TextBlock x:Name="ApplicationTitle" Text="MON
APPLICATION" Style="{StaticResource
PhoneTextNormalStyle}"/>
9 <TextBlock x:Name="PageTitle" Text="Hello World" Margin
="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
>
13 <Canvas >
14 <TextBlock x:Name="MonTextBlock" Text="Bonjour
tous" Canvas.Left="160" />
15 <Button x:Name="MonBouton" Content="Cliquez -moi"
Canvas.Left="140" Canvas.Top="40" />
16 </Canvas >
17 </Grid >
18 </Grid >
Alors que si on le retourne, on peut voir un beau trou droite (voir la gure 23.3).
344
DTECTER LES CHANGEMENTS DORIENTATION
Figure 23.3 Positionnement dcal suivant lorientation
Dtecter les changements dorientation
Il est possible de dtecter le type dorientation dun tlphone en consultant la proprit
Orientation dune page.
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6
7 switch (Orientation)
8 {
9 case PageOrientation.Landscape:
10 case PageOrientation.LandscapeLeft:
11 case PageOrientation.LandscapeRight:
12 MessageBox.Show("Mode paysage");
13 break;
14 case PageOrientation.Portrait:
15 case PageOrientation.PortraitDown:
16 case PageOrientation.PortraitUp:
17 MessageBox.Show("Mode portrait");
18 break;
19 }
20 }
21 }
345
CHAPITRE 23. GRER LORIENTATION
Que lon peut galement simplier de cette faon :
1 if (( Orientation & PageOrientation.Landscape) ==
PageOrientation.Landscape)
2 {
3 MessageBox.Show("Mode paysage");
4 }
5 else
6 {
7 MessageBox.Show("Mode portrait");
8 }
Et, bien souvent plus utile, il est possible dtre noti des changements dorientation.
Cela pourra permettre par exemple de raliser des ajustements. Pour tre prvenu, il
sut de substituer la mthode OnOrientationChanged :
1 protected override void OnOrientationChanged(
OrientationChangedEventArgs e)
2 {
3 switch (e.Orientation)
4 {
5 case PageOrientation.Landscape:
6 case PageOrientation.LandscapeLeft:
7 case PageOrientation.LandscapeRight:
8 // faire des choses pour le mode paysage
9 break;
10 case PageOrientation.Portrait:
11 case PageOrientation.PortraitDown:
12 case PageOrientation.PortraitUp:
13 // faire des choses pour le mode portrait
14 break;
15 }
16 base.OnOrientationChanged(e);
17 }
que lon peut nouveau simplier en :
1 protected override void OnOrientationChanged(
OrientationChangedEventArgs e)
2 {
3 if ((e.Orientation & PageOrientation.Landscape) ==
PageOrientation.Landscape)
4 {
5 // faire des choses pour le mode paysage
6 }
7 else
8 {
9 //faire des choses pour le mode portrait
10 }
11 base.OnOrientationChanged(e);
12 }
346
STRATGIES DE GESTION DORIENTATION
Prenons notre prcdent exemple. Nous pouvons modier les proprits de dpendance
Canvas.Left pour avoir :
1 protected override void OnOrientationChanged(
OrientationChangedEventArgs e)
2 {
3 if ((e.Orientation & PageOrientation.Landscape) ==
PageOrientation.Landscape)
4 {
5 MonTextBlock.SetValue(Canvas.LeftProperty , 320.0);
6 MonBouton.SetValue(Canvas.LeftProperty , 300.0);
7 }
8 else
9 {
10 MonTextBlock.SetValue(Canvas.LeftProperty , 160.0);
11 MonBouton.SetValue(Canvas.LeftProperty , 140.0);
12 }
13 base.OnOrientationChanged(e);
14 }
Ainsi, nous recentrons les contrles chaque changement dorientation.
Stratgies de gestion dorientation
Bien sr, lexemple prcdent est un mauvais exemple, vous laurez compris. La bonne
solution est dutiliser correctement le systme de placement du XAML pour centrer
nos composants, avec uniquement du XAML :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <StackPanel >
3 <TextBlock x:Name="MonTextBlock" Text="Bonjour tous"
HorizontalAlignment="Center" />
4 <Button x:Name="MonBouton" Content="Cliquez -moi"
HorizontalAlignment="Center" />
5 </StackPanel >
6 </Grid >
Mais modier des proprits de contrles permet quand mme de pouvoir faire des
choses intressantes. Prenez lexemple suivant o nous positionnons des contrles dans
une grille :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
347
CHAPITRE 23. GRER LORIENTATION
8 <TextBlock x:Name="ApplicationTitle" Text="MON
APPLICATION" Style="{StaticResource
PhoneTextNormalStyle}"/>
9 <TextBlock x:Name="PageTitle" Text="Hello World" Margin
="9,-7,0,0" Style="{StaticResource
PhoneTextTitle1Style}"/>
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
>
13 <Grid.ColumnDefinitions >
14 <ColumnDefinition Width="*" />
15 <ColumnDefinition Width="*" />
16 <ColumnDefinition Width="*" />
17 </Grid.ColumnDefinitions >
18 <Grid.RowDefinitions >
19 <RowDefinition Height="*" />
20 <RowDefinition Height="*" />
21 <RowDefinition Height="*" />
22 </Grid.RowDefinitions >
23 <Button x:Name="Accueil" Content="Accueil" />
24 <Button Grid.Column="1" x:Name="Cours" Content="Cours"
/>
25 <Button Grid.Column="2" x:Name="MesMPs" Content="Mes
MPs" />
26 <Image x:Name="ImageSdz" Grid.Row="1" Grid.RowSpan="2"
Grid.ColumnSpan="3" Source="http ://open -e-education -
2013.openclassrooms.com/img/logos/logo -
openclassrooms.png" />
27 </Grid >
28 </Grid >
Observez la gure 23.4 pour le rendu.
Nous pouvons utiliser la technique prcdente pour changer la disposition des contrles
dans la grille an de produire un autre rendu en mode paysage. Pour cela, voyez le
code-behind suivant :
1 protected override void OnOrientationChanged(
OrientationChangedEventArgs e)
2 {
3 if ((e.Orientation & PageOrientation.Landscape) ==
PageOrientation.Landscape)
4 {
5 Grid.SetRow(ImageSdz , 0);
6 Grid.SetRow(Accueil , 0);
7 Grid.SetRow(Cours , 1);
8 Grid.SetRow(MesMPs , 2);
9
10 Grid.SetColumn(ImageSdz , 0);
11 Grid.SetColumn(Accueil , 2);
348
STRATGIES DE GESTION DORIENTATION
Figure 23.4 La grille en mode portrait
12 Grid.SetColumn(Cours , 2);
13 Grid.SetColumn(MesMPs , 2);
14
15 Grid.SetRowSpan(ImageSdz , 3);
16 Grid.SetColumnSpan(ImageSdz , 2);
17 }
18 else
19 {
20 Grid.SetRow(ImageSdz , 1);
21 Grid.SetRow(Accueil , 0);
22 Grid.SetRow(Cours , 0);
23 Grid.SetRow(MesMPs , 0);
24
25 Grid.SetColumn(ImageSdz , 0);
26 Grid.SetColumn(Accueil , 0);
27 Grid.SetColumn(Cours , 1);
28 Grid.SetColumn(MesMPs , 2);
29
30 Grid.SetRowSpan(ImageSdz , 2);
31 Grid.SetColumnSpan(ImageSdz , 3);
32 }
33 base.OnOrientationChanged(e);
34 }
349
CHAPITRE 23. GRER LORIENTATION
Ainsi, on dplace les contrles dune colonne lautre, on arrange la fusion de certaines
lignes, etc. Regardez la gure 23.5 pour le rendu.
Figure 23.5 La grille rordonne en mode paysage
Et voil un positionnement compltement dirent, plutt sympathique. Noubliez bien
sr pas de repositionner les contrles en mode portrait galement, sinon ils garderont
la disposition prcdente.
Cependant, il est parfois judicieux de ne pas grer le changement dorientation et de
forcer lapplication une unique orientation. Beaucoup de jeux sont bloqus en mode
paysage et beaucoup dapplications, notamment ds quil y a un panorama ou un pivot
forcent lorientation en portrait. Cest un choix qui peut se justier et il vaut parfois
mieux proposer une exprience utilisateur optimale dans un mode, quune exprience
bancale dans les deux modes. Nous avons vu quil susait de positionner la proprit
SupportedOrientations Portrait ou Landscape. Sachant que ceci peut galement
se faire via le code-behind, si par exemple toute lapplication gre la double orientation,
mais quun cran en particulier peut uniquement tre utilis en mode portrait.
Si vous le pouvez, cest galement trs pratique que vos applications grent direntes
orientations. La solution la plus pratique est dutiliser la mise en page automatique
du XAML, comme ce que nous avons fait en centrant le bouton et la zone de texte
grce la proprit HorizontalAlignement. La premire chose faire est de toujours
utiliser des conteneurs qui peuvent se redimensionner automatiquement, dviter de
xer des largeurs ou des hauteurs et de penser des contrles pouvant faire dler
leur contenu (ListBox, ScrollViewer, etc.). Cela peut par contre parfois donner des
rendus pas toujours esthtiques, avec un bouton qui prend toute la longueur de lcran
par exemple. Pensez-bien au design de vos crans et noubliez pas de tester dans toutes
les orientations possibles. Comme on la dj vu, vous pouvez galement faire vos
ajustements lors de la dtection du changement dorientation. Vous pouvez modier
la hauteur/largeur dun contrle, changer son positionnement, en ajouter un nouveau
ou au contraire, supprimer un contrle qui ne rentre plus. Linconvnient de cette
technique est quelle requiert plus de code et quelle est plus complique mettre en
place avec une approche MVVM.
350
STRATGIES DE GESTION DORIENTATION
Vous pouvez galement rediriger lutilisateur sur une page adapte un mode prcis
lorsquil y a un changement dorientation. Par exemple sur la PagePortrait.xaml :
1 protected override void OnOrientationChanged(
OrientationChangedEventArgs e)
2 {
3 if ((e.Orientation & PageOrientation.Landscape) ==
PageOrientation.Landscape)
4 {
5 NavigationService.Navigate(new Uri("/PagePaysage.xaml",
UriKind.Relative));
6 }
7 base.OnOrientationChanged(e);
8 }
et sur la PagePaysage.xaml :
1 protected override void OnOrientationChanged(
OrientationChangedEventArgs e)
2 {
3 if (!((e.Orientation & PageOrientation.Landscape) ==
PageOrientation.Landscape))
4 {
5 NavigationService.Navigate(new Uri("/PagePortrait.xaml"
, UriKind.Relative));
6 }
7 base.OnOrientationChanged(e);
8 }
Linconvnient est que cela fait empiler beaucoup de pages dans la navigation. Il faut
alors retirer la page prcdente de la pile de navigation. Il sut de rednir la mthode
OnNavigatedTo et dutiliser la mthode RemoveBackEntry :
1 protected override void OnNavigatedTo(NavigationEventArgs e)
2 {
3 NavigationService.RemoveBackEntry ();
4 base.OnNavigatedTo(e);
5 }
Dans le mme style, nous pouvons crer des contrles utilisateurs ddis une orienta-
tion, que nous achons et masquons en fonction de lorientation. Un contrle utilisateur
est un bout de page que nous pouvons rutiliser dans nimporte quelle page. Pour crer
un nouveau contrle utilisateur, on utilise le modle Contrle utilisateur Windows
Phone lors dun clic droit sur le projet, ajouter, nouvel lment (voir la gure 23.6).
Le contrle utilisateur portrait pourra contenir le XAML suivant :
1 <Grid x:Name="LayoutRoot">
2 <StackPanel >
3 <TextBlock Text="Je suis en mode portrait"
HorizontalAlignment="Center" />
4 </StackPanel >
5 </Grid >
351
CHAPITRE 23. GRER LORIENTATION
Figure 23.6 Ajout dun contrle utilisateur
Alors que le contrle utilisateur paysage contiendra :
1 <Grid x:Name="LayoutRoot">
2 <StackPanel >
3 <TextBlock Text="Je suis en mode paysage"
HorizontalAlignment="Center" />
4 </StackPanel >
5 </Grid >
Nous pourrons alors avoir le code-behind suivant dans la page principale :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private ControlePortrait controlePortrait;
4 private ControlePaysage controlePaysage;
5
6 public MainPage ()
7 {
8 InitializeComponent ();
9 controlePortrait = new ControlePortrait ();
10 controlePaysage = new ControlePaysage ();
11
12 ContentPanel.Children.Add(controlePortrait);
13 }
14
15 protected override void OnOrientationChanged(
OrientationChangedEventArgs e)
352
STRATGIES DE GESTION DORIENTATION
16 {
17 if ((e.Orientation & PageOrientation.Landscape) ==
PageOrientation.Landscape)
18 {
19 ContentPanel.Children.Remove(controlePortrait);
20 ContentPanel.Children.Add(controlePaysage);
21 }
22 else
23 {
24 ContentPanel.Children.Remove(controlePaysage);
25 ContentPanel.Children.Add(controlePortrait);
26 }
27 base.OnOrientationChanged(e);
28 }
29 }
Le principe est dinstancier les deux contrles et de les ajouter ou de les retirer la
grille en fonction de lorientation. Linconvnient, comme pour la prcdente stratgie,
est quil faut potentiellement dupliquer pas mal de code dans chacun des contrles.
Enn, nous pouvons utiliser le gestionnaire dtat. De la mme faon que nous lavons
vu dans la partie prcdente pour les contrles, une page peut avoir plusieurs tats.
Il sut de considrer que ltat normal est celui en mode portrait et que nous allons
crer un tat pour le mode paysage. Pour cela, le plus simple est dutiliser Blend.
Dmarrons-le et commenons crer notre page (voir la gure 23.7).
Figure 23.7 Page portrait dans Blend
353
CHAPITRE 23. GRER LORIENTATION
qui correspond au XAML suivant :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0">
2 <TextBlock Text="Mode Portrait" HorizontalAlignment="Center
" />
3 <Button Content="Cliquez -moi" Width="200" VerticalAlignment
="Bottom" HorizontalAlignment="Right" />
4 </Grid >
Maintenant, nous allons crer un nouvel tat. Slectionnez la page dans larbre visuel
(en bas gauche) puis dans longlet tat, cliquez sur le petit bouton droite permettant
dajouter un groupe dtat, comme indiqu sur la gure 23.8.
Figure 23.8 Ajout dun groupe dtat dans Blend
Nous pouvons le nommer par exemple EtatsOrientations.
Avant de pouvoir crer un tat propre au mode paysage, nous allons positionner le
designer en mode paysage. Pour cela il faut aller dans longlet Appareil qui est un peu
plus droite que longlet tats et basculer en landscape (voir la gure 23.9).
Revenez dans longlet tat, et cliquez prsent droite sur ajouter un tat , comme
indiqu la gure 23.10.
Nous pouvons appeler ce nouvel tat ModePaysage (voir la gure 23.11).
Nous pouvons voir que ltat est en mode enregistrement, cest--dire que nous al-
lons pouvoir maintenant modier la position des contrles pour crer notre cran en
mode paysage. Changez la disposition et changez la proprit Text du TextBlock pour
acher Mode paysage, comme indiqu la gure 23.12.
354
STRATGIES DE GESTION DORIENTATION
Figure 23.9 Passer en mode paysage dans Blend
Figure 23.10 Ajout dun tat dans Blend
355
CHAPITRE 23. GRER LORIENTATION
Figure 23.11 Ajout dun tat dans Blend
Figure 23.12 Modication de la disposition des contrles en mode paysage
356
STRATGIES DE GESTION DORIENTATION
Vous pouvez maintenant sauvegarder vos modications, fermer Blend et revenir dans
Visual Studio. Remarquons que Blend nous a modi notre XAML, notamment pour
rajouter de quoi faire une animation des contrles :
1 <TextBlock x:Name="textBlock" Text="Mode Portrait"
HorizontalAlignment="Center" RenderTransformOrigin="0.5,0.5"
>
2 <TextBlock.RenderTransform >
3 <CompositeTransform/>
4 </TextBlock.RenderTransform >
5 </TextBlock >
6 <Button x:Name="button" Content="Cliquez -moi" Width="200"
VerticalAlignment="Bottom" HorizontalAlignment="Right"
RenderTransformOrigin="0.5,0.5" >
7 <Button.RenderTransform >
8 <CompositeTransform/>
9 </Button.RenderTransform >
10 </Button >
De mme, il a rajout de quoi grer les tats :
1 <VisualStateManager.VisualStateGroups >
2 <VisualStateGroup x:Name="EtatsOrientations">
3 <VisualState x:Name="ModePaysage">
4 <Storyboard >
5 <DoubleAnimation Duration="0" To="-254"
Storyboard.TargetProperty="(
UIElement.RenderTransform).(
CompositeTransform.TranslateX)"
Storyboard.TargetName="textBlock" d:
IsOptimized="True"/>
6 <DoubleAnimation Duration="0" To="182"
Storyboard.TargetProperty="(
UIElement.RenderTransform).(
CompositeTransform.TranslateY)"
Storyboard.TargetName="textBlock" d:
IsOptimized="True"/>
7 <ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="(
TextBlock.Text)" Storyboard.
TargetName="textBlock">
8 <DiscreteObjectKeyFrame KeyTime
="0" Value="Mode Paysage"/>
9 </ObjectAnimationUsingKeyFrames >
10 <DoubleAnimation Duration="0" To="-300"
Storyboard.TargetProperty="(
UIElement.RenderTransform).(
CompositeTransform.TranslateX)"
Storyboard.TargetName="button" d:
IsOptimized="True"/>
357
CHAPITRE 23. GRER LORIENTATION
11 <DoubleAnimation Duration="0" To="-208"
Storyboard.TargetProperty="(
UIElement.RenderTransform).(
CompositeTransform.TranslateY)"
Storyboard.TargetName="button" d:
IsOptimized="True"/>
12 </Storyboard >
13 </VisualState >
14 </VisualStateGroup >
15 </VisualStateManager.VisualStateGroups >
Nous pouvons constater quil sopre des changements de coordonnes via transla-
tions, ainsi que la modication du texte du TextBlock. cet tat, ajoutons un tat
ModePortrait vide pour signier ltat de dpart, le plus simple ici est de le faire dans
le XAML, avec :
1 <VisualStateGroup x:Name="EtatsOrientations">
2 <VisualState x:Name="ModePortrait" />
3 <VisualState x:Name="ModePaysage">
4 <Storyboard >
5 ...
6 </Storyboard >
7 </VisualState >
8 </VisualStateGroup >
Enn, vous allez avoir besoin dindiquer que vous grez le multi-orientation et que vous
dmarrez en mode portrait avec :
1 SupportedOrientations="PortraitOrLandscape" Orientation="
Portrait"
Puis maintenant, il faudra ragir un changement dorientation et modier ltat de
la page grce au VisualStateManager :
1 protected override void OnOrientationChanged(
OrientationChangedEventArgs e)
2 {
3 if ((e.Orientation & PageOrientation.Landscape) ==
PageOrientation.Landscape)
4 {
5 VisualStateManager.GoToState(this , "ModePaysage", true)
;
6 }
7 else
8 {
9 VisualStateManager.GoToState(this , "ModePortrait", true
);
10 }
11
12 base.OnOrientationChanged(e);
13 }
358
STRATGIES DE GESTION DORIENTATION
Maintenant, vous pouvez changer lorientation de lmulateur ; vous pouvez voir le
rendu la gure 23.13.
Figure 23.13 Changement dtat de la page lors du changement dorientation
Et voil !
Si vous dcidez de grer les deux orientations dans votre application, cest
une bonne ide de prvoir une conguration permettant de ger lorientation
dans un unique sens. Par exemple, il est trs dsagrable de voir son cran
se tourner quand on utilise son tlphone en position allong. Pouvoir ger
lorientation la demande de lutilisateur savre tre un plus pour les pauvres
utilisateurs fatigus ou alits.
En rsum
Un tlphone sait dtecter les changements dorientation, ainsi une application
peut sexcuter en mode portrait ou en mode paysage.
Pour tre averti dun changement dorientation, il sut de rednir la mthode
OnOrientationChanged.
Il faut toujours tester fond notre application avec direntes orientations si
lon souhaite grer le changement dorientation.
359
CHAPITRE 23. GRER LORIENTATION
360
Chapitre 24
Grer les multiples rsolutions
Dicult :
Alors que Windows Phone 7.X ne supportait que des tlphones ayant la rsolution 480x800,
Windows Phone 8 permet maintenant de supporter 3 rsolutions. Ceci est un avantage pour
les utilisateurs qui peuvent ainsi avoir des tlphones avec des rsolutions direntes, mais
cela devient un inconvnient pour le dveloppeur qui doit maintenant faire en sorte que son
application fonctionne pour toutes les rsolutions des appareils.
Voyons maintenant ce quil faut savoir.
361
CHAPITRE 24. GRER LES MULTIPLES RSOLUTIONS
Les direntes rsolutions
Windows Phone 8 supporte trois rsolutions :
Rsolution Taille Format
WVGA 480x800 15/9
WXGA 768x1280 15/9
720p 720x1280 16/9
Cest aussi le cas de lmulateur, que nous pouvons dmarrer suivant plusieurs rsolu-
tions, en la changeant dans la liste droulante, comme indiqu sur la gure 24.1.
Figure 24.1 Les direntes rsolutions de lmulateur
Voici prsent le mme cran prsent dans les 3 direntes rsolutions, avec de gauche
droite WVGA, WXGA et 720P (voir la gure 24.2).
Pour raliser cet exemple, je me suis servi dun contrle du Windows Phone
Toolkit que nous allons dcouvrir dans quelques chapitres : le WrapPanel.
Jai positionn une srie de boutons qui font tous 90 pixels de longueur et de
largeur.
La premire chose remarquer est que le rendu est le mme entre la rsolution WVGA
et WXGA, nonobstant la dirence de rsolution. En eet, le format tant le mme,
savoir du 15/9 ime, Windows Phone prend automatiquement en charge la mise
lchelle de la page et ramne nalement la rsolution 768x1280 une taille de 480x800.
Ce nest par contre pas le cas pour la rsolution 720p, qui est du 16/9 ime, et o la
mise lchelle automatique donne du 480x853. On peut voir en eet sur la copie
dcran que nous avons un peu plus de choses qui sont achs en bas du 720p.
Grer plusieurs rsolutions
Alors, comment grer toutes ces belles rsolutions ?
Vous aurez srement devin que cest grosso modo le mme principe que pour les
direntes orientations. Il y a plusieurs techniques pour grer les rsolutions :
362
GRER PLUSIEURS RSOLUTIONS
Figure 24.2 Le mme cran dans les trois rsolutions
Utiliser le redimensionnement automatique des contrles, nhsitez pas utiliser
ltoile (*) dans les grilles ou la valeur auto, les alignements centrs, etc.
Faire un ajustement avec le code-behind.
Rediriger vers les bonnes pages ou utiliser les bons contrles utilisateurs en
fonction de la rsolution.
Modier ltat de la page en fonction de la rsolution.
. . .
La seule dirence est quil ne faut pas le faire en rception un vnement de chan-
gement de taille, car en eet il est trs rare quun tlphone puisse changer de taille
dcran en cours dutilisation. Par contre, il est possible de dtecter la rsolution au
lancement de lapplication an de faire les ajustements adquats. Il sut dutiliser les
proprits prsentes dans Application.Current.Host.Content, comme :
ActualHeight qui donne la hauteur de lcran
ActualWidth qui donne la largeur de lcran
ScaleFactor qui donne le facteur dchelle
Et nous aurons pour chaque rsolution, les valeurs suivantes :
Ces valeurs vont donc nous permettre de dtecter la rsolution du tlphone.
363
CHAPITRE 24. GRER LES MULTIPLES RSOLUTIONS
Rsolution Hauteur Largeur Facteur dchelle
WVGA 800 480 100
WXGA 800 480 160
720p 853 480 150
Les images
tant donn que nous avons direntes rsolutions, il se pose la question des images.
Mon image va-t-elle tre jolie dans toutes les rsolutions ? La premire ide tentante
serait dinclure 3 images direntes, chacune optimise pour une rsolution dcran.
Nous pourrions alors crire un petit helper qui nous dtecterait la rsolution et nous
permettrait de mettre la bonne image au bon moment :
1 public static class ResolutionHelper
2 {
3 public static bool EstWvga
4 {
5 get { return Application.Current.Host.Content.
ActualHeight == 800 && Application.Current.Host.
Content.ScaleFactor == 100; }
6 }
7
8 public static bool EstWxga
9 {
10 get { return Application.Current.Host.Content.
ScaleFactor == 160; }
11 }
12
13 public static bool Est720p
14 {
15 get { return Application.Current.Host.Content.
ScaleFactor == 150; }
16 }
17 }
Il serait ainsi facile de charger telle ou telle image en fonction de la rsolution :
1 if (ResolutionHelper.EstWvga)
2 MonImage.Source = new BitmapImage(new Uri("/Assets/Images/
Wvga/fond.png", UriKind.Relative));
3 if (ResolutionHelper.EstWxga)
4 MonImage.Source = new BitmapImage(new Uri("/Assets/Images/
Wxga/fond.png", UriKind.Relative));
5 if (ResolutionHelper.Est720p)
6 MonImage.Source = new BitmapImage(new Uri("/Assets/Images/
720p/fond.png", UriKind.Relative));
Cest une bonne solution sauf que cela augmentera considrablement la taille de notre
.xap et la consommation mmoire de notre application. tant donn que le facteur est
364
LES IMAGES
le mme entre WVGA et WXGA, il est possible de ninclure que les images optimises
pour la rsolution WXGA et de laisser le systme redimensionner automatiquement
les images pour la rsolution WVGA. De mme, si on peut faire en sorte de ne pas
inclure dimages en 720p et que ce soit la mise en page qui soit lgrement dirente
pour cette rsolution, cest toujours une image en moins de gagne dans le .xap nal
et en mmoire dans lapplication. Cependant, il peut parfois tre justi dinclure les
images en direntes rsolutions et dutiliser notre petit helper.
noter que nous pouvons utiliser notre helper pour choisir la bonne image dans le
XAML galement. Crons une nouvelle classe :
1 public class ChoisisseurImage
2 {
3 public Uri MonImageDeFond
4 {
5 get
6 {
7 if (ResolutionHelper.EstWxga)
8 return new Uri("/Assets/Images/Wxga/fond.png",
UriKind.Relative);
9 if (ResolutionHelper.Est720p)
10 return new Uri("/Assets/Images/720p/fond.png",
UriKind.Relative);
11 return new Uri("/Assets/Images/Wvga/fond.png",
UriKind.Relative);
12 }
13 }
14
15 public Uri ImageRond
16 {
17 get
18 {
19 if (ResolutionHelper.EstWxga)
20 return new Uri("/Assets/Images/Wxga/rond.png",
UriKind.Relative);
21 if (ResolutionHelper.Est720p)
22 return new Uri("/Assets/Images/720p/rond.png",
UriKind.Relative);
23 return new Uri("/Assets/Images/Wvga/rond.png",
UriKind.Relative);
24 }
25 }
26 }
Que nous allons dclarer en ressources de notre application :
1 <Application
2 x:Class="DemoResolution.App"
3 ...
4 xmlns:local="clr -namespace:DemoResolution">
5
365
CHAPITRE 24. GRER LES MULTIPLES RSOLUTIONS
6 <Application.Resources >
7 <local:ChoisisseurImage x:Key="ChoisisseurImageResource
"/>
8 </Application.Resources >
9
10 [...]
11 </Application >
Ainsi, nous pourrons utiliser cette ressource dans le XAML :
1 <Image Source="{Binding MonImageDeFond , Source ={ StaticResource
ChoisisseurImageResource }}"/>
2 <Image Source="{Binding ImageRond , Source ={ StaticResource
ChoisisseurImageResource }}"/>
Limage de lcran daccueil
Vous vous rappelez que nous avons vu comment ajouter une image pour notre cran
daccueil, le fameux splash screen ? Vous pouvez galement fournir des images de splash
screen dans direntes rsolutions, il sut dutiliser trois images dans les bonnes rso-
lutions portant ces noms :
SplashScreenImage.Screen-WVGA.jpg
SplashScreenImage.Screen-WXGA.jpg
SplashScreenImage.Screen-720p.jpg
Vous devez quand mme garder limage SplashScreenImage.jpg qui est limage par
dfaut.
En rsum
Windows Phone 8 apporte 3 rsolutions direntes que nous devons grer en
tant que dveloppeur pour orir la meilleure qualit dapplication possible.
Les direntes stratgies pour grer les rsolutions multiples sont les mmes que
pour grer les direntes orientations.
Il est possible dutiliser des images de direntes rsolutions dans son application
mais gardez lesprit quelles occuperont de la mmoire et augmenteront la taille
du .xap.
366
Chapitre 25
Lapplication Bar
Dicult :
Nous ne lavons pas encore vue, mais vous la connaissez srement si vous possdez un
tlphone quip de Windows Phone. La barre dapplication, si elle est prsente, est situe
en bas de lcran et possde des boutons que nous pouvons cliquer. Elle fait oce plus ou
moins de menu, accessible tout le temps, un peu comme le menu en haut des fentres qui
existaient sur nos vieilles applications Windows.
Elle peut savrer trs pratique et est plutt simple daccs, deux bonnes raisons pour
pousser un peu plus loin sa dcouverte.
367
CHAPITRE 25. LAPPLICATION BAR
Prsentation et utilisation
Si vous utilisez le SDK pour Windows Phone 7, vous lavez srement dj vue dans le
code XAML sans vraiment y faire attention. Il y a un exemple dutilisation comment
dans chaque nouvelle page cre :
1 <!--Exemple de code illustrant l'utilisation d'ApplicationBar
-->
2 <phone:PhoneApplicationPage.ApplicationBar >
3 <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"
>
4 <shell:ApplicationBarIconButton IconUri="/Images/
appbar_button1.png" Text="Bouton 1"/>
5 <shell:ApplicationBarIconButton IconUri="/Images/
appbar_button2.png" Text="Bouton 2"/>
6 <shell:ApplicationBar.MenuItems >
7 <shell:ApplicationBarMenuItem Text="lmentMenu 1"
/>
8 <shell:ApplicationBarMenuItem Text="lmentMenu 2"
/>
9 </shell:ApplicationBar.MenuItems >
10 </shell:ApplicationBar >
11 </phone:PhoneApplicationPage.ApplicationBar >
Si vous d-commentez ces lignes ou que vous les recopiez dans votre page Windows
Phone 8, que vous dmarrez lmulateur, vous aurez la gure 25.1.
La barre dapplication est bien sr ce que jai encadr en rouge. Ce XAML doit tre
au mme niveau que la page, cest--dire hors du conteneur racine :
1 <phone:PhoneApplicationPage
2 x:Class="DemoBarreApplication.MainPage"
3 ...>
4
5 <Grid x:Name="LayoutRoot" Background="Transparent">
6 ...
7 </Grid >
8
9 <phone:PhoneApplicationPage.ApplicationBar >
10 ...
11 </phone:PhoneApplicationPage.ApplicationBar >
12 </phone:PhoneApplicationPage >
Le XAML est plutt facile comprendre. On constate que la barre est visible, que le
menu est activ et quelle possde deux boutons, bouton 1 et bouton 2 , ainsi
que deux lments de menu, lmentMenu 1 et lmentMenu 2 . Pour acher
les lments de menu, il faut cliquer sur les trois petits points en bas droite. Cela
permet galement de voir le texte associ un bouton, comme vous pouvez le voir sur
la gure 25.2.
368
PRSENTATION ET UTILISATION
Figure 25.1 Achage de la barre dapplication
Figure 25.2 Les lments de menu de la barre
369
CHAPITRE 25. LAPPLICATION BAR
Par contre, nos images ne sont pas trs jolies. En eet, le code XAML fait rfrence
des images qui nexistent pas dans notre solution. La croix ache reprsente donc
labsence dimage. Ces images sont des icnes. Elles sont toujours visibles sur la barre
dapplication alors que ce nest pas forcment le cas des lments de menu. Il est
donc primordial que ces icnes soient les plus reprsentatives possibles, car pour voir la
lgende de licne, il faut cliquer sur les trois petits points permettant dacher la suite
de la barre. Les icnes doivent avoir la taille de 48x48, sachant que le cercle est ajout
automatiquement en surimpression par Windows Phone. Cela implique que la zone
visible de votre icne doit tre de 26x26 au centre de licne. Enn, licne doit tre de
couleur blanche, sur fond transparent. Cest un look trs Modern UI que nous impose
Microsoft an de privilgier la smantique du dessin plutt que sa beaut. Pour nous
aider, Microsoft propose un pack dicne Modern UI que nous pouvons librement
utiliser dans nos applications. Ce pack a t install avec le SDK de Windows Phone,
vous pouvez le retrouver cet emplacement : C:\Program Files (x86)\Microsoft
SDKs\Windows Phone\v8.0\Icons.
Vous pouvez voir quil y a plusieurs rpertoires. Vous navez qu vous soucier
du rpertoire dark qui correspond au thme fonc. Windows Phone utilise
automatiquement la bonne image en fonction du thme slectionn.
Maintenant, ajoutons deux images notre application, disons delete.png et edit.png.
Pour ce faire, crez par exemple un rpertoire Icones sous le rpertoire Assets et
ajoutez les icnes dedans en ajoutant un lment existant. Ensuite, dans la fentre de
proprits, modiez laction de gnration en Contenu ainsi que la copie dans le
rpertoire de sortie en copier si plus rcent . Modiez ensuite le XAML pour utiliser
nos nouvelles icnes :
1 <phone:PhoneApplicationPage.ApplicationBar >
2 <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"
>
3 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/delete.png" Text="Supprimer"/>
4 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/edit.png" Text="Modifier"/>
5 <shell:ApplicationBar.MenuItems >
6 <shell:ApplicationBarMenuItem Text="lmentMenu 1"
/>
7 <shell:ApplicationBarMenuItem Text="lmentMenu 2"
/>
8 </shell:ApplicationBar.MenuItems >
9 </shell:ApplicationBar >
10 </phone:PhoneApplicationPage.ApplicationBar >
Et voil la gure 25.3 le beau rsultat !
La barre dapplication est positionne en bas de lcran, juste au-dessus des trois bou-
tons physiques. On ne peut pas la changer de place, mais elle sait cependant sorienter
diremment suivant lorientation du tlphone. Par exemple dans la gure 25.4, en
mode paysage, nous pouvons voir la rotation des images et du texte.
370
PRSENTATION ET UTILISATION
Figure 25.3 Utilisation des icnes de la barre dapplication
Figure 25.4 La barre dapplication subit une rotation lors du changement dorien-
tation du tlphone
371
CHAPITRE 25. LAPPLICATION BAR
Il faudra bien sr au pralable faire en sorte que la page supporte les deux orientations
comme nous lavons vu dans un chapitre prcdent.
Remarquez quon ne peut avoir que 4 boutons dans la barre dapplication. Si
vous tentez den mettre plus, vous aurez une exception.
Bon, une barre avec des boutons cest bien, mais si on pouvait cliquer dessus pour
faire des choses, a serait pas plus mal non? Rien de plus simple, vous pouvez ajouter
lvnement de clic sur un bouton ou sur un lment de menu :
1 <phone:PhoneApplicationPage.ApplicationBar >
2 <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"
>
3 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/delete.png" Text="Supprimer" Click="
ApplicationBarIconButton_Click_1"/>
4 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/edit.png" Text="Modifier"/>
5 <shell:ApplicationBar.MenuItems >
6 <shell:ApplicationBarMenuItem Text="lmentMenu 1"
Click="ApplicationBarMenuItem_Click_1"/>
7 <shell:ApplicationBarMenuItem Text="lmentMenu 2"
/>
8 </shell:ApplicationBar.MenuItems >
9 </shell:ApplicationBar >
10 </phone:PhoneApplicationPage.ApplicationBar >
Ici, nous utilisons lvnement Click, il nexiste pas dvnement Tap pour
la barre dapplication.
Avec :
1 private void ApplicationBarIconButton_Click_1(object sender ,
EventArgs e)
2 {
3 MessageBox.Show("Voulez -vous vraiment supprimer ?", "
Suppression", MessageBoxButton.OKCancel);
4 }
5
6 private void ApplicationBarMenuItem_Click_1(object sender ,
EventArgs e)
7 {
8 MessageBox.Show("Menu !");
9 }
Observez la gure 25.5 pour le rendu.
372
PRSENTATION ET UTILISATION
Figure 25.5 Le clic sur un bouton de menu dclenche lachage du message
On peut jouer sur les proprits de la barre dapplication. Citons par exemple sa pro-
prit IsVisible qui permet de la rendre visible ou invisible. Citons encore la proprit
Opacity qui permet dacher des contrles sous la barre dapplication, par exemple
avec le XAML suivant :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,
0,28">
8 <TextBlock Text="MON APPLICATION" Style="{
StaticResource PhoneTextNormalStyle}" Margin="12,0"
/>
9 <TextBlock Text="nom de la page" Margin="9,-7,0,0"
Style="{StaticResource PhoneTextTitle1Style}"/>
10 </StackPanel >
11
12 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0"
>
13 <Canvas >
14 <TextBlock Text="Je suis cach" Foreground="Red"
FontSize="50" Canvas.Top="500" />
373
CHAPITRE 25. LAPPLICATION BAR
15 </Canvas >
16 </Grid >
17 </Grid >
18
19 <phone:PhoneApplicationPage.ApplicationBar >
20 <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"
>
21 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/delete.png" Text="Supprimer" Click="
ApplicationBarIconButton_Click_1"/>
22 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/edit.png" Text="Modifier"/>
23 <shell:ApplicationBar.MenuItems >
24 <shell:ApplicationBarMenuItem Text="lmentMenu 1"
Click="ApplicationBarMenuItem_Click_1"/>
25 <shell:ApplicationBarMenuItem Text="lmentMenu 2"
/>
26 </shell:ApplicationBar.MenuItems >
27 </shell:ApplicationBar >
28 </phone:PhoneApplicationPage.ApplicationBar >
Si vous dmarrez lapplication, le texte rouge est invisible car il est derrire la barre
dapplication. Si vous changez lopacit en mettant par exemple 0.5 :
1 <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"
Opacity="0.5">
le texte apparatra sous la barre dapplication (voir la gure 25.6).
Pour les boutons, on peut remarquer en plus la proprit IsEnabled qui permet de
dsactiver ou dactiver un bouton. Il est bien sr possible de manipuler la barre dap-
plication par le code-behind, via la proprit ApplicationBar. Par exemple, je peux
rendre invisible la barre dapplication de cette faon :
1 ApplicationBar.IsVisible = false;
Ou modier le texte du premier bouton :
1 (( ApplicationBarIconButton)ApplicationBar.Buttons[0]).Text = "
Changement dynamqiue";
Pour les lments de menu, le principe est le mme que pour les boutons.
Notons juste quil est possible de sabonner un vnement qui permet de savoir si ltat
de la barre change, cest--dire quand les lments de menu sont achs ou non. Cela
permet par exemple de faire en sorte que certaines infos soient aches diremment
si jamais le menu les cache. Il sagit de lvnement StateChanged :
1 private void ApplicationBar_StateChanged(object sender ,
ApplicationBarStateChangedEventArgs e)
2 {
3 if (e.IsMenuVisible)
4 {
374
PRSENTATION ET UTILISATION
Figure 25.6 Utilisation de lopacit sur la barre dapplication
5 // ...
6 }
7 }
Enn, remarquons une dernire petite chose qui peut-tre vous a intrigu. Il sagit de
lendroit dans le XAML o est dnie la barre dapplication :
1 <phone:PhoneApplicationPage
2 ...>
3
4 <Grid x:Name="LayoutRoot" Background="Transparent">
5 ...
6 </Grid >
7
8 <phone:PhoneApplicationPage.ApplicationBar >
9 ...
10 </phone:PhoneApplicationPage.ApplicationBar >
11 </phone:PhoneApplicationPage >
Jen ai parl un peu en haut mais vous avez vu? Elle est au mme niveau que la grille !
Alors que nous avons dit quun seul conteneur racine tait autoris. Cest parce que
lobjet ApplicationBar ne drive pas de FrameworkElement, pour notre plus grand
malheur dailleurs. La proprit ApplicationBar de la PhoneApplicationPage est une
proprit de dpendance : http://msdn.microsoft.com/fr-fr/library/microsoft.
375
CHAPITRE 25. LAPPLICATION BAR
phone.controls.phoneapplicationpage.applicationbarproperty(v=vs.92). Cest
pour cela que nous pouvons (et dailleurs devons !) la mettre au niveau de la page.
Attention : il est recommand de ne pas avoir de trop long textes dans les
lments de menu, entre 14 et 20 caractres.
Appliquer le Databinding
tant donn que notre barre dapplication nest pas un FrameworkElement, elle ne
sait pas grer la liaison de donnes. Il nest donc pas possible dutiliser les extensions
de balisage {Binding} ni les commandes sur cet lment. Ce qui pose un problme
lorsque lon fait du MVVM ou mme quand il sagit de traduire notre application. Il
y a cependant une petite astuce pour rendre notre barre application fonctionnelle avec
la liaison de donnes ainsi quavec le systme de commandes. Il sut de dvelopper
une nouvelle classe qui encapsule les fonctionnalits de la classe ApplicationBar. On
appelle communment ce genre de classe un wrapper.
Nous nallons pas faire cet exercice ici vu que dautres personnes lont dj fait pour
nous. Cest le cas par exemple de la bibliothque BindableApplicationBar que nous
pouvons trouver cet emplacement : http://bindableapplicationb.codeplex.com/.
Vous pouvez tlcharger cette bibliothque ou tout simplement utiliser NuGet (voir la
gure 25.7).
Il ne reste plus qu importer lespace de nom suivant :
1 xmlns:barre="clr -namespace:BindableApplicationBar;assembly=
BindableApplicationBar"
et modier notre barre comme suit :
1 <barre:Bindable.ApplicationBar >
2 <barre:BindableApplicationBar IsVisible="{Binding
EstBarreVisible}">
3 <barre:BindableApplicationBarButton Command="{Binding
SupprimerCommand}" Text="{Binding SupprimerText}"
IconUri="/Assets/Icones/delete.png" />
4 <barre:BindableApplicationBar.MenuItems >
5 <barre:BindableApplicationBarMenuItem Text="{
Binding ElementText}" Command="{Binding
ElementCommand}" />
6 </barre:BindableApplicationBar.MenuItems >
7 </barre:BindableApplicationBar >
8 </barre:Bindable.ApplicationBar >
Notons la liaison de donnes sur la proprit IsVisible de la barre dapplication, de
la proprit Text du bouton ainsi que lutilisation dune commande lors du clic sur le
bouton. Nous aurons donc un contexte qui pourra tre :
376
APPLIQUER LE DATABINDING
Figure 25.7 Utilisation de NuGet pour tlcharger la barre dapplication bindable
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 public event PropertyChangedEventHandler PropertyChanged;
4
5 public void NotifyPropertyChanged(string nomPropriete)
6 {
7 if (PropertyChanged != null)
8 PropertyChanged(this , new PropertyChangedEventArgs(
nomPropriete));
9 }
10
11 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
12 {
13 if (object.Equals(variable , valeur)) return false;
14
15 variable = valeur;
16 NotifyPropertyChanged(nomPropriete);
17 return true;
18 }
19
20 private bool estBarreVisible;
21 public bool EstBarreVisible
377
CHAPITRE 25. LAPPLICATION BAR
22 {
23 get { return estBarreVisible; }
24 set { NotifyPropertyChanged(ref estBarreVisible , value)
; }
25 }
26
27 public string SupprimerText
28 {
29 get { return "Supprimer"; }
30 }
31
32 public string ElementText
33 {
34 get { return "Elment"; }
35 }
36
37 public ICommand SupprimerCommand { get; set; }
38 public ICommand ElementCommand { get; set; }
39
40 public MainPage ()
41 {
42 InitializeComponent ();
43 SupprimerCommand = new RelayCommand(OnSupprimer);
44 ElementCommand = new RelayCommand(OnElement);
45 EstBarreVisible = true;
46
47 DataContext = this;
48 }
49
50 private void OnSupprimer ()
51 {
52 MessageBox.Show("Voulez -vous vraiment supprimer ?", "
Suppression", MessageBoxButton.OKCancel);
53 }
54
55 private void OnElement ()
56 {
57 EstBarreVisible = false;
58 }
59 }
Notez que vous aurez besoin dune classe RelayCommand, venant de votre framework
MVVM prfr ou bien lexemple simple que nous avons cr prcdemment. Grce
cette classe, nous pouvons dsormais respecter correctement le pattern MVVM, chose
qui tait plus dicile sans.
Le framework Ultralight MVVM que nous avons cit dans un chapitre pr-
cdent propose une solution pour grer la liaison de donnes avec la barre
dapplication.
378
MODE PLEIN CRAN
Mode plein cran
Vous avez d remarquer quil y a tout en haut de lcran, un petit bout qui est rserv
lachage de la batterie, de la qualit de la connexion, etc. Il sagit de la barre systme.
Ce nest pas vraiment la barre dapplication, mais je trouve quil est pertinent den
parler ici. Il nest pas possible de modier le contenu de la barre systme, mais il est
par contre possible de la masquer an davoir un mode plein cran , grce une
proprit. Cette proprit est positionne vrai par dfaut lorsque lon cre un nouvelle
page XAML, elle rend la barre systme visible :
1 <phone:PhoneApplicationPage
2 ...
3 shell:SystemTray.IsVisible="True"
Nous pouvons modier ici sa valeur en mettant False. Ou bien par code, en utili-
sant la classe statique SystemTray - http://msdn.microsoft.com/en-us/library/
microsoft.phone.shell.systemtray(v=vs.92).aspx :
1 SystemTray.IsVisible = false;
Cela permet de rcuprer 16 pixels en hauteur. Vous aurez besoin dinclure lespace de
nom suivant :
1 using Microsoft.Phone.Shell;
Attention cependant, ce nest pas toujours pertinent de masquer cette barre
systme car elle fournit des informations intressantes. Personnellement,
lorsque je dois tre connect internet, jaime bien vrier la force du si-
gnal histoire de savoir sil vaut mieux relancer la requte, ou tout simplement
pour avoir lheure. . . utiliser judicieusement.
En rsum
La barre dapplication est un contrle utile lorsquil y a besoin de faire des
actions rcurrentes dans une application.
Elle fonctionne un peu comme un menu, accessible de partout.
Ne supportant pas la liaison de donnes par dfaut, il est possible dutiliser des
wrappers pour la rendre fonctionnelle avec le binding.
Il est recommand de ne pas masquer la barre systme, mais cest cependant
possible pour passer en mode plein cran.
379
CHAPITRE 25. LAPPLICATION BAR
380
Chapitre 26
Le toolkit Windows Phone
Dicult :
Bien que dj bien fournis, les contrles Windows Phone ne font pas tout. Nous avons
dj vu des bibliothques tierces, comme le MVVM Light toolkit qui permet de faire en
sorte que son application respecte plus facilement le patron de conception MVVM. Nous
avons galement utilis une bibliothque qui permet dutiliser le binding avec la barre
dapplication.
Il existe dautres bibliothques bien pratiques contenant des contrles volus qui vont
nous permettre denrichir nos applications et dorir avec le moindre eort une exprience
utilisateur des plus sympathiques.
En plus, il y en a qui sont gratuites, alors pourquoi sen priver ?
381
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
Prsentation et installation du toolkit Windows Phone
La bibliothque la plus connue est sans nul doute le Toolkit pour Windows Phone. Il
sagit dun projet trs suivi qui contient beaucoup de contrles pour Windows Phone.
Historiquement, ce toolkit proposait dj toute une gamme de contrles supplmen-
taires pour Silverlight. Depuis la sortie de Silverlight pour Windows Phone 7.X, cest
tout naturellement quune bibliothque parallle, ddie Windows Phone, a vu le
jour. Et aujourdhui, avec larrive de Windows Phone 8, il en existe une version pour
lui.
Comme beaucoup de bibliothques, elle est open-source, utilisable dans beaucoup de
situations mais pas toujours exempte de bug. Il y a tout une communaut qui travaille
sur ces projets et qui continue rgulirement lamliorer. Cette bibliothque est t-
lchargeable sur http://phone.codeplex.com/. lheure o jcris ces lignes, nous
pouvons tlcharger la version de novembre 2012. Vous pouvez tlcharger les binaires
sur le site ou encore une fois utiliser NuGet qui facilite la rcupration de bibliothques
tierces (voir la gure 26.1).
Figure 26.1 Utilisation de NuGet pour tlcharger le Windows Phone Toolkit
NuGet nous a donc ajout la rfrence lassembly Microsoft.Phone.Controls.Toolkit.dll.
Je ne vais pas vous prsenter tous les contrles tellement il y en a. Je vous encourage
tlcharger les sources ainsi que lapplication exemple et de la tester pour voir ce
quelle renferme. Mais voyons-en quand mme quelques uns.
382
PERFORMANCEPROGRESSBAR
PerformanceProgressBar
Je souhaitais vous parler de la barre de progression PerformanceProgressBar car
cest un trs bon exemple de la puissance du toolkit. La barre de progression qui tait
originellement prsente avec le SDK pour Windows Phone 7.X posait des problmes
de performances. Celle du toolkit prote de toutes les optimisations possibles et gre
galement beaucoup mieux les threads. Nous parlerons des Threads dans un prochain
chapitre. Toujours est-il que pour Windows Phone 7, ctait cette barre de progression
qui tait recommande un peu partout sur le net et par Microsoft (pour la petite his-
toire, cest un dveloppeur de Microsoft qui a cr cette nouvelle barre de progression).
Elle a depuis t intgre dans le SDK de Windows Phone 8 an de tirer parti de
ces amliorations. Je vais vous montrer ici comment sen servir dans une application
pour Windows Phone 7 et aprs je rebasculerai sur Windows Phone 8. Crez donc une
application qui cible le SDK 7.1. Ensuite, pour utiliser la barre, rien de plus simple, il
vous sut dimporter lespace de nom du toolkit :
1 xmlns:toolkit="clr -namespace:Microsoft.Phone.Controls;assembly=
Microsoft.Phone.Controls.Toolkit"
et de la dclarer o vous souhaitez quelle sache :
1 <toolkit:PerformanceProgressBar IsIndeterminate="True" />
La barre de progression nen est en fait pas vraiment une, du moins pas dans le sens o
on les connait : en loccurrence, elle nache pas un pourcentage de progression sur une
tche dont on connait la dure totale. Il sagit plutt dune petite animation qui montre
quil se passe un chargement, sans que lon sache vraiment o nous en sommes. Vous
pouvez voir son fonctionnement dans le designer de Visual Studio, la barre sanime et
ache des points, comme indiqu sur la gure 26.2.
La barre est visible dans un tat o la progression est indtermine. Cest pour cela
que la proprit sappelle IsIndeterminate et permet dindiquer si elle est visible ou
non. Passez la False pour la voir se masquer. En gnral, ce que vous ferez, cest
dans un premier temps mettre la proprit vrai, dmarrer quelque chose de long de
manire asynchrone, par exemple un tlchargement, et une fois termin vous passerez
la proprit faux. Nous pouvons simuler ce fonctionnement avec un DispatcherTimer -
http://msdn.microsoft.com/fr-fr/library/system.windows.threading.dispatchertimer(v=
vs.95).aspx, il sagit dune classe qui va nous permettre dappeler une mthode une
frquence dtermine. Nous en reparlerons plus tard, mais par exemple ici, mon Timer
va me permettre de masquer ma barre de progression au bout de 7 secondes :
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 private DispatcherTimer timer;
4
5 public event PropertyChangedEventHandler PropertyChanged;
6
7 private void NotifyPropertyChanged(String propertyName)
8 {
383
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
Figure 26.2 Animation de la barre dans le designer
9 PropertyChangedEventHandler handler = PropertyChanged;
10 if (null != handler)
11 {
12 handler(this , new PropertyChangedEventArgs(
propertyName));
13 }
14 }
15
16 private bool chargementEnCours;
17 public bool ChargementEnCours
18 {
19 get { return chargementEnCours; }
20 set
21 {
22 chargementEnCours = value;
23 NotifyPropertyChanged("ChargementEnCours");
24 }
25 }
26
27 public MainPage ()
28 {
29 InitializeComponent ();
30 DataContext = this;
31
32 ChargementEnCours = true;
384
LISTPICKER
33 timer = new DispatcherTimer { Interval = TimeSpan.
FromSeconds(7) };
34 timer.Tick += timer_Tick;
35 timer.Start ();
36 }
37
38 private void timer_Tick(object sender , EventArgs e)
39 {
40 ChargementEnCours = false;
41 timer.Stop();
42 }
43 }
Noubliez pas dinclure lespace de noms suivant pour pouvoir utiliser le DispatcherTimer :
1 using System.Windows.Threading;
Et dans le XAML, nous aurons le binding suivant :
1 <toolkit:PerformanceProgressBar IsIndeterminate="{Binding
ChargementEnCours}" />
Remarquez quil est possible de changer facilement la couleur des points grce la
proprit Foreground. noter que son utilisation est globalement la mme avec le SDK
pour Windows Phone 8, on utilisera cependant le contrle ProgressBar directement.
Sachant que pour reproduire exactement le mme fonctionnement, il faudra masquer
la barre de progression une fois son statut indtermin activ :
1 <ProgressBar IsIndeterminate="{Binding ChargementEnCours}"
Visibility="{Binding ChargementEnCours ,Converter ={
StaticResource VisibilityConverter }}" />
Usez et abusez de cette barre ds quil faut avertir lutilisateur que quelque chose de
potentiellement long se passe.
ListPicker
Le contrle ListPicker est une espce de ListBox simplie. Il est lquivalent dun
contrle connu mais qui manquait dans les contrles Windows Phone, la ComboBox.
Ce ListPicker permet de choisir un lment parmi une liste dlments relativement
restreinte. Puissant grce son systme de modle, il permet de prsenter linformation
de manire volue. Voyons prsent comment il fonctionne.
La manire la plus simple de lutiliser est de le lier une liste de chanes de caractres :
1 <toolkit:ListPicker ItemsSource="{Binding Langues}" />
Avec dans le code-behind :
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
385
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
2 {
3 public event PropertyChangedEventHandler PropertyChanged;
4
5 private void NotifyPropertyChanged(String propertyName)
6 {
7 PropertyChangedEventHandler handler = PropertyChanged;
8 if (null != handler)
9 {
10 handler(this , new PropertyChangedEventArgs(
propertyName));
11 }
12 }
13
14 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
15 {
16 if (object.Equals(variable , valeur)) return false;
17
18 variable = valeur;
19 NotifyPropertyChanged(nomPropriete);
20 return true;
21 }
22
23 private List <string > langues;
24 public List <string > Langues
25 {
26 get { return langues; }
27 set { NotifyPropertyChanged(ref langues , value); }
28 }
29
30 public MainPage ()
31 {
32 InitializeComponent ();
33 DataContext = this;
34
35 Langues = new List <string > { "Franais", "English", "
Deutsch", "Espaol" };
36 }
37 }
Nous obtenons la gure 26.3.
Et lorsque nous cliquons dessus, il se dplie pour nous permettre de slectionner un
lment, comme vous pouvez le voir la gure 26.4.
Pour la slection, ce contrle fonctionne comme la ListBox. Nous pouvons prslection-
ner un lment et tre informs de quel lment est slectionn. Donnons un nom
notre ListPicker et abonnons-nous lvnement SelectionChanged :
1 <toolkit:ListPicker ItemsSource="{Binding Langues}" x:Name="
Liste" SelectionChanged="Liste_SelectionChanged" />
386
LISTPICKER
Figure 26.3 Le ListPicker pli
Figure 26.4 Le ListPicker dpli nous permet de slectionner un lment
387
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
Et dans le code-behind :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 DataContext = this;
5
6 Langues = new List <string > { "Franais", "English", "
Deutsch", "Espaol" };
7 Liste.SelectedIndex = 2;
8 }
9
10 private void Liste_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
11 {
12 if (Liste.SelectedItem != null)
13 {
14 MessageBox.Show(Liste.SelectedItem.ToString ());
15 }
16 }
Nous obtenons la gure 26.5.
Figure 26.5 Slection dun lement du ListPicker
Dans cet exemple, lorsquon clique dans le ListPicker, la liste se droule pour nous
montrer tous les lments de la liste. Il existe un autre mode de slection : le mode
plein cran. Il sut de changer dans le XAML :
388
LISTPICKER
1 <toolkit:ListPicker ItemsSource="{Binding Langues}" Header="
Langue :" FullModeHeader="Choisir une langue :"
ExpansionMode="FullScreenOnly" />
Remarquons la proprit ExpansionMode qui permet de forcer la slection dans un
mode plein cran. Nous pouvons galement donner un titre notre ListPicker grce
la proprit Header, titre qui peut tre dirent si nous sommes en mode plein cran
(voir la gure 26.6).
Figure 26.6 Slection en mode plein cran
Comme je lai dj dit, il est possible de fournir un modle pour chaque lment et ceci
grce aux proprits ItemTemplate et FullModeItemTemplate. Par exemple, chan-
geons le type de notre liste dlments :
1 private List <Element > langues;
2 public List <Element > Langues
3 {
4 get { return langues; }
5 set { NotifyPropertyChanged(ref langues , value); }
6 }
Avec la classe Element suivante :
1 public class Element
2 {
3 public string Langue { get; set; }
4 public string Code { get; set; }
389
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
5 public Uri Url { get; set; }
6 }
Que nous alimentons ainsi :
1 Langues = new List <Element >
2 {
3 new Element { Code = "FR", Langue = "Franais", Url = new
Uri("/Assets/Images/france.png", UriKind.Relative)},
4 new Element { Code = "US", Langue = "English", Url = new
Uri("/Assets/Images/usa.png", UriKind.Relative)},
5 new Element { Code = "DE", Langue = "Deutsch", Url = new
Uri("/Assets/Images/allemagne.png", UriKind.Relative)},
6 new Element { Code = "ES", Langue = "Espaol", Url = new
Uri("/Assets/Images/espagne.png", UriKind.Relative)},
7 };
sachant que les images correspondant aux drapeaux de chaque langue sont inclues dans
le rpertoire Images, sous le rpertoire Assets, dans notre solution (en ayant chang
laction de gnration Contenu ). Je peux alors modier le XAML pour avoir :
1 <toolkit:ListPicker ItemsSource="{Binding Langues}" Header="
Langue :" FullModeHeader="Choisir une langue :"
ExpansionMode="FullScreenOnly">
2 <toolkit:ListPicker.ItemTemplate >
3 <DataTemplate >
4 <StackPanel Orientation="Horizontal">
5 <Border BorderThickness="2" BorderBrush="Beige"
Background="Azure">
6 <TextBlock Text="{Binding Code}" Foreground
="Blue" />
7 </Border >
8 <TextBlock Margin="20 0 0 0" Text="{Binding
Langue}" />
9 </StackPanel >
10 </DataTemplate >
11 </toolkit:ListPicker.ItemTemplate >
12 <toolkit:ListPicker.FullModeItemTemplate >
13 <DataTemplate >
14 <StackPanel Orientation="Horizontal">
15 <TextBlock Margin="20 0 0 0" Text="{Binding
Langue}" Style="{StaticResource
PhoneTextTitle1Style}" />
16 <Image Source="{Binding Url}" />
17 </StackPanel >
18 </DataTemplate >
19 </toolkit:ListPicker.FullModeItemTemplate >
20 </toolkit:ListPicker >
Ce qui donnera la page prsente dans la gure 26.7.
Ainsi que dans le mode de slection plein cran (voir la gure 26.8).
390
LISTPICKER
Figure 26.7 Utilisation des templates du ListPicker
Figure 26.8 Le template plein cran
391
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
Ce ListPicker est dnitivement bien pratique lorsquil sagit de permettre de choisir
entre plusieurs lments, dans une liste relativement courte. De plus, ses dirents
modes de slection orent une touche supplmentaire vos applications.
WrapPanel
Au mme titre que le StackPanel, le WrapPanel du toolkit est un conteneur de contrles
qui a une fonctionnalit intressante. Il est capable de passer automatiquement la ligne
ou la colonne suivante si les contrles prsents lintrieur dpassent du conteneur.
Prenons par exemple le XAML suivant et rutilisons les images de lexemple prcdent :
1 <StackPanel Orientation="Horizontal">
2 <Image Source="/Assets/Images/france.png" Width="150"
Height="150" Margin="10" />
3 <Image Source="/Assets/Images/usa.png" Width="150" Height="
150" Margin="10" />
4 <Image Source="/Assets/Images/allemagne.png" Width="150"
Height="150" Margin="10" />
5 <Image Source="/Assets/Images/espagne.png" Width="150"
Height="150" Margin="10" />
6 </StackPanel >
Vous pouvez voir le rsultat la gure 26.9.
Figure 26.9 Lcran nest pas assez large pour voir les 4 images avec un StackPanel
392
WRAPPANEL
Oh diantre, cest plutt embtant, on ne voit que 3 images sur les 4 promises. . . ! Eh
oui, il ny a pas assez de place sur lcran et la troisime image dpasse du conteneur.
Changeons maintenant juste le conteneur et remplaons-le par un WrapPanel :
1 <toolkit:WrapPanel >
2 <Image Source="/Assets/Images/france.png" Width="150"
Height="150" Margin="10" />
3 <Image Source="/Assets/Images/usa.png" Width="150" Height="
150" Margin="10" />
4 <Image Source="/Assets/Images/allemagne.png" Width="150"
Height="150" Margin="10" />
5 <Image Source="/Assets/Images/espagne.png" Width="150"
Height="150" Margin="10" />
6 </toolkit:WrapPanel >
Nous aurons la gure 26.10.
Figure 26.10 Le WrapPanel passe automatiquement la ligne sil ny a pas assez de
place
Et miracle, toutes les images sont dsormais prsentes. Vous avez compris que cest
le WrapPanel qui a fait automatiquement passer les images la ligne an quelles
apparaissent lcran. Son but : faire en sorte que tout tienne lcran !
Cela fonctionne galement en orientation verticale :
1 <toolkit:WrapPanel Orientation="Vertical">
2 <Image Source="/Assets/Images/france.png" Width="150"
Height="150" Margin="10" />
393
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
3 <Image Source="/Assets/Images/usa.png" Width="150" Height="
150" Margin="10" />
4 <Image Source="/Assets/Images/allemagne.png" Width="150"
Height="150" Margin="10" />
5 <Image Source="/Assets/Images/espagne.png" Width="150"
Height="150" Margin="10" />
6 </toolkit:WrapPanel >
Ce qui donnera la gure 26.11.
Figure 26.11 Le WrapPanel en orientation verticale
Le WrapPanel est trs pratique combin avec une ListBox ou mme un ListPicker.
Dans lexemple fourni avec le toolkit, on peut le voir utilis lintrieur dun Pivot.
Nhsitez pas vous servir de ce conteneur ds que vous aurez besoin dacher une
liste dlments dont vous ne maitrisez pas forcment le nombre.
Et je ne sais pas si vous vous souvenez, mais je vous ai fait une capture dcran pr-
cdemment lorsque je parlais des direntes rsolutions des Windows Phone o javais
ajout plein de boutons les uns la suite des autres. Ils taient dans un WrapPanel et
salignaient alors automatiquement, les uns la suite des autres.
394
LONGLISTSELECTOR
LongListSelector
Avant de sarrter sur lexploration des contrles de ce toolkit, regardons encore le
contrle LongListSelector. Bien que jaie choisi de prsenter ce contrle dans le cha-
pitre sur le toolkit Windows Phone, le LongListSelector existe dans le SDK de Win-
dows Phone 8. Eh oui, cest comme pour le ProgressBar, voici un contrle qui nexistait
pas avec le SDK pour Windows Phone 7, qui a t cr et approuv par la commu-
naut, et qui trouve naturellement sa place dans le SDK pour Windows Phone 8. Il
permet damliorer encore la ListBox, notamment quand celle-ci contient normment
de valeurs. Grce lui, nous pouvons regrouper des valeurs an que chacune soit plus
facilement accessible. Ce type de contrle est utilis par exemple avec les contacts dans
notre tlphone, lorsque nous commenons en avoir beaucoup.
La gure 26.12 montre le rsultat que nous allons obtenir la n de ce chapitre, les
prnoms sont regroups suivant leur premire lettre.
Figure 26.12 Les prnoms sont regroups avec le LongListSelector
Et lors dun clic sur un groupe, nous obtenons la liste des groupes o nous pouvons
slectionner un lment pour latteindre plus rapidement (voir la gure 26.13).
Pour dmontrer ce fonctionnement, prenons par exemple la liste des 50 prnoms fmi-
nins de bb les plus donns en 2012 :
1 List <string > liste = new List <string > { "Emma", "Manon", "Chlo
", "Camille", "La", "Lola", "Louise", "Zo", "Jade", "Clara
", "Lena", "Eva", "Anas", "Clmence", "Lilou", "Ins", "
395
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
Figure 26.13 La liste des groupes du LongListSelector
Juliette", "Malys", "Lucie", "Alice", "Sarah", "Romane", "
Jeanne", "Margaux", "Mathilde", "Elise", "Lonie", "Louna",
"Lisa", "Ambre", "Anna", "Justine", "Lily", "Pauline", "
Laura", "Charlotte", "Rose", "Julia", "Noemie", "Elose", "
Lou", "Alicia", "Elna", "Margot", "Elsa", "Louane", "Elisa"
, "Nina", "Marie", "Agathe" };
Le principe est de faire une liste de liste groupe dlments grce loprateur Linq
join :
1 IEnumerable <List <string >> prenoms = from prenom in liste
2 group prenom by prenom[0]. ToString () into p
3 orderby p.Key
4 select new List <string >(p);
5
6 ListePrenoms = prenoms.ToList ();
Ici, jai choisi de regrouper les prnoms en fonction de leur premire lettre, mais on pour-
rait trs bien imaginer une liste de villes regroupes en fonction de leur pays dapparte-
nance. . . ou quoi que ce soit dautre. . . Pour utiliser le binding avec ce LongListSelector,
nous devons avoir la proprit suivante :
1 private List <List <string >> listePrenoms;
2 public List <List <string >> ListePrenoms
3 {
396
LONGLISTSELECTOR
4 get { return listePrenoms; }
5 set { NotifyPropertyChanged(ref listePrenoms , value); }
6 }
Cot XAML cest un peu plus compliqu. Nous avons premirement besoin de lier la
proprit ItemsSource du LongListSelector notre proprit ListePrenoms :
1 <phone:LongListSelector ItemsSource="{Binding ListePrenoms}">
2 </phone:LongListSelector >
Noubliez pas quil sagit dun contrle Windows Phone 8,
et que son espace de nom est inclus dans la page avec :
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=
Microsoft.Phone". Si vous utilisez le SDK pour Windows Phone 7, il vous
sura dutiliser le contrle du toolkit, mais il y aura quand mme quelques
adaptations faire sur les templates.
Il faut maintenant indiquer plusieurs choses, premirement que le contrle est en mode
liste, quil accepte de grouper les lments et quil a la possibilit dobtenir la liste des
groupes. Cela se fait grce ces proprits :
1 <phone:LongListSelector ItemsSource="{Binding ListePrenoms}"
LayoutMode="List" IsGroupingEnabled="True" JumpListStyle="{
StaticResource LongListSelectorJumpListStyle}">
2 </phone:LongListSelector >
Notez la prsence du style LongListSelectorJumpListStyle qui est dnir.
Ensuite, il y a plusieurs modles crer. Premirement le modle des lments, cest-
-dire des prnoms. Il sagit du modle ItemTemplate. Ici, un simple TextBlock sut :
1 <phone:LongListSelector ItemsSource="{Binding ListePrenoms}">
2 <phone:LongListSelector.ItemTemplate >
3 <DataTemplate >
4 <TextBlock Text="{Binding}" FontSize="26" Margin="
12 ,-12 ,12 ,6"/>
5 </DataTemplate >
6 </phone:LongListSelector.ItemTemplate >
7 </phone:LongListSelector >
Ensuite, nous rajoutons un modle pour les groupes visibles dans la liste. Il sagit du
modle GroupHeaderTemplate. Ici nous devons acher la premire lettre du groupe,
entoure dans un rectangle dont le bord correspond la couleur daccentuation :
1 <phone:LongListSelector ItemsSource="{Binding ListePrenoms}">
2 ...
3 <phone:LongListSelector.GroupHeaderTemplate >
4 <DataTemplate >
5 <Border BorderBrush="{Binding Converter ={
StaticResource BackgroundConverter }}"
397
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
BorderThickness="2" Width="60" Margin="10"
HorizontalAlignment="Left">
6 <TextBlock Text="{Binding Converter ={
StaticResource ListConverter }}" FontSize="40
" Foreground="{Binding Converter ={
StaticResource BackgroundConverter }}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
7 </Border >
8 </DataTemplate >
9 </phone:LongListSelector.GroupHeaderTemplate >
10 </phone:LongListSelector >
Remarquez qutant donn que la liaison se fait sur la List<string>, jutilise un conver-
ter pour nacher que la premire lettre. Ce converter est dni classiquement en
ressource :
1 <converter:ListConverter x:Key="ListConverter" />
Avec limport despace de nom adquat :
1 xmlns:converter="clr -namespace:DemoToolkit"
Le converter quant lui est trs simple, il prend simplement la premire lettre du
premier lment de la liste :
1 public class ListConverter : IValueConverter
2 {
3 public object Convert(object value , Type targetType , object
parameter , CultureInfo culture)
4 {
5 List <string > liste = (List <string >) value;
6 if (liste == null || liste.Count == 0)
7 return string.Empty;
8 return liste[0][0];
9 }
10
11 public object ConvertBack(object value , Type targetType ,
object parameter , CultureInfo culture)
12 {
13 throw new NotImplementedException ();
14 }
15 }
Notez lutilisation du converter BackgroundConverter qui permet dobtenir la couleur
daccentuation. Ce converter est dni dans les ressources et est un converter systme.
Dclarons-le ainsi que son petit frre, le ForegroundConverter, qui permet davoir la
couleur du thme :
1 <phone:JumpListItemBackgroundConverter x:Key="
BackgroundConverter"/>
398
LONGLISTSELECTOR
2 <phone:JumpListItemForegroundConverter x:Key="
ForegroundConverter"/>
Enn, il reste le style de la liste des groupes, qui apparat lorsquon clique sur un groupe.
Il sagit du style LongListSelectorJumpListStyle que nous avons prcdemment vu,
qui est galement mettre en ressources :
1 <Style x:Key="LongListSelectorJumpListStyle" TargetType="phone:
LongListSelector">
2 <Setter Property="GridCellSize" Value="113 ,113"/>
3 <Setter Property="LayoutMode" Value="Grid" />
4 <Setter Property="ItemTemplate">
5 <Setter.Value >
6 <DataTemplate >
7 <Border Background="{Binding Converter ={
StaticResource BackgroundConverter }}"
8 Width="113" Height="113" Margin
="6" >
9 <TextBlock Text="{Binding Converter ={
StaticResource ListConverter }}"
10 FontFamily="{
StaticResource
PhoneFontFamilySemiBold
}"
11 FontSize="48" Padding="
6"
12 Foreground="{Binding
Converter ={
StaticResource
ForegroundConverter
}}"
13 VerticalAlignment="
Center"/>
14 </Border >
15 </DataTemplate >
16 </Setter.Value >
17 </Setter >
18 </Style >
Ici, le principe est le mme, on utilise le converter pour acher la premire lettre. Elle
sera dans un cadre au fond du thme daccentuation. Ce qui nous donne le code XAML
complet suivant :
1 <phone:LongListSelector ItemsSource="{Binding ListePrenoms}"
LayoutMode="List" IsGroupingEnabled="True" JumpListStyle="{
StaticResource LongListSelectorJumpListStyle}">
2 <phone:LongListSelector.ItemTemplate >
3 <DataTemplate >
4 <TextBlock Text="{Binding}" FontSize="26" Margin="
12 ,-12 ,12 ,6"/>
5 </DataTemplate >
399
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
6 </phone:LongListSelector.ItemTemplate >
7 <phone:LongListSelector.GroupHeaderTemplate >
8 <DataTemplate >
9 <Border BorderBrush="{Binding Converter ={
StaticResource BackgroundConverter }}"
BorderThickness="2" Width="60" Margin="10"
HorizontalAlignment="Left">
10 <TextBlock Text="{Binding Converter ={
StaticResource ListConverter }}" FontSize="40
" Foreground="{Binding Converter ={
StaticResource BackgroundConverter }}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
11 </Border >
12 </DataTemplate >
13 </phone:LongListSelector.GroupHeaderTemplate >
14 </phone:LongListSelector >
Cest vrai, je le reconnais, il fait un peu peur ! Nous allons le simplier en mettant nos
DataTemplate en ressource. Il sut de les dclarer ainsi :
1 <phone:PhoneApplicationPage.Resources >
2 ...
3
4 <DataTemplate x:Key="ModeleElement">
5 <TextBlock Text="{Binding}" FontSize="26" Margin="12 ,-
12 ,12 ,6"/>
6 </DataTemplate >
7 <DataTemplate x:Key="ModeleGroupe">
8 <Border BorderBrush="{Binding Converter ={ StaticResource
BackgroundConverter }}" BorderThickness="2" Width="
60" Margin="10" HorizontalAlignment="Left">
9 <TextBlock Text="{Binding Converter ={ StaticResource
ListConverter }}" FontSize="40" Foreground="{
Binding Converter ={ StaticResource
BackgroundConverter }}" HorizontalAlignment="
Center" VerticalAlignment="Center"/>
10 </Border >
11 </DataTemplate >
12
13 ...
14 </phone:PhoneApplicationPage.Resources >
Noubliez pas quil faut imprativement une cl un lment prsent dans les ressources.
Nous pourrons alors simplier lcriture du contrle ainsi :
1 <phone:LongListSelector ItemsSource="{Binding ListePrenoms}"
LayoutMode="List" IsGroupingEnabled="True" JumpListStyle="{
StaticResource LongListSelectorJumpListStyle}" ItemTemplate=
"{StaticResource ModeleElement}" GroupHeaderTemplate="{
StaticResource ModeleGroupe}" />
400
AVANTAGES & LIMITES DU TOOLKIT
Ce qui est beaucoup plus court et qui permet galement de potentiellement rutiliser
les modles. . . Je nai pas dcrit toutes les possibilits de ce contrle. Sachez quil est
possible de dnir un modle pour raliser un entte de liste et un pied de liste. Elle
peut galement se consulter plat , en utilisant la proprit :
1 IsFlatList="True"
Ce contrle est plutt pratique. Jai choisi dutiliser un converter pour acher le titre
dun groupe en utilisant la premire lettre des prnoms. Ce qui se fait aussi cest
de construire un objet directement liable possdant une proprit Titre et une liste
dlments, en gnral quelque chose comme a :
1 public class Group <T> : List <T>
2 {
3 public Group(string nom , IEnumerable <T> elements)
4 : base(elements)
5 {
6 this.Titre = nom;
7 }
8
9 public string Titre { get; set; }
10 }
Avantages & limites du toolkit
Bon, je marrte l pour cette petite prsentation limite du toolkit. Nous aurons loc-
casion de revoir des choses du toolkit de temps en temps dans la suite du cours. Il
rajoute des fonctionnalits trs intressantes qui manquaient aux dveloppeurs souhai-
tant raliser des applications denvergure avec Windows Phone. Il ne sagit bien sr pas
de contrles ociels, mais ils sont largement reconnus par la communaut. Ce toolkit,
notamment dans sa version XAML, sert parfois galement de bac sable pour les dve-
loppeurs Microsoft an de fournir des contrles sans quils ne fassent partie intgrante
de la bibliothque de contrles ocielle.
Il y a tout une communaut active et dynamique qui pousse an que ces contrles aient
le moins de bug possible, cependant nous ne sommes pas labri dun comportement
indsirable. . .
Les autres toolkits
Le toolkit pour Windows Phone nest pas la seule bibliothque de contrles du mar-
ch. Il en existe dautres. Citons par lexemple la bibliothque Coding4Fun - http:
//coding4fun.codeplex.com/ qui est gratuite et qui fournit des contrles plutt sym-
pathiques. Notons par exemple un contrle qui permet de slectionner une date ou une
heure (voir la gure 26.14).
401
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
Figure 26.14 Le choix dune dure grce au toolkit Coding4Fun
402
LES AUTRES TOOLKITS
Dautres sont payants et dvelopps par des socits tierces, citons par exemple les
contrles de la socit Telerik ou encore de Syncfusion. Ils fournissent des contrles qui
nous simplient la tche et qui permettent de gagner du temps dans nos dveloppe-
ments. Nhsitez pas y jeter un coup dil, cest souvent plus intressant dacheter
un contrle dj tout fait que de passer du temps (beaucoup de temps !) le raliser.
En rsum
Le toolkit pour Windows Phone est une bibliothque de contrles fournie gratui-
tement qui permet denrichir vos applications avec des contrles trs pratiques.
Il y a beaucoup de bibliothques qui existent et qui proposent des contrles
complets, sadaptant beaucoup de situation. Certaines sont gratuites, dautres
payantes. Nhsitez pas les consulter, il y a souvent de bonnes surprises.
403
CHAPITRE 26. LE TOOLKIT WINDOWS PHONE
404
Chapitre 27
Le contrle de cartes (Map)
Dicult :
Avant de commencer regarder le contrle Map, il faut savoir quil est dirent entre
la version du SDK pour dvelopper pour Windows Phone 7 et celui pour dvelopper pour
Windows Phone 8. Le premier est le contrle de cartes de Microsoft alors que pour Windows
Phone 8, cest celui ralis par Nokia qui est utilis. Ils se ressemblent cependant fortement
dans leurs utilisations, mais celui de Nokia a une particularit intressante lui permettant de
faire des choses hors connexion que ne permet pas celui de Microsoft. Mais rassurez-vous,
nul besoin de possder un tlphone Nokia pour pouvoir sen servir, il fonctionne pour tous
les tlphones Windows Phone 8.
405
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
Je vais prsenter ici le contrle de Windows Phone 8, mais sachez quil
est galement possible dutiliser lancien contrle avec des applications Win-
dows Phone 8. Il sagit dun contrle trs complet et bien pratique :
le contrle Map - http://msdn.microsoft.com/en-us/library/windowsphone/
develop/microsoft.phone.maps.controls.map(v=vs.105).aspx. Il permet dem-
barquer une carte dans notre application. Nous allons pouvoir acher la carte de
France, la carte dEurope, etc . . . dnir des positions, calculer des itinraires . . . Bref,
tout plein de choses qui peuvent servir nos tlphones quips de GPS.
Dcouvrons prsent ce fameux contrle.
Prsentation et utilisation
Pour utiliser le contrle Map, le plus simple est de le faire glisser depuis la boite outils
pour le mettre par exemple lintrieur de la grille, comme indiqu la gure 27.1.
Figure 27.1 Le contrle de carte dans la boite outils
Visual Studio nous ajoute le contrle et nous pouvons voir dans la fentre de design
une mini carte du monde (voir la gure 27.2).
Aprs lajout du contrle, si nous regardons le XAML, Visual Studio nous a ajout
lespace de nom suivant :
1 xmlns:Controls="clr -namespace:Microsoft.Phone.Maps.Controls;
assembly=Microsoft.Phone.Maps"
ainsi que le XAML positionnant le contrle :
1 <Controls:Map />
Personnellement, je change le Controls en carte et je donne le nom Carte
mon contrle :
406
PRSENTATION ET UTILISATION
Figure 27.2 Le contrle map dans le designer
1 <carte:Map Name="Carte" />
Si vous dmarrez lmulateur tout de suite, vous allez avoir un problme. Visual Studio
nous lve une exception de type :
1 Une exception de premire chance de type 'System.Windows.Markup
.XamlParseException ' s'est produite dans System.Windows.ni.
dll
Mais si on fouille un peu dans les InnerException, on trouve plutt :
1 Access to Maps requires ID_CAP_MAP to be defined in the
manifest
En fait, pour utiliser le contrle de cartes, nous devons dclarer notre application comme
utilisatrice du contrle de cartes. Cela permettra notamment aux personnes qui veulent
tlcharger notre application de savoir quelle utilise le contrle de carte. On appelle
cela les capacits. Pour dclarer une capacit, nous allons avoir besoin de double-cliquer
sur le chier WMAppManifest.xml (sous Properties dans lexplorateur de solutions) et
daller dans longlet Capacits. Ensuite, il faut cocher la capacit ID_CAP_MAP, comme
lindique la gure 27.3.
Et voil, maintenant en dmarrant lmulateur, nous allons avoir une jolie carte du
monde (si vous tes connects Internet) - voir la gure 27.4.
407
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
Figure 27.3 Activer la capacit dutilisation de carte
Figure 27.4 La carte sache dans lmulateur
408
INTERACTIONS AVEC LE CONTRLE
Interactions avec le contrle
Et si nous prenions le contrle de la carte ? On peut tout faire avec cette carte, comme
se positionner un emplacement prcis grce des coordonnes GPS, ajouter des
marques pour pingler des lieux, zoomer, d-zoomer, etc. Pour illustrer tout cela, nous
allons manipuler cette fameuse carte. Premire chose faire, nous allons acher des
boutons pour zoomer et d-zoomer. Utilisons par exemple une barre dapplication pour
ce faire et intgrons-y les deux icnes suivantes, prsentes dans le rpertoire du SDK :
add.png
minus.png
Nhsitez pas aller faire un tour dans le chapitre de la barre dapplication si vous
avez un doute sur la marche suivre. Voici donc le XAML de la barre dapplication
utilise :
1 <phone:PhoneApplicationPage.ApplicationBar >
2 <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"
>
3 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/add.png" Text="Zoom" Click="Zoom_Click"/>
4 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/minus.png" Text="D-zoom" Click="Dezoom_Click"/>
5 </shell:ApplicationBar >
6 </phone:PhoneApplicationPage.ApplicationBar >
Comme dhabitude, prenez garde au chemin des icnes. Et le code-behind associ :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6 }
7
8 private void Zoom_Click(object sender , EventArgs e)
9 {
10 Carte.ZoomLevel ++;
11 }
12
13 private void Dezoom_Click(object sender , EventArgs e)
14 {
15 Carte.ZoomLevel --;
16 }
17 }
Vous pouvez voir que nous pouvons facilement zoomer ou d-zoomer en utilisant les
boutons de la barre dapplication, et tout a grce la proprit ZoomLevel. De plus,
nous pouvons nous dplacer sur la carte en faisant glisser notre doigt (ou notre souris !),
comme indiqu la gure 27.5.
409
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
Figure 27.5 Dplacement et zoom pour acher la carte de Paris
Tout au long de lutilisation, sur un tlphone, nous pouvons galement zoomer et d-
zoomer grce au geste qui consiste ramener ses deux doigts vers le centre de lcran
ou au contraire les carter pour d-zoomer (geste que lon appelle le Pinch-to-zoom
ou le Stretch-to-zoom). Cest par contre un peu plus dicile faire la souris dans
lmulateur, sachant que nous avons quand mme la possibilit de zoomer en double-
cliquant. . . Mais cela sera quand mme bien plus simple dans lmulateur avec la barre
dapplication.
Nous pouvons aussi centrer la carte un emplacement prcis. Pour cela, on uti-
lise la proprit Center qui est du type GeoCoordinate - http://msdn.microsoft.
com/fr-fr/library/system.device.location.geocoordinate.aspx. Il sagit dune
classe contenant des coordonnes GPS, avec notamment la latitude et la longitude.
Nous pouvons utiliser des coordonnes pour centrer la carte un emplacement dsir.
Par exemple :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 Carte.ZoomLevel = 17;
5 Carte.Center = new GeoCoordinate { Latitude = 48.858115 ,
Longitude = 2.294710 };
6 }
410
INTERACTIONS AVEC LE CONTRLE
qui centre la carte sur la tour Eiel. On noubliera pas dinclure lespace de nom
permettant dutiliser le type GeoCoordinate :
1 using System.Device.Location;
La carte est galement disponible en mode satellite (ou arien), il sut de changer la
proprit CartographicMode du contrle pour passer en mode arien avec :
1 Carte.CartographicMode = MapCartographicMode.Aerial;
Disponible avec limport despace de nom suivant :
1 using Microsoft.Phone.Maps.Controls;
Vous pouvez voir le rsultat la gure 27.6.
Figure 27.6 La carte en mode arien
Le mode route, par dfaut, correspond la valeur dnumration MapCartographicMode.Road,
sachant quil existe galement la valeur Terrain et Hybrid. Nous pouvons inclure des
points de repres dans la carte grce la proprit LandmarksEnabled en la passant
True. la gure 27.7, la mme carte sans et avec points de repres.
Vous noterez la dirence ! Vous pouvez galement indiquer un degr dinclinaison
grce la proprit Pitch. Voici par exemple la gure 27.8 la carte avec un degr
dinclinaison de 0 et de 45.
Nous pouvons galement inclure les informations pitonnes, comme les escaliers grce
la proprit PedestrianFeaturesEnabled en la passant True (voir la gure 27.9).
411
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
Figure 27.7 La carte peut acher des points de repres
Figure 27.8 La carte sans et avec un degr dinclinaison
412
EPINGLER DES POINTS DINTRT
Figure 27.9 La carte avec les informations pitonnes
Le zoom doit tre suprieur 7 et le pitch suprieur 25 pour avoir accs
cette fonctionnalit.
Epingler des points dintrt
Une des grandes forces du contrle Map est quon peut dessiner nimporte quoi par
dessus, pour par exemple pingler des points dintrts sur la carte. Cela permet de
mettre en valeur certains lieux et pourquoi pas acher une information contextuelle
complmentaire. Le principe est simple, il sut dajouter des coordonnes GPS et une
punaise apparat automatiquement cet emplacement. Cela ne se fait par contre pas
tout seul, mais grce au Windows Phone Toolkit que nous venons de voir. Ajoutez une
rfrence celui-ci, comme nous venons de le faire, et utilisons la classe PushPin qui
reprsente une telle pingle. Il faut dans un premier temps importer lespace de nom :
1 xmlns:toolkitcarte="clr -namespace:Microsoft.Phone.Maps.Toolkit;
assembly=Microsoft.Phone.Controls.Toolkit"
puis ajouter des lments PushPin :
1 <carte:Map Name="Carte">
2 <toolkitcarte:MapExtensions.Children >
413
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
3 <toolkitcarte:Pushpin GeoCoordinate="48.842276 , 2.
321747" />
4 <toolkitcarte:Pushpin GeoCoordinate="48.858115 , 2.
294710" />
5 <toolkitcarte:Pushpin GeoCoordinate="48.873783 , 2.
294930" />
6 </toolkitcarte:MapExtensions.Children >
7 </carte:Map >
Et nous aurons ce rsultat (voir la gure 27.10).
Figure 27.10 Les punaises pour pingler des points dintrts
Pour avoir le mme rendu avec le code behind, il sut davoir le XAML suivant :
1 <carte:Map Name="Carte" />
Et le code suivant :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 Carte.ZoomLevel = 12;
5 Carte.Center = new GeoCoordinate { Latitude = 48.863134 ,
Longitude = 2.320518 };
6
7 var elts = MapExtensions.GetChildren(Carte);
8 MapExtensions.Add(elts , new Pushpin (), new GeoCoordinate {
Longitude = 2.321747 , Latitude = 48.842276 });
414
EPINGLER DES POINTS DINTRT
9 MapExtensions.Add(elts , new Pushpin (), new GeoCoordinate {
Longitude = 2.294710 , Latitude = 48.858115 });
10 MapExtensions.Add(elts , new Pushpin (), new GeoCoordinate {
Longitude = 2.294930 , Latitude = 48.873783 });
11 }
La punaise est bien sr stylisable souhait, car celle-l est un peu triste. Prenez par
exemple celle-ci, permettant de remplacer la grosse punaise par un petit point bleu :
1 <phone:PhoneApplicationPage.Resources >
2 <ControlTemplate x:Key="PushpinControlTemplate" TargetType=
"toolkitcarte:Pushpin">
3 <Ellipse Fill="{TemplateBinding Background}"
4 HorizontalAlignment="Center"
5 VerticalAlignment="Center"
6 Width="20"
7 Height="20"
8 Stroke="{TemplateBinding Foreground}"
9 StrokeThickness="3" />
10 </ControlTemplate >
11
12 <Style TargetType="toolkitcarte:Pushpin" x:Key="
PushpinControlTemplateEllipse">
13 <Setter Property="Template" Value="{StaticResource
PushpinControlTemplate}" />
14 <Setter Property="Background" Value="Blue" />
15 <Setter Property="Foreground" Value="White" />
16 </Style >
17 </phone:PhoneApplicationPage.Resources >
Que nous pourrons utiliser ainsi :
1 <carte:Map Name="Carte">
2 <toolkitcarte:MapExtensions.Children >
3 <toolkitcarte:Pushpin GeoCoordinate="48.842276 , 2.
321747" Style="{StaticResource
PushpinControlTemplateEllipse}" />
4 <toolkitcarte:Pushpin GeoCoordinate="48.858115 , 2.
294710" Style="{StaticResource
PushpinControlTemplateEllipse}" />
5 <toolkitcarte:Pushpin GeoCoordinate="48.874956 , 2.
350690" Style="{StaticResource
PushpinControlTemplateEllipse}" />
6 </toolkitcarte:MapExtensions.Children >
7 </carte:Map >
ou la mme chose avec le code behind :
1 var elts = MapExtensions.GetChildren(Carte);
2 MapExtensions.Add(elts , new Pushpin { Style = Resources["
PushpinControlTemplateEllipse"] as Style }, new
415
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
GeoCoordinate { Longitude = 2.321747 , Latitude = 48.842276
});
3 MapExtensions.Add(elts , new Pushpin { Style = Resources["
PushpinControlTemplateEllipse"] as Style }, new
GeoCoordinate { Longitude = 2.294710 , Latitude = 48.858115
});
4 MapExtensions.Add(elts , new Pushpin { Style = Resources["
PushpinControlTemplateEllipse"] as Style }, new
GeoCoordinate { Longitude = 2.350690 , Latitude = 48.874956
});
Ce qui donne le rsultat ach la gure 27.11.
Figure 27.11 Les punaises ont du style !
Do vient cette punaise OpenClassrooms ? Simplement de mon autre style utilisant
une image comme punaise :
1 <ControlTemplate x:Key="PushpinControlTemplateImage" TargetType
="toolkitcarte:Pushpin">
2 <Image Source="http ://open -e-education -2013.openclassrooms.
com/img/logos/logo -openclassrooms.png" Width="60" Height
="60" />
3 </ControlTemplate >
4
5 <Style TargetType="toolkitcarte:Pushpin" x:Key="
PushpinControlTemplateImageStyle">
416
EPINGLER DES POINTS DINTRT
6 <Setter Property="Template" Value="{StaticResource
PushpinControlTemplateImage}" />
7 </Style >
Le logo dOpenClassrooms pour indiquer lemplacement des locaux dOpenClassrooms ?
Cest pas la classe a ? Ajouter des punaises en spciant des coordonnes dans le
XAML, cest bien. Mais nous pouvons galement le faire par binding ! Voyez par
exemple avec ce XAML :
1 <carte:Map Name="Carte">
2 <toolkitcarte:MapExtensions.Children >
3 <toolkitcarte:Pushpin GeoCoordinate="{Binding
PositionTourEiffel}" Style="{StaticResource
PushpinControlTemplateEllipse}" />
4 </toolkitcarte:MapExtensions.Children >
5 </carte:Map >
La proprit GeoCoordinate de lobjet Pushpin est lie la proprit PositionTourEiffel,
qui sera du genre :
1 private GeoCoordinate positionTourEiffel;
2 public GeoCoordinate PositionTourEiffel
3 {
4 get { return positionTourEiffel; }
5 set { NotifyPropertyChanged(ref positionTourEiffel , value);
}
6 }
Que lon pourra alimenter avec :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 Carte.ZoomLevel = 12;
5 Carte.Center = new GeoCoordinate { Latitude = 48.863134 ,
Longitude = 2.320518 };
6 PositionTourEiffel = new GeoCoordinate { Longitude = 2.
321747 , Latitude = 48.842276 };
7 DataContext = this;
8 }
Noubliez pas dimplmenter correctement INotifyPropertyChanged, mais bon, vous
savez faire maintenant. On peut mme leur rajouter un petit texte grce la proprit
Content :
1 <toolkitcarte:Pushpin GeoCoordinate="{Binding
PositionTourEiffel}" Content="{Binding Texte}" />
Avec :
1 private string texte;
2 public string Texte
417
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
3 {
4 get { return texte; }
5 set { NotifyPropertyChanged(ref texte , value); }
6 }
Et :
1 Texte = "La tour Eiffel";
Ce qui donne la gure 27.12.
Figure 27.12 Lgende sur les punaises
Notez que jai retir le style ellipse bleue car ce style ne prenait pas en charge la
proprit Content. Pour ce faire, il faudrait modier le style pour avoir, par exemple :
1 <ControlTemplate x:Key="PushpinControlTemplate" TargetType="
toolkitcarte:Pushpin">
2 <StackPanel >
3 <ContentPresenter Content="{TemplateBinding Content}"
/>
4 <Ellipse Fill="{TemplateBinding Background}"
5 HorizontalAlignment="Center"
6 VerticalAlignment="Center"
7 Width="20"
8 Height="20"
9 Stroke="{TemplateBinding Foreground}"
10 StrokeThickness="3" />
418
EPINGLER DES POINTS DINTRT
11 </StackPanel >
12 </ControlTemplate >
Et le contrle serait :
1 <carte:Map Name="Carte">
2 <toolkitcarte:MapExtensions.Children >
3 <toolkitcarte:Pushpin GeoCoordinate="{Binding
PositionTourEiffel}" Style="{StaticResource
PushpinControlTemplateEllipse}" Content="{Binding
Texte}" Foreground="Black" />
4 </toolkitcarte:MapExtensions.Children >
5 </carte:Map >
Pour le rsultat, observez la gure 27.13.
Figure 27.13 Le style avec une lgende
Et si on a plusieurs punaises lier ? On pourrait tre tents dutiliser le binding,
mais ce jour ce nest pas fonctionnel. Peut-tre un bug corriger ? On peut quand
mme sen sortir grce au code-behind. La premire chose faire est de dnir un
MapItemsControl possdant un template :
1 <carte:Map Name="Carte">
2 <toolkitcarte:MapExtensions.Children >
3 <toolkitcarte:MapItemsControl >
4 <toolkitcarte:MapItemsControl.ItemTemplate >
5 <DataTemplate >
419
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
6 <toolkitcarte:Pushpin GeoCoordinate="{
Binding}" Style="{StaticResource
PushpinControlTemplateEllipse}" />
7 </DataTemplate >
8 </toolkitcarte:MapItemsControl.ItemTemplate >
9 </toolkitcarte:MapItemsControl >
10 </toolkitcarte:MapExtensions.Children >
11 </carte:Map >
Il faudra ensuite lier par exemple une liste de positions ce MapItemsControl via
code-behind :
1 List <GeoCoordinate > maListeDePositions = new List <GeoCoordinate
>
2 {
3 new GeoCoordinate { Longitude = 2.321747 , Latitude = 48.
842276 },
4 new GeoCoordinate { Longitude = 2.294710 , Latitude = 48.
858115 },
5 new GeoCoordinate { Longitude = 2.294930 , Latitude = 48.
873783 }
6 };
7
8 MapItemsControl mapItemsControl = MapExtensions.GetChildren(
Carte).OfType <MapItemsControl >().FirstOrDefault ();
9 mapItemsControl.ItemsSource = maListeDePositions;
Comme ceci, cela fonctionne et donne le rsultat que vous voyez sur la gure 27.14.
Personnellement, jadore ces punaises !
Elles peuvent galement ragir un clic, ce qui nous laisse lopportunit dacher par
exemple des informations complmentaires sur cette position. On utilisera lvnement
Tap du contrle Pushpin. Sauf quen gnral, si on utilise une liste de positions comme
on la fait juste au-dessus, nous ne disposons pas dinformations susantes pour sa-
voir quelle punaise a t clique. Ce quon peut faire ce moment-l, cest utiliser
la proprit Tag du contrle, qui est une espce dobjet fourre-tout pour passer des
informations.
La proprit Tag est une proprit hrite de la classe FrameworkElement.
Tous les contrles possdent donc cette proprit fourre-tout.
Illustrons ce point en crant une nouvelle classe :
1 public class MaPosition
2 {
3 public GeoCoordinate Position { get; set; }
4 public string Informations { get; set; }
5 }
420
EPINGLER DES POINTS DINTRT
Figure 27.14 Plusieurs punaises lies par code-behind
Puis, changeons notre proprit MaListeDePositions pour avoir une liste dobjets
MaPosition :
1 private IEnumerable <MaPosition > maListeDePositions;
2 public IEnumerable <MaPosition > MaListeDePositions
3 {
4 get { return maListeDePositions; }
5 set { NotifyPropertyChanged(ref maListeDePositions , value);
}
6 }
Qui sera alimente de cette faon :
1 MaListeDePositions = new List <MaPosition >
2 {
3 new MaPosition { Position = new GeoCoordinate { Longitude =
2.321747 , Latitude = 48.842276 }, Informations = "Tour
Eiffel"},
4 new MaPosition { Position = new GeoCoordinate { Longitude =
2.294710 , Latitude = 48.858115 }, Informations = "Tour
Montparnasse"},
5 new MaPosition { Position = new GeoCoordinate { Longitude =
2.294930 , Latitude = 48.873783 }, Informations = "Arc
de triomphe"}
6 };
421
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
Puis changeons le XAML pour avoir :
1 <carte:Map Name="Carte">
2 <toolkitcarte:MapExtensions.Children >
3 <toolkitcarte:MapItemsControl ItemsSource="{Binding
PositionList}">
4 <toolkitcarte:MapItemsControl.ItemTemplate >
5 <DataTemplate >
6 <toolkitcarte:Pushpin GeoCoordinate="{
Binding Position}" Style="{
StaticResource
PushpinControlTemplateEllipse}" Tag="{
Binding Informations}" Tap="Pushpin_Tap"
/>
7 </DataTemplate >
8 </toolkitcarte:MapItemsControl.ItemTemplate >
9 </toolkitcarte:MapItemsControl >
10 </toolkitcarte:MapExtensions.Children >
11 </carte:Map >
Notons que la proprit GeoCoordinate de la punaise est lie la proprit Position
de notre classe et que la proprit Tag est lie la proprit Informations. Ce qui
nous permet, dans lvnement associ, de faire :
1 private void Pushpin_Tap(object sender , GestureEventArgs e)
2 {
3 MessageBox.Show ((( FrameworkElement)sender).Tag.ToString ());
4 }
Et nous aurons ce rsultat (voir la gure 27.15).
Pratique.
Acher un itinraire
Bonne nouvelle, avec Windows Phone 8, il est trs facile de calculer et dacher un
itinraire entre deux points. Prenons une carte classique :
1 <maps:Map x:Name="Carte" />
Et calculons dans le code-behind un itinraire entre des coordonnes de dpart, disons
la Tour Montparnasse, jusquaux Champs-lyses. Il sut dutiliser un objet Geo-
codeQuery - http://msdn.microsoft.com/en-us/library/windowsphone/develop/
jj208581(v=vs.105).aspx et de faire :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private List <GeoCoordinate > coordonnesTrajet;
4
5 public MainPage ()
422
AFFICHER UN ITINRAIRE
Figure 27.15 Le clic sur une punaise nous dclenche lachage dun message
6 {
7 InitializeComponent ();
8
9 Carte.ZoomLevel = 13;
10 Carte.Center = new GeoCoordinate { Latitude = 48.863134
, Longitude = 2.320518 };
11 coordonnesTrajet = new List <GeoCoordinate >();
12
13 CalculerItineraire ();
14 }
15
16 private void CalculerItineraire ()
17 {
18 GeoCoordinate positionDepart = new GeoCoordinate(48.
858115 , 2.294710);
19 coordonnesTrajet.Add(positionDepart);
20
21 GeocodeQuery geocodeQuery = new GeocodeQuery
22 {
23 SearchTerm = "avenue des champs -lyses , Paris"
,
24 GeoCoordinate = positionDepart
25 };
26
423
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
27 geocodeQuery.QueryCompleted +=
geocodeQuery_QueryCompleted;
28 geocodeQuery.QueryAsync ();
29 }
30
31 private void geocodeQuery_QueryCompleted(object sender ,
QueryCompletedEventArgs <IList <MapLocation >> e)
32 {
33 if (e.Error == null)
34 {
35 RouteQuery routeQuery = new RouteQuery ();
36 coordonnesTrajet.Add(e.Result[0]. GeoCoordinate);
37 routeQuery.Waypoints = coordonnesTrajet;
38 routeQuery.QueryCompleted +=
routeQuery_QueryCompleted;
39 routeQuery.QueryAsync ();
40 }
41 }
42
43 void routeQuery_QueryCompleted(object sender ,
QueryCompletedEventArgs <Route > e)
44 {
45 if (e.Error == null)
46 {
47 Carte.AddRoute(new MapRoute(e.Result));
48 }
49 }
50 }
Dans lobjet GeocodeQuery il sut de renseigner la destination souhaite et la mthode
QueryAsync() calcule automatiquement le trajet et nous fournit de quoi construire une
route ajouter la carte grce la mthode AddRoute. Remarquez que la destination
souhaite peut galement tre des coordonnes GPS.
Et nous aurons la gure 27.16.
Il est bien sr possible dappliquer la mme technique que pour le WebClient an de
pouvoir utiliser les mots-cls await et async. Il sut de rajouter ces mthodes dans
une classe dextensions :
1 public static class Extensions
2 {
3 public static Task <IList <MapLocation >> QueryLocationAsync(
this GeocodeQuery geocodeQuery)
4 {
5 TaskCompletionSource <IList <MapLocation >>
taskCompletionSource = new TaskCompletionSource <
IList <MapLocation >>();
6 EventHandler <QueryCompletedEventArgs <IList <MapLocation
>>> queryCompleteddHandler = null;
7 queryCompleteddHandler = (s, e) =>
424
AFFICHER UN ITINRAIRE
Figure 27.16 Calcul ditinraire entre deux points
8 {
9 geocodeQuery.QueryCompleted -=
queryCompleteddHandler;
10 if (e.Error != null)
11 taskCompletionSource.TrySetException(e.Error);
12 else
13 taskCompletionSource.TrySetResult(e.Result);
14 };
15
16 geocodeQuery.QueryCompleted += queryCompleteddHandler;
17 geocodeQuery.QueryAsync ();
18
19 return taskCompletionSource.Task;
20 }
21
22 public static Task <Route > QueryRouteAsync(this RouteQuery
routeQuery)
23 {
24 TaskCompletionSource <Route > taskCompletionSource = new
TaskCompletionSource <Route >();
25 EventHandler <QueryCompletedEventArgs <Route >>
queryCompleteddHandler = null;
26 queryCompleteddHandler = (s, e) =>
27 {
425
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
28 routeQuery.QueryCompleted -= queryCompleteddHandler
;
29 if (e.Error != null)
30 taskCompletionSource.TrySetException(e.Error);
31 else
32 taskCompletionSource.TrySetResult(e.Result);
33 };
34
35 routeQuery.QueryCompleted += queryCompleteddHandler;
36 routeQuery.QueryAsync ();
37
38 return taskCompletionSource.Task;
39 }
40 }
Et ensuite de faire :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private List <GeoCoordinate > coordonnesTrajet;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8
9 Carte.ZoomLevel = 13;
10 Carte.Center = new GeoCoordinate { Latitude = 48.863134
, Longitude = 2.320518 };
11 coordonnesTrajet = new List <GeoCoordinate >();
12
13 CalculerItineraire ();
14 }
15
16 private async void CalculerItineraire ()
17 {
18 GeoCoordinate positionDepart = new GeoCoordinate(48.
858115 , 2.294710);
19 coordonnesTrajet.Add(positionDepart);
20
21 GeocodeQuery geocodeQuery = new GeocodeQuery
22 {
23 SearchTerm = "avenue des champs -lyses , Paris",
24 GeoCoordinate = positionDepart
25 };
26
27 try
28 {
29 var resultat = await geocodeQuery.
QueryLocationAsync ();
30
31 RouteQuery routeQuery = new RouteQuery ();
426
AFFICHER UN ITINRAIRE
32 coordonnesTrajet.Add(resultat[0]. GeoCoordinate);
33 routeQuery.Waypoints = coordonnesTrajet;
34 var route = await routeQuery.QueryRouteAsync ();
35 Carte.AddRoute(new MapRoute(route));
36 }
37 catch (Exception)
38 {
39 }
40 }
41 }
Nous pouvons mme avoir les instructions de dplacement. Rajoutons une ListBox dans
le XAML :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="*" />
4 <RowDefinition Height="*" />
5 </Grid.RowDefinitions >
6 <maps:Map x:Name="Carte" />
7 <ListBox x:Name="ListeDirections" Grid.Row="1">
8 <ListBox.ItemTemplate >
9 <DataTemplate >
10 <TextBlock Text="{Binding}" />
11 </DataTemplate >
12 </ListBox.ItemTemplate >
13 </ListBox >
14 </Grid >
Que nous pouvons lier la liste dinstruction, obtenues ainsi :
1 try
2 {
3 var resultat = await geocodeQuery.QueryLocationAsync ();
4
5 RouteQuery routeQuery = new RouteQuery ();
6 coordonnesTrajet.Add(resultat[0]. GeoCoordinate);
7 routeQuery.Waypoints = coordonnesTrajet;
8 var route = await routeQuery.QueryRouteAsync ();
9 Carte.AddRoute(new MapRoute(route));
10
11 List <string > routeList = new List <string >();
12 foreach (RouteLeg leg in route.Legs)
13 {
14 foreach (RouteManeuver maneuver in leg.Maneuvers)
15 {
16 routeList.Add(maneuver.InstructionText);
17 }
18 }
19
20 ListeDirections.ItemsSource = routeList;
427
CHAPITRE 27. LE CONTRLE DE CARTES (MAP)
21 }
22 catch (Exception)
23 {
24 }
Ce qui donne la rsultat ach la gure 27.17.
Figure 27.17 Les instructions de litinraire
noter que si vous souhaitez calculer un itinraire piton, vous pouvez changer le
mode de calcul en modiant lobjet RouteQuery :
1 routeQuery.TravelMode = TravelMode.Walking;
En rsum
Le contrle Map est un contrle trs puissant qui nous permet dexploiter les
cartes du monde entier dans nos applications.
Il est possible dpingler des points dintrts grce aux objets PushPin du tool-
kit Windows Phone.
Le contrle de carte fournit de quoi calculer un itinraire, que lon peut acher
sur la carte.
428
Chapitre 28
TP : Une application mto
Dicult :
Bienvenue dans ce nouveau TP. Nous allons mettre en pratique les derniers lments que
nous avons appris, mais aussi des lments dj vus. Eh oui ! tant donn quils vont faire
partie intgrante de beaucoup de vos futures applications, vous vous devez de les matriser.
Bref, le but de ce TP sera de raliser une petite application mto tout fait fonctionnelle,
que vous pourrez exhiber devant vos amis : regardez, cest moi qui lai fait ! Allez, passons
sans plus attendre lnonc du TP.
429
CHAPITRE 28. TP : UNE APPLICATION MTO
Instructions pour raliser le TP
Il sagit donc de raliser une application mto. Cette application fournira les prvisions
dune ville grce au service web de mto de worldweatheronline. Pourquoi celui-l ?
Parce que je le trouve trs facile utiliser, vous le verrez par vous-mme et que cela
vous forcera manipuler du JSON, ce qui ne fait jamais de mal. Il ncessite cependant
une petite inscription pralable an de disposer dune cl dAPI, mais rassurez-vous,
tout est gratuit.
Notez que je nai pas dactions chez eux, vous ntes bien sr pas obligs de
vous inscrire (ou utilisez un email poubelle). Au tout dbut de la rdaction de
ce cours, jutilisais le service mto de Google, mais ils ont dcid de larrter,
me forant en trouver un autre.
Allez sur le lien - http://www.worldweatheronline.com/register.aspx et remplis-
sez le formulaire avec votre nom et votre email, ainsi que le captcha (voir la gure
28.1).
Aprs linscription, vous recevez un mail pour vrier votre compte, ainsi quune cl
dAPI une fois le mail vri. Avec cette cl dAPI, vous pourrez ensuite construire
votre requte. Par exemple pour obtenir la mto de Bordeaux 5 jours, jappellerai
lURL suivante :
1 http://free.worldweatheronline.com/feed/weather.ashx?q=Bordeaux
&format=json&num_of_days=5&key=MA_CLE_API
On peut donc prciser le nom de la ville dans le paramtre q, le type de format souhait
et le nombre de jours dinformations mtos souhaits (maxi 5). Jobtiens un JSON en
retour, du genre :
1 { "data" : { "current_condition" : [ ... abrg... ],
2 "request" : [ { "query" : "Bordeaux , France",
3 "type" : "City"
4 } ],
5 "weather" : [ { "date" : "2012 -11 -14",
6 "tempMaxC" : "17",
7 "tempMinC" : "8",
8 "weatherDesc" : [ { "value" : "Sunny" } ],
9 "weatherIconUrl" : [ { "value" : "http :// www.
worldweatheronline.com/images/wsymbols01_png_64/
wsymbol_0001_sunny.png" } ],
10 [...pur...]
11 },
12 { "date" : "2012 -11 -15",
13 [... abrg...]
14 },
15 { "date" : "2012 -11 -16",
16 [... abrg...]
17 },
18 { "date" : "2012 -11 -17",
430
INSTRUCTIONS POUR RALISER LE TP
Figure 28.1 Le formulaire de cration de compte
431
CHAPITRE 28. TP : UNE APPLICATION MTO
19 [... abrg...]
20 },
21 { "date" : "2012 -11 -18",
22 [... abrg...]
23 }
24 ]
25 } }
Nous pouvons voir quelques informations intressantes, comme la temprature mini,
la temprature maxi, une image qui illustre le temps prvu, la description du temps,
etc. Ah oui tiens, la description du temps est en anglais, il pourra tre judicieux de
se faire une petite matrice de traduction grce la liste que lon trouve ici : http:
//www.worldweatheronline.com/feed/wwoConditionCodes.xml.
Vous avez lhabitude maintenant du format JSON. Nous allons donc devoir exploiter
ces informations. Lapplication sera compose de 3 pages. La premire page prsentera
les direntes conditions mtos dans un Pivot qui nous permettra de consulter les
conditions mto du jour et des jours suivants. Vous acherez le nom de la ville, et
dans le pivot toutes les informations que nous possdons, de la faon que vous le sou-
haitez. Pendant le chargement des informations de mto, vous mettrez une barre de
progression indtermine an que lutilisateur ne soit pas perturb et ne croie lappli-
cation inactive. Cette page contiendra une barre dapplication contenant deux icnes
qui renverront vers une page permettant dajouter une ville et vers une autre page
permettant de slectionner une ville avec le ListPicker parmi la liste de toutes les villes
prcdemment ajoutes. Bien sr, lapplication retiendra la liste de toutes les villes
ajoutes ainsi que la dernire ville slectionne an dacher directement les condi-
tions mto de cette ville lors de la prochaine ouverture de lapplication.
Vous vous sentez prt ? Vous avez tout ce quil faut ? Alors, allez-y et crez une belle
application mto. Bon courage
Correction
Ah voil une petite application quelle est sympathique. Et utile en plus ! Cest toujours
pratique de pouvoir savoir sil vaut mieux prendre son parapluie ou ses tongues. Pour
raliser cette correction, nous allons commencer par crer la page qui permet dajouter
une ville, je lappelle Ajouter.xaml. Voici le XAML :
1 <phone:PhoneApplicationPage
2 x:Class="TpApplicationMeteo1.Ajouter"
3 ...
4
5 <Grid x:Name="LayoutRoot" Background="Transparent">
6 <Grid.RowDefinitions >
7 <RowDefinition Height="Auto"/>
8 <RowDefinition Height="*"/>
9 </Grid.RowDefinitions >
10
432
CORRECTION
11 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12
,17 ,0,28">
12 <TextBlock x:Name="ApplicationTitle" Text="Mto en
direct" Style="{StaticResource
PhoneTextNormalStyle}"/>
13 <TextBlock x:Name="PageTitle" Text="Ajouter une
ville" Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle2Style}"/>
14 </StackPanel >
15
16 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,
12 ,0">
17 <StackPanel >
18 <TextBlock Text="Nom de la ville" />
19 <TextBox x:Name="NomVille" />
20 <Button Content="Ajouter" Tap="Button_Tap" />
21 </StackPanel >
22 </Grid >
23 </Grid >
24 </phone:PhoneApplicationPage >
Elle nest pas trs complique, nous avons une zone de saisie permettant dindiquer
une ville et un bouton permettant dajouter la ville. Le code-behind est :
1 public partial class Ajouter : PhoneApplicationPage
2 {
3 public Ajouter ()
4 {
5 InitializeComponent ();
6 }
7
8 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
9 {
10 if (string.IsNullOrEmpty(NomVille.Text))
11 {
12 MessageBox.Show("Veuillez saisir un nom de ville");
13 }
14 else
15 {
16 IsolatedStorageSettings.ApplicationSettings["
DerniereVille"] = NomVille.Text;
17 List <string > nomVilles;
18 if (IsolatedStorageSettings.ApplicationSettings.
Contains("ListeVilles"))
19 nomVilles = (List <string >)
IsolatedStorageSettings.ApplicationSettings[
"ListeVilles"];
20 else
21 nomVilles = new List <string >();
22 nomVilles.Add(NomVille.Text);
433
CHAPITRE 28. TP : UNE APPLICATION MTO
23 IsolatedStorageSettings.ApplicationSettings["
ListeVilles"] = nomVilles;
24
25 if (NavigationService.CanGoBack)
26 NavigationService.GoBack ();
27 }
28 }
29 }
Aprs un test pour vrier quil y a bien un lment dans la zone de saisie, jenregistre
la ville dans le rpertoire local, en tant que dernire ville consulte et dans la liste
totale des villes dj enregistres. Bien sr, si cette liste nexiste pas, je la cre. Je
mautorise mme une petite navigation arrire aprs lenregistrement, fainant comme
je suis, pour viter davoir appuyer sur le bouton de retour arrire (voir la gure
28.2).
Figure 28.2 Lcran dajout de ville
Bon, cette page est plutt simple faire. Passons la page qui permet de choisir une
ville dj enregistre, je lappelle ChoisirVille.xaml. Le XAML sera :
1 <phone:PhoneApplicationPage
2 x:Class="TpApplicationMeteo1.ChoisirVille"
3 ...
4 xmlns:toolkit="clr -namespace:Microsoft.Phone.Controls;
assembly=Microsoft.Phone.Controls.Toolkit">
5
434
CORRECTION
6 <Grid x:Name="LayoutRoot" Background="Transparent">
7 <Grid.RowDefinitions >
8 <RowDefinition Height="Auto"/>
9 <RowDefinition Height="*"/>
10 </Grid.RowDefinitions >
11
12 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12
,17 ,0,28">
13 <TextBlock x:Name="ApplicationTitle" Text="Mto en
direct" Style="{StaticResource
PhoneTextNormalStyle}"/>
14 <TextBlock x:Name="PageTitle" Text="Choisir une
ville" Margin="9,-7,0,0" Style="{StaticResource
PhoneTextTitle2Style}"/>
15 </StackPanel >
16
17 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,
12 ,0">
18 <toolkit:ListPicker x:Name="Liste" ItemsSource="{
Binding ListeVilles}"
19 Header="Ville choisie :"
20 CacheMode="BitmapCache">
21 </toolkit:ListPicker >
22 </Grid >
23 </Grid >
24 </phone:PhoneApplicationPage >
Nous notons lutilisation du ListPicker et sa liaison la proprit ListeVilles. Il
a donc fallu importer lespace de nom du toolkit ainsi que rfrencer lassembly du
toolkit. Le code-behind sera :
1 public partial class ChoisirVille : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 public event PropertyChangedEventHandler PropertyChanged;
4
5 private void NotifyPropertyChanged(String propertyName)
6 {
7 PropertyChangedEventHandler handler = PropertyChanged;
8 if (null != handler)
9 {
10 handler(this , new PropertyChangedEventArgs(
propertyName));
11 }
12 }
13
14 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
15 {
16 if (object.Equals(variable , valeur)) return false;
17
435
CHAPITRE 28. TP : UNE APPLICATION MTO
18 variable = valeur;
19 NotifyPropertyChanged(nomPropriete);
20 return true;
21 }
22
23 private List <string > listeVilles;
24 public List <string > ListeVilles
25 {
26 get { return listeVilles; }
27 set { NotifyPropertyChanged(ref listeVilles , value); }
28 }
29
30 public ChoisirVille ()
31 {
32 InitializeComponent ();
33 DataContext = this;
34 }
35
36 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
37 {
38 if (! IsolatedStorageSettings.ApplicationSettings.
Contains("ListeVilles"))
39 {
40 MessageBox.Show("Vous devez ajouter des villes");
41 if (NavigationService.CanGoBack)
42 NavigationService.GoBack ();
43 }
44 else
45 {
46 ListeVilles = (List <string >) IsolatedStorageSettings
.ApplicationSettings["ListeVilles"];
47 if (ListeVilles.Count == 0)
48 {
49 MessageBox.Show("Vous devez ajouter des villes"
);
50 if (NavigationService.CanGoBack)
51 NavigationService.GoBack ();
52 }
53
54 if (IsolatedStorageSettings.ApplicationSettings.
Contains("DerniereVille"))
55 {
56 string ville = (string)IsolatedStorageSettings.
ApplicationSettings["DerniereVille"];
57 int index = ListeVilles.IndexOf(ville);
58 if (index >= 0)
59 Liste.SelectedIndex = index;
60 }
61 Liste.SelectionChanged += Liste_SelectionChanged;
436
CORRECTION
62 }
63 base.OnNavigatedTo(e);
64 }
65
66 protected override void OnNavigatedFrom(System.Windows.
Navigation.NavigationEventArgs e)
67 {
68 Liste.SelectionChanged -= Liste_SelectionChanged;
69 base.OnNavigatedFrom(e);
70 }
71
72 private void Liste_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
73 {
74 if (Liste.SelectedItem != null)
75 {
76 IsolatedStorageSettings.ApplicationSettings["
DerniereVille"] = (string)Liste.SelectedItem;
77 }
78 }
79 }
On commence par un petit test, sil ny a pas de ville choisir alors, nous navons rien
faire ici. Ensuite nous associons la proprit ListeVilles au contenu du rpertoire
local et nous rcuprons la dernire ville an de prslectionner le ListPicker avec la
ville dj choisie. Attention, lorsque nous slectionnons un lment ainsi, lvnement
de changement de slection est lev. Ce qui ne mintresse pas. Cest pour cela que
je me suis abonn cet vnement aprs avoir modi la proprit SelectedIndex.
Pour la propret du code, ceci implique que je me dsabonne de ce mme vnement
lorsque je quitte la page. Enn, en cas de changement de slection, jenregistre la ville
slectionne dans le rpertoire local. Pas trs compliqu non plus, part peut-tre la
petite astuce pour viter que lvnement de slection ne soit lev. De toute faon, ce
genre de chose se voit trs rapidement lorsque nous testons notre application, comme
vous pouvez le constater sur la gure 28.3.
Enn, il reste la page achant les conditions mto. Voici ma classe Meteo utilise,
ainsi que les classes gnres pour le mapping des donnes JSON :
1 public class Meteo
2 {
3 public string Date { get; set; }
4 public string TemperatureMin { get; set; }
5 public string TemperatureMax { get; set; }
6 public Uri Url { get; set; }
7 public string Temps { get; set; }
8 }
9
10 public class WeatherDesc
11 {
12 public string value { get; set; }
437
CHAPITRE 28. TP : UNE APPLICATION MTO
Figure 28.3 Lcran de choix dune ville
13 }
14
15 public class WeatherIconUrl
16 {
17 public string value { get; set; }
18 }
19
20 public class CurrentCondition
21 {
22 public string cloudcover { get; set; }
23 public string humidity { get; set; }
24 public string observation_time { get; set; }
25 public string precipMM { get; set; }
26 public string pressure { get; set; }
27 public string temp_C { get; set; }
28 public string temp_F { get; set; }
29 public string visibility { get; set; }
30 public string weatherCode { get; set; }
31 public List <WeatherDesc > weatherDesc { get; set; }
32 public List <WeatherIconUrl > weatherIconUrl { get; set; }
33 public string winddir16Point { get; set; }
34 public string winddirDegree { get; set; }
35 public string windspeedKmph { get; set; }
36 public string windspeedMiles { get; set; }
438
CORRECTION
37 }
38
39 public class Request
40 {
41 public string query { get; set; }
42 public string type { get; set; }
43 }
44
45 public class WeatherDesc2
46 {
47 public string value { get; set; }
48 }
49
50 public class WeatherIconUrl2
51 {
52 public string value { get; set; }
53 }
54
55 public class Weather
56 {
57 public string date { get; set; }
58 public string precipMM { get; set; }
59 public string tempMaxC { get; set; }
60 public string tempMaxF { get; set; }
61 public string tempMinC { get; set; }
62 public string tempMinF { get; set; }
63 public string weatherCode { get; set; }
64 public List <WeatherDesc2 > weatherDesc { get; set; }
65 public List <WeatherIconUrl2 > weatherIconUrl { get; set; }
66 public string winddir16Point { get; set; }
67 public string winddirDegree { get; set; }
68 public string winddirection { get; set; }
69 public string windspeedKmph { get; set; }
70 public string windspeedMiles { get; set; }
71 }
72
73 public class Data
74 {
75 public List <CurrentCondition > current_condition { get; set;
}
76 public List <Request > request { get; set; }
77 public List <Weather > weather { get; set; }
78 }
79
80 public class RootObject
81 {
82 public Data data { get; set; }
83 }
Voyons prsent le XAML de la page, qui sera donc MainPage.xaml :
439
CHAPITRE 28. TP : UNE APPLICATION MTO
1 <phone:PhoneApplicationPage
2 x:Class="TpApplicationMeteo1.MainPage"
3 ...>
4
5 <phone:PhoneApplicationPage.Resources >
6 <converter:VisibilityConverter x:Key="
VisibilityConverter" />
7 </phone:PhoneApplicationPage.Resources >
8
9 <Grid x:Name="LayoutRoot" Background="Transparent">
10 <Grid.RowDefinitions >
11 <RowDefinition Height="Auto"/>
12 <RowDefinition Height="*"/>
13 </Grid.RowDefinitions >
14
15 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12
,17 ,0,28">
16 <TextBlock x:Name="ApplicationTitle" Text="Mto en
direct" Style="{StaticResource
PhoneTextNormalStyle}"/>
17 </StackPanel >
18
19 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,
12 ,0">
20 <Grid.RowDefinitions >
21 <RowDefinition Height="auto" />
22 <RowDefinition Height="*" />
23 </Grid.RowDefinitions >
24 <ProgressBar IsIndeterminate="{Binding
ChargementEnCours}" Visibility="{Binding
ChargementEnCours ,Converter ={ StaticResource
VisibilityConverter }}" />
25 <TextBlock Text="{Binding NomVille}" Style="{
StaticResource PhoneTextTitle2Style}"/>
26 <phone:Pivot Grid.Row="1" ItemsSource="{Binding
ListeMeteo}">
27 <phone:Pivot.HeaderTemplate >
28 <DataTemplate >
29 <TextBlock Text="{Binding Date}" />
30 </DataTemplate >
31 </phone:Pivot.HeaderTemplate >
32 <phone:Pivot.ItemTemplate >
33 <DataTemplate >
34 <StackPanel >
35 <TextBlock Text="{Binding
TemperatureMin}" />
36 <TextBlock Text="{Binding
TemperatureMax}" />
37 <TextBlock Text="{Binding Temps}"
/>
440
CORRECTION
38 <Image Source="{Binding Url}" Width
="200" Height="200" Margin="0 50
0 0" HorizontalAlignment="
Center" />
39 </StackPanel >
40 </DataTemplate >
41 </phone:Pivot.ItemTemplate >
42 </phone:Pivot >
43 <TextBlock Text="Ajoutez une ville avec les boutons
en bas" Visibility="Collapsed" x:Name="
Information" />
44 </Grid >
45 </Grid >
46 <phone:PhoneApplicationPage.ApplicationBar >
47 <shell:ApplicationBar IsVisible="True">
48 <shell:ApplicationBarIconButton IconUri="/Assets/
Icones/add.png" Text="Ajouter" Click="
Ajouter_Click"/>
49 <shell:ApplicationBarIconButton IconUri="/Assets/
Icones/feature.settings.png" Text="Choisir"
Click="Choisir_Click"/>
50 </shell:ApplicationBar >
51 </phone:PhoneApplicationPage.ApplicationBar >
52
53 </phone:PhoneApplicationPage >
Tout dabord, regardons la barre dapplication tout en bas. Elle possde deux bou-
tons avec deux icnes. Il faudra bien sr rajouter ces icnes dans notre application,
en action de gnration gale contenu et en copie si plus rcent. Les deux boutons
permettent de naviguer vers nos deux pages, cres prcdemment. Ensuite, nous avons
une barre de progression, lie la proprit ChargementEnCours, que ce soit sa pro-
prit IsIndeterminate ou sa proprit Visibility. Nous avons galement le Pivot,
li la proprit ListeMeteo. Lentte du Pivot sera le nom du jour et les lments du
corps du pivot sont les diverses proprits de lobjet Meteo. Accompagnant le XAML,
nous aurons le code-behind suivant :
1 public partial class MainPage : PhoneApplicationPage ,
INotifyPropertyChanged
2 {
3 public event PropertyChangedEventHandler PropertyChanged;
4
5 private void NotifyPropertyChanged(String propertyName)
6 {
7 PropertyChangedEventHandler handler = PropertyChanged;
8 if (null != handler)
9 {
10 handler(this , new PropertyChangedEventArgs(
propertyName));
11 }
12 }
441
CHAPITRE 28. TP : UNE APPLICATION MTO
13
14 private bool NotifyPropertyChanged <T>(ref T variable , T
valeur , [CallerMemberName] string nomPropriete = null)
15 {
16 if (object.Equals(variable , valeur)) return false;
17
18 variable = valeur;
19 NotifyPropertyChanged(nomPropriete);
20 return true;
21 }
22
23 private List <Meteo > listeMeteo;
24 public List <Meteo > ListeMeteo
25 {
26 get { return listeMeteo; }
27 set { NotifyPropertyChanged(ref listeMeteo , value); }
28 }
29
30 private bool chargementEnCours;
31 public bool ChargementEnCours
32 {
33 get { return chargementEnCours; }
34 set { NotifyPropertyChanged(ref chargementEnCours ,
value); }
35 }
36
37 private string nomVille;
38 public string NomVille
39 {
40 get { return nomVille; }
41 set { NotifyPropertyChanged(ref nomVille , value); }
42 }
43
44 public MainPage ()
45 {
46 InitializeComponent ();
47 DataContext = this;
48 }
49
50 protected async override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
51 {
52 if (IsolatedStorageSettings.ApplicationSettings.
Contains("DerniereVille"))
53 {
54 Information.Visibility = Visibility.Collapsed;
55 ChargementEnCours = true;
56 NomVille = (string)IsolatedStorageSettings.
ApplicationSettings["DerniereVille"];
57 WebClient client = new WebClient ();
442
CORRECTION
58 try
59 {
60 ChargementEnCours = false;
61 string resultatMeteo = await client.
DownloadStringTaskAsync(new Uri(string.
Format("http :// free.worldweatheronline.com/
feed/weather.ashx?q={0}& format=json&
num_of_days=5&key=MA_CLE_API", NomVille.
Replace(' ', '+')), UriKind.Absolute));
62
63 RootObject resultat = JsonConvert.
DeserializeObject <RootObject >( resultatMeteo)
;
64 List <Meteo > liste = new List <Meteo >();
65 foreach (Weather temps in resultat.data.weather
.OrderBy(w => w.date))
66 {
67 Meteo meteo = new Meteo { TemperatureMax =
temps.tempMaxC + " C", TemperatureMin =
temps.tempMinC + " C" };
68 DateTime date;
69 if (DateTime.TryParse(temps.date , out date)
)
70 {
71 meteo.Date = date.ToString("dddd dd
MMMM");
72 meteo.Temps = GetTemps(temps.
weatherCode);
73 WeatherIconUrl2 url = temps.
weatherIconUrl.FirstOrDefault ();
74 if (url != null)
75 {
76 meteo.Url = new Uri(url.value ,
UriKind.Absolute);
77 }
78 }
79 liste.Add(meteo);
80 }
81 ListeMeteo = liste;
82 }
83 catch (Exception)
84 {
85 MessageBox.Show("Impossible de rcuprer les
informations de mto, vrifiez votre
connexion internet");
86 }
87 }
88 else
89 Information.Visibility = Visibility.Visible;
90
443
CHAPITRE 28. TP : UNE APPLICATION MTO
91 base.OnNavigatedTo(e);
92 }
93
94 private string GetTemps(string code)
95 {
96 // complter ...
97 switch (code)
98 {
99 case "113":
100 return "Clair / Ensoleill";
101 case "116":
102 return "Partiellement nuageux";
103 case "119":
104 return "Nuageux";
105 case "296":
106 return "Faible pluie";
107 case "353":
108 return "Pluie";
109 default:
110 return "";
111 }
112 }
113
114 private void Ajouter_Click(object sender , EventArgs e)
115 {
116 NavigationService.Navigate(new Uri("/Ajouter.xaml",
UriKind.Relative));
117 }
118
119 private void Choisir_Click(object sender , EventArgs e)
120 {
121 NavigationService.Navigate(new Uri("/ChoisirVille.xaml"
, UriKind.Relative));
122 }
123 }
On commence par tester si la dernire ville consulte existe bien. Si ce nest pas le
cas, nous achons un petit message pour dire quoi faire. Puis nous dmarrons le t-
lchargement des conditions de mto, sans oublier danimer la barre de progression.
Aprs avoir attendu la n du tlchargement (mot cl await), nous pouvons utiliser
JSON.NET pour extraire les conditions mto et les mettre dans la proprit lie au
Pivot. Nous remarquons au passage ma technique hautement labore pour obtenir une
traduction de la description du temps. . . Quoi il manque des traductions ? Nhsitez
pas complter avec les vtres . . . Enn, les deux mthodes de clic sur les boutons
de la barre dapplication appellent simplement le service de navigation (voir la gure
28.4).
Et si vous griez lorientation multiple maintenant ?
444
CORRECTION
Figure 28.4 Achage de la mto
445
CHAPITRE 28. TP : UNE APPLICATION MTO
446
Quatrime partie
Un tlphone ouvert vers
lextrieur
447
Chapitre 29
La gestuelle
Dicult :
Au contraire de la gnration prcdente, Windows Mobile, les Windows Phone sont utili-
sables exclusivement avec les doigts. Cela peut paraitre vident, mais un doigt est beaucoup
plus large que le pointeur dune souris. Pour les dveloppeurs qui sont habitus crer des
applications ou des sites web utilisables avec une souris, il faut prendre conscience que les
zones qui sont touchables par un doigt doivent tre tailles en consquence. De plus, les
crans des Windows Phone sont multipoints, cest--dire que nous pouvons exercer plu-
sieurs points de pressions simultans, avec notamment plusieurs doigts. Ce qui ore tout
une gamme de nouvelles faons dapprhender linteraction avec lutilisateur. Malheureuse-
ment, il est dicile de faire du multipoint avec une souris dans lmulateur. Il est prfrable
dans ce cas dutiliser directement un tlphone.
449
CHAPITRE 29. LA GESTUELLE
Le simple toucher
Nous lavons vu plusieurs reprises, cest le mode dinteraction le plus pratique et
le plus naturel pour lutilisateur. Il utilise un doigt pour toucher lcran. Geste trs
classique qui ressemble trs fortement un clic dune souris. Le doigt est utilis pour
slectionner un lment. En gnral, les contrles qui ont besoin dtre slectionns par
une pression exposent un vnement Tap. Cest le cas par exemple des boutons que
nous avons vu :
1 <Button x:Name="MonBouton" Content="Cliquez -moi" Tap="
MonBouton_Tap" />
Ils exposent galement un vnement Click :
1 <Button x:Name="MonBouton" Content="Cliquez -moi" Click="
MonBouton_Click_1" />
Nous lavons vu par exemple sur la barre dapplication, mais il est prsent un peu
partout. Cet vnement est hrit de Silverlight pour PC, il reste cependant utilisable
mais il est dconseill pour des raisons notamment de performance. Nous lui prfrerons
lvnement Tap, comme on la dj vu. Il existe dautres vnements, toujours hrits
de Silverlight, comme lvnement MouseLeftButtonDown :
1 <Rectangle Width="200" Height="200" Fill="Aqua"
MouseLeftButtonDown="Rectangle_MouseLeftButtonDown" />
Il correspond lvnement qui est lev lorsque lon touche un contrle. Lvnement
MouseLeftButtonUp est quant lui lev quand le doigt est relev. Mais le toucher
simple ne sert pas qu cliquer , il permet galement darrter un dlement. Voyez
par exemple lorsque vous faites dler une ListBox bien remplie, si vous touchez la
ListBox et que vous lancez le doigt vers le bas, la liste dle vers le bas en fonction de la
vitesse laquelle vous avez lanc le doigt (ce mouvement sappelle le Flick ). Si vous
retouchez la ListBox, le dlement sarrtera. Tous ces toucher sont grs nativement
par beaucoup de contrles XAML. Il est alors trs simple de ragir un toucher.
Les dirents touchers
Dautres touchers sont utilisables, notamment le double-toucher, que lon peut rappro-
cher du double-clic bien connu des utilisateurs de Windows. Il correspond lvnement
DoubleTap. Gnralement peu utilis, il peut servir eectuer un zoom, comme dans
Internet Explorer.
Nous connaissons un autre toucher, que lon utilise pour faire dler une ListBox par
exemple. Il sappelle le pan et consiste toucher lcran et maintenir le toucher
tout en bougeant le doigt dans nimporte quelle direction. Cette gestuelle ressemble au
drag & drop que lon connait sous Windows. Dans le mme genre, il existe le ick
qui correspond un toucher puis un mouvement rapide dans une direction. Cest
ce mouvement que lon utilise dans le contrle Pivot par exemple, et qui ressemble
450
GESTUELLE AVANCE
un tourner de page. Ce ick est galement utilis dans la ListBox pour eectuer un
fort dlement. Notons encore un autre toucher, le touch and hold qui correspond
un clic long . On maintient le doigt appuy pendant un certain temps. En gnral,
cela fait apparatre un menu contextuel. Enn, nous avons le pinch et le stretch qui
consistent, avec deux doigts rapprocher ou carter ses doigts. Cest ce mouvement
qui est utilis pour zoomer et d-zoomer.
Il ny a pas de support pour ces gestuelles volues dans les contrles Windows Phone,
aussi si nous souhaitons les utiliser nous allons devoir implmenter par nous-mme ces
gestuelles. Certaines sont plus ou moins faciles. Pour ceux par exemple qui ont dj
implment un drag & drop dans des applications Windows, il devient assez facile dim-
plmenter le Pan grce aux vnements MouseLeftButtonDown, MouseLeftButtonUp
et MouseMove (qui correspond la souris qui bouge).
Gestuelle avance
Dautres vnements un peu plus complexes sont galement disponibles sur nos
contrles, il sagit des vnements ManipulationStarted, ManipulationDelta, et
ManipulationCompleted. Ce qui est intressant dans ces vnements cest quils
fournissent un paramtre avec beaucoup dinformations sur le toucher. Lvnement
ManipulationStarted est lev au dmarrage de la manipulation fournissant la po-
sition dun ou plusieurs points de pression. Au fur et mesure de la gestuelle, cest
lvnement ManipulationDelta qui est lev fournissant des informations par exemple
sur les translations opres. Enn, la n de la manipulation, cest lvnement
ManipulationCompleted qui est lev. Par exemple, on pourrait se servir de ces v-
nements pour dterminer la gestuelle du ick car cet vnement fourni la vlocit
nale du mouvement ainsi que la translation totale. La translation nous renseigne sur
la direction du mouvement et la vlocit nous permet de savoir sil sagit rellement
dun ick et sa puissance .
Bref, ces vnements peuvent fournir beaucoup dinformations sur la gestuelle en cours,
mais cest nous de fournir du code pour interprter ces mouvements, ce qui nest pas
toujours simple. . .
Je pourrais vous faire une petite dmonstration, mais . . . il y a mieux !
Le toolkit la rescousse
Heureusement, dautres personnes ont raliss ces calculs pour nous. Ouf ! Mme si cela
pourrait tre trs intressant de prendre en compte des considrations de moteur phy-
sique pour dterminer la puissance dun ick, il savre que cest une tche fastidieuse.
Cest l quintervient nouveau le toolkit et ses contrles de gestuelle.
Prenez justement le Flick, il sut de faire dans le XAML :
1 <Rectangle Width="300" Height="300" Fill="Aqua">
2 <toolkit:GestureService.GestureListener >
451
CHAPITRE 29. LA GESTUELLE
3 <toolkit:GestureListener
4 Flick="GestureListener_Flick" />
5 </toolkit:GestureService.GestureListener >
6 </Rectangle >
On utilise la proprit attache GestureListener et on sabonne lvnement Flick.
Ainsi, dans le code-behind on pourra avoir :
1 private void GestureListener_Flick(object sender ,
FlickGestureEventArgs e)
2 {
3 switch (e.Direction)
4 {
5 case System.Windows.Controls.Orientation.Horizontal:
6 MessageBox.Show("Flick horizontal , angle : " + e.
Angle);
7 break;
8 case System.Windows.Controls.Orientation.Vertical:
9 MessageBox.Show("Flick vertical , angle : " + e.
Angle);
10 break;
11 }
12 }
Ce qui est quand mme super simple pour interprter un ick.
Nhsitez pas tester ce code, la gestuelle est dicile faire passer avec des
copies dcrans.
Dautres gestuelles sont gres avec les vnements suivants :
vnement Description
Tap Simple toucher
DoubleTap Deux touchers rapprochs
Flick Mouvement rapide dans une direction
DragStarted, DragDelta,
DragCompleted
Utiliss pour le mouvement du Pan
Hold Reprsente le toucher long
PinchStarted, PinchDelta,
PinchCompleted
Pour le mouvement du zoom
GestureBegin, GestureCompleted Classe de base pour toutes les gestuelles
Chaque vnement possde un paramtre qui fournit des informations complmentaires
sur la gestuelle. Par exemple, le PinchDelta fournit des informations sur langle de
rotation ou sur la distance parcourue lors du mouvement.
Pour nir, nous allons illustrer lvnement DragDelta pour dplacer notre rectangle
grce une transformation :
452
LE TOOLKIT LA RESCOUSSE
1 <Rectangle Width="300" Height="300" Fill="Aqua">
2 <Rectangle.RenderTransform >
3 <CompositeTransform x:Name="Transformation"/>
4 </Rectangle.RenderTransform >
5 <toolkit:GestureService.GestureListener >
6 <toolkit:GestureListener DragDelta="
GestureListener_DragDelta" />
7 </toolkit:GestureService.GestureListener >
8 </Rectangle >
Et dans le code behind :
1 private void GestureListener_DragDelta(object sender ,
DragDeltaGestureEventArgs e)
2 {
3 Transformation.TranslateX += e.HorizontalChange;
4 Transformation.TranslateY += e.VerticalChange;
5 }
Dicile dillustrer ce mouvement avec une copie dcran, mais nhsitez pas tester
cet exemple. Vous verrez que le rectangle bouge en fonction de votre mouvement de
type Pan.
Merci le Windows Phone Toolkit !
En rsum
Les Windows Phone tant utilisables exclusivement avec les doigts, il est impor-
tant de bien grer les gestuelles en utilisant les vnements des contrles.
Le Windows Phone Toolkit nous aide fortement dans limplmentation de ces
gestuelles.
453
CHAPITRE 29. LA GESTUELLE
454
Chapitre 30
Lacclromtre
Dicult :
Chaque Windows Phone est quip dun acclromtre. Il sagit dun capteur qui permet
de mesurer lacclration linaire suivant les trois axes dans lespace. Ainsi, tout moment,
on peut connaitre la direction et lacclration de la pesanteur qui sexerce sur le tlphone.
Ceci peut nous permettre de raliser des petites applications sympathiques en nous servant
de lorientation du tlphone comme dune interface avec lutilisateur. Dautres capteurs
facultatifs existent sur un Windows Phone, comme le gyroscope ou le compas.
Voyons comment nous en servir.
455
CHAPITRE 30. LACCLROMTRE
Utiliser lacclromtre
Si le tlphone est pos sur la table et que la table est bien horizontale, nous allons
pouvoir dtecter une acclration d1g sur laxe des Z, qui correspond la force de
lapesanteur. Si lcran est tourn vers le haut, alors lacclration sera de (0, 0, -1) -
voir la gure 30.1.
Figure 30.1 Acclration sur laxe des Z
Bien sr, lacclromtre nest pas g dans cette position, la valeur oscille sans arrt
et vous aurez plus vraisemblablement une valeur comme (0,02519062, -0,05639198, -
0,994348). . .
Pour utiliser lacclromtre, vous allez devoir importer lespace de nom :
1 using Microsoft.Devices.Sensors;
tant donn que lacclromtre fourni un objet de Type Vector3, qui fait partie
de la bibliothque XNA, nous aurons besoin dajouter une rfrence lassembly
Microsoft.Xna.Framework.dll (uniquement dans les versions 7.X car pour le SDK
8, la rfrence est dj ajoute).
Il sut ensuite de sabonner lvnement de changement de valeur et de dmarrer
lacclromtre :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private Accelerometer accelerometre;
4 public MainPage ()
456
UTILISER LACCLROMTRE AVEC LMULATEUR
5 {
6 InitializeComponent ();
7 accelerometre = new Accelerometer ();
8 accelerometre.CurrentValueChanged +=
accelerometre_CurrentValueChanged;
9 accelerometre.Start ();
10 }
11
12 private void accelerometre_CurrentValueChanged(object
sender , SensorReadingEventArgs <AccelerometerReading > e)
13 {
14 Dispatcher.BeginInvoke (() => Valeurs.Text = e.
SensorReading.Acceleration.X + ", " + e.
SensorReading.Acceleration.Y + ", " + e.
SensorReading.Acceleration.Z);
15 }
16 }
On utilisera le Dispatcher pour pouvoir mettre jour notre contrle dans le thread
ddi linterface :
1 <TextBlock x:Name="Valeurs" />
Cet vnement nous fournit les 3 valeurs des dirents axes. Par contre, partir du
moment o nous dmarrons lacclromtre, nous recevrons un paquet de positions
trs rgulirement. Il est important de pouvoir faire du tri l-dedans. Ne vous in-
quitez pas si vos valeurs oscillent dans une petite fourchette, cest normal. Mme
si vous tes le plus immobile possible. Suivant vos besoins, vous aurez peut-tre be-
soin de lisser les informations obtenus, par exemple en faisant une moyenne sur les
X dernires valeurs. Une autre solution est dutiliser une formule un peu plus com-
pliqu, issue du traitement du signal. Je ne rentrerai pas dans ces dtails car nous
nen aurons pas besoin mais vous pouvez retrouver quelques informations en anglais
cette adresse - http://windowsteamblog.com/windows_phone/b/wpdev/archive/
2010/09/08/using-the-accelerometer-on-windows-phone-7.aspx.
Utiliser lacclromtre avec lmulateur
Alors, lacclromtre, cest trs bien avec un tlphone, mais comment faire lorsque
nous navons pas encore appris dployer une application sur notre tlphone ? Cela
semble dicile dorienter notre PC pour faire croire lmulateur que nous sommes en
train de bouger. . . Heureusement, il existe une autre solution : les outils de lmulateur.
On peut les dmarrer en cliquant sur le dernier bouton de sa barre droite, comme
indiqu sur la gure 30.2.
Dans le premier onglet des outils, nous avons de quoi simuler lacclromtre (voir la
gure 30.3).
Il sut de slectionner le petit point orange pour simuler une acclration du tlphone.
Vous pouvez utiliser la liste droulante en bas gauche pour changer lorientation du
457
CHAPITRE 30. LACCLROMTRE
Figure 30.2 Accder aux outils de lmulateur
Figure 30.3 En dplaant le rond orange, nous simulons une acclration du tl-
phone
458
EXPLOITER LACCLROMTRE
tlphone an de faciliter lutilisation de lacclromtre. De mme, la liste en bas
droite permet de simuler un secouage de tlphone. . .
Exploiter lacclromtre
Maintenant que nous savons titiller lacclromtre de lmulateur, utilisons ds pr-
sent les valeurs brutes de lacclromtre pour raliser une petite application o nous
allons faire bouger une balle en bougeant notre tlphone. Nous avons dit que lorsquon
tient le tlphone plat, cran vers le haut, nous avons une acclration de (0,0,-1).
Lorsquon incline le tlphone vers la gauche, on tend vers lacclration suivante (-
1,0,0). Lorsquon incline vers la droite, on tend vers lacclration (1,0,0). De la mme
faon, lorsquon incline le tlphone vers lavant, on tend vers (0,1,0) et lorsquon incline
vers nous, on tend vers (0,-1,0).
On peut donc utiliser la force des composantes du vecteur pour faire bouger notre balle.
Utilisons un Canvas et ajoutons un cercle dedans :
1 <phone:PhoneApplicationPage
2 x:Class="DemoAccelerometre.MainPage"
3 ...>
4
5 <Canvas x:Name="LayoutRoot" Background="Transparent" Width=
"480" Height="800" >
6 <Ellipse x:Name="Balle" Fill="Blue" Width="50" Height="
50" />
7 </Canvas >
8
9 </phone:PhoneApplicationPage >
Dans le code-behind, nous prendrons gare dmarrer et arrter lacclromtre, puis
il sura de rcuprer les coordonnes de la balle et de les modier en fonction des
composantes du vecteur :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private Accelerometer accelerometre;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8
9 Balle.SetValue(Canvas.LeftProperty , LayoutRoot.Width /
2);
10 Balle.SetValue(Canvas.TopProperty , LayoutRoot.Height /
2);
11
12 accelerometre = new Accelerometer ();
13 accelerometre.CurrentValueChanged +=
accelerometre_CurrentValueChanged;
459
CHAPITRE 30. LACCLROMTRE
14 }
15
16 private void accelerometre_CurrentValueChanged(object
sender , SensorReadingEventArgs <AccelerometerReading > e)
17 {
18 Dispatcher.BeginInvoke (() =>
19 {
20 double x = (double)Balle.GetValue(Canvas.
LeftProperty) + e.SensorReading.Acceleration
.X;
21 double y = (double)Balle.GetValue(Canvas.
TopProperty) - e.SensorReading.Acceleration.
Y;
22
23 if (x <= 0)
24 x = 0;
25 if (y <= 0)
26 y = 0;
27 if (x >= LayoutRoot.Width - Balle.Width)
28 x = LayoutRoot.Width - Balle.Width;
29 if (y >= LayoutRoot.Height - Balle.Height)
30 y = LayoutRoot.Height - Balle.Height;
31
32 Balle.SetValue(Canvas.LeftProperty , x);
33 Balle.SetValue(Canvas.TopProperty , y);
34 });
35 }
36
37 protected override void OnNavigatedFrom(System.Windows.
Navigation.NavigationEventArgs e)
38 {
39 accelerometre.Stop();
40 base.OnNavigatedFrom(e);
41 }
42
43 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
44 {
45 accelerometre.Start ();
46 base.OnNavigatedTo(e);
47 }
48 }
Et voil, notre cercle bouge en fonction de lorientation du tlphone. Remarquez que
pour avoir un mouvement naturel, nous avons invers laxe des Y en ralisant une
soustraction. Bon, cest bien mais la balle navance pas trs vitre. Il pourrait tre
judicieux dappliquer un facteur de vitesse, par exemple :
1 double vitesse = 3.5;
2 double x = (double)Balle.GetValue(Canvas.LeftProperty) + e.
SensorReading.Acceleration.X * vitesse;
460
LES AUTRES CAPTEURS FACULTATIFS
3 double y = (double)Balle.GetValue(Canvas.TopProperty) - e.
SensorReading.Acceleration.Y * vitesse;
La balle va cette fois-ci un peu plus vite. Mais elle pourrait avoir un peu plus dinertie, et
notamment freiner lorsquon redresse le tlphone. Noubliez pas que plus le tlphone
est plat et plus Z tend vers -1. On peut donc trouver une formule o le fait que le
tlphone soit plat ralentisse la balle, en divisant par exemple par la valeur absolue de
Z :
1 double facteur = e.SensorReading.Acceleration.Z == 0 ? 0.00001
: Math.Abs(e.SensorReading.Acceleration.Z);
2 double vitesse = 3.5;
3 double x = (double)Balle.GetValue(Canvas.LeftProperty) + e.
SensorReading.Acceleration.X * vitesse / facteur;
4 double y = (double)Balle.GetValue(Canvas.TopProperty) - e.
SensorReading.Acceleration.Y * vitesse / facteur;
Bon, on est loin dun vrai moteur physique simulant lacclration, mais cest dj un
peu mieux.
Attention faire en sorte que Z soit toujours dirent de zro, sinon cest la
mga honte. Je crois que diviser par zro cest vraiment la pire des exceptions
que lon peut avoir.
Attention, noubliez pas darrter lacclromtre quand vous avez ni avec lui grce
la mthode Stop() an dconomiser la batterie. Cest ce que je fais dans la mthode
OnNavigatedFrom().
Les autres capteurs facultatifs
Lacclromtre est le seul capteur obligatoire dans les spcications dun Windows
Phone. Mais il y a dautres capteurs facultatifs qui peuvent faire partie dun Windows
Phone. Il y a notamment le compas (ou le magntomtre). Il permet de connaitre
lemplacement du ple nord magntique et peut servir faire une boussole par exemple.
tant facultatif, il faudra penser vrier sil est prsent avec :
1 if (! Compass.IsSupported)
2 {
3 MessageBox.Show("Votre tlphone ne possde pas de compas")
;
4 }
De mme, le gyroscope est facultatif sur les Windows Phone. Il sert mesurer la
vitesse de rotation suivant les trois axes. Il est dirent de lacclromtre. Pour voir la
dirence entre les deux, imaginez-vous debout avec le tlphone en position portrait
devant vous, face au nord. Si vous faites un quart de tour vers la droite, vous vous
retrouvez face lest, le tlphone na pas chang de position dans vos mains, mais il
461
CHAPITRE 30. LACCLROMTRE
a subi une rotation suivant un axe. Cette rotation, cest le gyroscope qui va tre en
mesure de vous la fournir. Pour lacclromtre, pensez notre petite application de
balle ralise plus haut. Pour tester sa prsence, vous pourrez faire :
1 if (! Gyroscope.IsSupported)
2 {
3 MessageBox.Show("Votre tlphone ne possde pas de
gyroscope");
4 }
Il vous faudra peut-tre adapter le comportement de votre application en consquence,
ou prvenir lutilisateur quelle est inutilisable sans gyroscope.
La motion API
Travailler avec tous ces capteurs en mme temps est plutt complexe. De plus, si jamais
il manque au tlphone un capteur que vous souhaitez utiliser, il vous faut revoir vos
calculs pour adapter votre application. Cest l quintervient la motion API, que lon
peut traduire en API de mouvement. Elle permet de grer toute la logique mathma-
tique associe ces trois capteurs an de fournir des valeurs facilement exploitables.
Au nal, on arrive trs facilement dterminer comment le tlphone est orient dans
lespace. Cela permet par exemple de transposer le tlphone dans un monde 3D vir-
tuel, permettant les applications de ralit augmente, les jeux et pourquoi pas des
applications auxquelles nous navons pas encore pens. . .
La motion API sutilise grosso modo comme lacclromtre. Elle nous fournit plusieurs
valeurs avec notamment une proprit Attitude que lon peut traduire en assiette ,
dans le langage de laviation, qui permet dobtenir lorientation de lavion dans les-
pace. Cette proprit nous fournit plusieurs valeurs intressantes qui, toujours dans le
domaine de laviation, sont :
Yaw : qui indique la direction par rapport au nez de lavion, an de savoir si
lavion tourne droite ou gauche ;
Pitch : qui indique si le nez de lavion monte ou descend;
Roll : qui permet de savoir si lavion bascule sur la droite ou la gauche.
Grosso modo, imaginons que vous ayez le tlphone pos sur la table devant vous, avec
les boutons proches de vous :
Si vous lui faite faire une rotation sur la table, tout en le conservant pos sur la
table, alors vous changez le Yaw.
Si vous levez le tlphone pour lavoir en position verticale, alors vous changez
le pitch.
Si vous basculez le tlphone pour le mettre sur sa tranche, alors vous changez
le roll.
On peut le reprsenter ainsi (voir la gure 30.4).
Mme si je ne doute pas de la qualit de mon dessin ( :- ), le mieux pour comprendre
est de lexprimenter sur un vrai tlphone. Pour obtenir ces valeurs, il vous sut
462
LA MOTION API
Figure 30.4 Assiette dun tlphone
de dclarer un objet Motion et de vous abonner lvnement CurrentValueChanged.
Notez que vous pouvez utiliser un petit Helper venant du framework XNA an dobtenir
un angle partir de cette valeur.
Utilisez donc le XAML suivant :
1 <TextBlock x:Name="Yaw" />
2 <TextBlock x:Name="Pitch" />
3 <TextBlock x:Name="Roll" />
Avec le code-behind :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 Motion motion;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8 }
9
10 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
11 {
12 if (! Motion.IsSupported)
13 {
14 MessageBox.Show("L'API Motion n'est pas supporte
sur ce tlphone.");
463
CHAPITRE 30. LACCLROMTRE
15 return;
16 }
17
18 if (motion == null)
19 {
20 motion = new Motion { TimeBetweenUpdates = TimeSpan
.FromMilliseconds(20) };
21 motion.CurrentValueChanged +=
motion_CurrentValueChanged;
22 }
23
24 try
25 {
26 motion.Start();
27 }
28 catch (Exception ex)
29 {
30 MessageBox.Show("Impossible de dmarrer l'API.");
31 }
32 }
33
34 private void motion_CurrentValueChanged(object sender ,
SensorReadingEventArgs <MotionReading > e)
35 {
36 Dispatcher.BeginInvoke (() =>
37 {
38 if (motion.IsDataValid)
39 {
40 float yaw = MathHelper.ToDegrees(e.
SensorReading.Attitude.Yaw);
41 float pitch = MathHelper.ToDegrees(e.
SensorReading.Attitude.Pitch);
42 float roll = MathHelper.ToDegrees(e.
SensorReading.Attitude.Roll);
43
44 Yaw.Text = "Yaw : " + yaw + " ";
45 Pitch.Text = "Pitch : " + pitch + " ";
46 Roll.Text = "Roll : " + roll + " ";
47 }
48 });
49 }
50 }
Pour utiliser le MathHelper, il faudra inclure lespace de nom suivant :
1 using Microsoft.Xna.Framework;
Lobjet Motion est quant lui disponible avec :
1 using Microsoft.Devices.Sensors;
464
LA MOTION API
Vous ne pourrez malheureusement pas tester lAPI motion dans lmulateur,
celle-ci nest pas supporte. Et vous ne savez pas encore comment dployer
une application sur votre tlphone, sauf si vous tes alls vers la n du cours
en avance !
En plus de lassiette, lAPI motion fourni dautres valeurs :
DeviceAcceleration, qui est la mme chose que ce que lon obtient avec lac-
clromtre.
DeviceRotationRate, qui est la mme chose que ce que lon obtient avec le
gyroscope.
Gravity, qui renvoie un vecteur en direction du centre de la terre, pour repr-
senter la gravit, comme avec lacclromtre.
Vous avez compris que ces valeurs peuvent tre obtenues avec les mthodes propres
aux capteurs et que ce qui est vraiment intressant, ce sont les valeurs calcules de
lassiette.
En rsum
Lacclromtre est un capteur obligatoire sur tout tlphone Windows Phone
qui nous ore de nouvelles faons dinteragir avec notre utilisateur.
Il est facile muler grce aux outils de lmulateur Windows Phone.
Dautres capteurs facultatifs existent, comme le gyroscope ou le compas.
La motion API nous simplie grandement la dtection de lorientation du tl-
phone dans lespace et nous ouvre les portes de la ralit augmente.
465
CHAPITRE 30. LACCLROMTRE
466
Chapitre 31
TP : Jeux de hasard (Grattage et
secouage)
Dicult :
Ahhh, a commence devenir sympa ce quon peut faire ! Lcran tactile et la gestuelle
associe, ainsi que lacclromtre sont des outils vraiment intressant utiliser. Et puis cela
nous oblige sortir de la classique souris et imaginer des nouveaux types dinteractions
avec lutilisateur. Nous allons donc mettre en pratique ces derniers lments dans ce nouveau
TP o nous allons crer une petite application de jeu de hasard, dcoupe en deux petits
jeux qui vont utiliser la gestuelle et lacclromtre.
467
CHAPITRE 31. TP : JEUX DE HASARD (GRATTAGE ET SECOUAGE)
Instructions pour raliser le TP
Crez dans un premier temps une page de menu qui renverra vers une page o nous
aurons un jeu de grattage et une autre page o nous aurons un jeu de secouage. . . Le
jeu en lui-mme ne sera pas super volu et peu esthtique car je souhaite que vous
vous concentriez sur les techniques tudies prcdemment, mais rien ne vous empche
de laisser courir votre imagination et de raliser la prochaine killer-app.
Donc, le grattage, je propose quil sagisse dacher 3 rectangles que lon peut gratter.
Une fois ces rectangles gratts, ils dcouvrent si nous avons gagn ou pas. Un tirage
alatoire est fait pour dterminer le rectangle gagnant et une fois que nous avons
commenc gratter un rectangle, il nest plus possible den gratter un autre. Pas
besoin de gratter tout le rectangle, vous pourrez acher la victoire ou la dfaite de
lutilisateur une fois un certain pourcentage du rectangle gratt. Noubliez pas dorir
lutilisateur la possibilit de rejouer et de voir le nombre de parties gagnes. Voici
la gure 31.1 le rsultat que je vous propose datteindre.
Figure 31.1 Le grattage
Passons maintenant au secouage. Le principe est de dtecter via lacclromtre lorsque
lutilisateur secoue son tlphone. ce moment-l, nous pourrons gnrer un nombre
alatoire avec une chance sur 3 de gagner. Pourquoi ne pas faire mariner un peu luti-
lisateur en lui achant une barre de progression indtermine et en attendant deux
secondes pour acher le rsultat. Voici la gure 31.2 le rsultat que je vous propose
datteindre.
468
INSTRUCTIONS POUR RALISER LE TP
Figure 31.2 Le secouage
Alors, si vous vous le sentez, nhsitez pas vous lancer directement. Sinon, je vais
vous proposer quelques pistes de rexion pour dmarrer sereinement le TP.
Tout dabord, au niveau du grattage. Il y a plusieurs solutions envisageables. Celle que
je vous propose est de ne pas avoir rellement un unique rectangle gratter, mais plutt
plein de petits rectangles qui recouvrent un TextBlock contenant un texte achant si
cest gagn ou perdu. Chaque TextBlock sera lcoute dun vnement de manipu-
lation, jai choisi pour ma part la gestuelle du drap & drop du toolkit. Il faut ensuite
arriver dterminer quel lment est concern lorsque nous touchons lcran. Pour cela,
jutilise une mthode du framework .NET : FindElementsInHostCoordinates - http://
msdn.microsoft.com/fr-fr/library/system.windows.media.visualtreehelper.findelementsinhostcoordinates(v=
vs.95).aspx. Par exemple, pour rcuprer le TextBlock choisi lors du premier contact,
je pourrais faire :
1 private void GestureListener_DragStarted(object sender ,
DragStartedGestureEventArgs e)
2 {
3 Point position = e.GetPosition(Application.Current.
RootVisual);
4 IEnumerable <UIElement > elements = VisualTreeHelper.
FindElementsInHostCoordinates(new Point(position.X,
position.Y), Application.Current.RootVisual);
5 TextBlock textBlockChoisi = elements.OfType <TextBlock >().
FirstOrDefault ();
469
CHAPITRE 31. TP : JEUX DE HASARD (GRATTAGE ET SECOUAGE)
6 }
La mthode GetPosition nous fournit la position du doigt par rapport la page cou-
rante, que nous pouvons obtenir grce la proprit RootVisual de lapplication - http:
//msdn.microsoft.com/fr-fr/library/system.windows.application.rootvisual(v=
vs.95).aspx. Ainsi, il sera possible de dterminer les lments qui sont slectionns et
les supprimer de devant le TextBlock.
Passons maintenant au secouage. Comment dtecter que lutilisateur secoue son tl-
phone ? Il y a plusieurs solutions. Celle que jai choisi consister dtecter un cart
signicatif entre les deux dernires acclrations du tlphone. Si cet cart se reproduit
plusieurs fois, alors je peux considrer quil sagit dun secouage. Par contre, si lcart
passe sous un certain seuil, alors je dois arrter dimaginer un potentiel secouage.
Allez, cest vous de jouer.
Correction
Alors, vous avez trouv comment ? Facile ? Dicile ? Ce nest pas toujours facile de
se confronter directement ce genre de situations, surtout lorsquon a lhabitude de
raliser des applications clientes lourdes ou web, ou mme lorsquon a pas du tout
lhabitude de raliser des applications.
Voici la correction que je propose. Tout dabord le menu, vous savez faire, il sagit de
ma page MainPage.xaml qui renvoie vers deux autres pages :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12 ,17,
0,28">
7 <TextBlock x:Name="ApplicationTitle" Text="TP Jeux de
hasard" Style="{StaticResource PhoneTextNormalStyle}
"/>
8 <TextBlock x:Name="PageTitle" Text="Menu" Margin="9,-7,
0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
9 </StackPanel >
10 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
>
11 <StackPanel >
12 <Button Content="Grattage ..." Tap="Button_Tap" />
13 <Button Content="Secouage ..." Tap="Button_Tap_1"
/>
14 </StackPanel >
15 </Grid >
16 </Grid >
Cest trs pur, le code-behind sera :
470
CORRECTION
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6 }
7
8 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
9 {
10 NavigationService.Navigate(new Uri("/Grattage.xaml",
UriKind.Relative));
11 }
12
13 private void Button_Tap_1(object sender , System.Windows.
Input.GestureEventArgs e)
14 {
15 NavigationService.Navigate(new Uri("/Secouage.xaml",
UriKind.Relative));
16 }
17 }
Une utilisation trs classique du service de navigation. Passons maintenant la page
Grattage.xaml :
1 <phone:PhoneApplicationPage
2 ...
3 xmlns:toolkit="clr -namespace:Microsoft.Phone.Controls;
assembly=Microsoft.Phone.Controls.Toolkit">
4
5 <Grid x:Name="LayoutRoot" Background="Transparent">
6 <Grid.RowDefinitions >
7 <RowDefinition Height="Auto"/>
8 <RowDefinition Height="*"/>
9 </Grid.RowDefinitions >
10 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12
,17 ,0,28">
11 <TextBlock x:Name="ApplicationTitle" Text="Grattage
" Style="{StaticResource PhoneTextNormalStyle}"
/>
12 </StackPanel >
13 <Canvas x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0
,12 ,0">
14 <TextBlock x:Name="TextBlock1" Width="100" Height="
100" Canvas.Top="10" Canvas.Left="40" Margin="20
30 0 0">
15 <toolkit:GestureService.GestureListener >
16 <toolkit:GestureListener DragStarted="
GestureListener_DragStarted" DragDelta="
GestureListener_DragDelta" DragCompleted
="GestureListener_DragCompleted" />
471
CHAPITRE 31. TP : JEUX DE HASARD (GRATTAGE ET SECOUAGE)
17 </toolkit:GestureService.GestureListener >
18 </TextBlock >
19 <TextBlock x:Name="TextBlock2" Width="100" Height="
100" Canvas.Top="10" Canvas.Left="170" Margin="
20 30 0 0">
20 <toolkit:GestureService.GestureListener >
21 <toolkit:GestureListener DragStarted="
GestureListener_DragStarted" DragDelta="
GestureListener_DragDelta" DragCompleted
="GestureListener_DragCompleted" />
22 </toolkit:GestureService.GestureListener >
23 </TextBlock >
24 <TextBlock x:Name="TextBlock3" Width="100" Height="
100" Canvas.Top="10" Canvas.Left="300" Margin="
20 30 0 0">
25 <toolkit:GestureService.GestureListener >
26 <toolkit:GestureListener DragStarted="
GestureListener_DragStarted" DragDelta="
GestureListener_DragDelta" DragCompleted
="GestureListener_DragCompleted" />
27 </toolkit:GestureService.GestureListener >
28 </TextBlock >
29 <StackPanel Canvas.Top="250" Width="480">
30 <Button Content="Rejouer" HorizontalAlignment="
Center" Tap="Button_Tap" />
31 <TextBlock x:Name="Resultat" />
32 </StackPanel >
33 </Canvas >
34 </Grid >
35 </phone:PhoneApplicationPage >
Comme je lai propos, jai simplement ajout trois TextBlock dans un Canvas. Re-
marquez que jai spci exhaustivement les largeurs et les hauteurs de chacun. Sur
chaque TextBlock, je suis galement lcoute des trois vnements de drag & drop.
Rien de bien compliqu. Cest cot code-behind que cela se complique.
1 public partial class Grattage : PhoneApplicationPage
2 {
3 private const int largeurRectangle = 15;
4 private int nbRects;
5 private TextBlock textBlockChoisi;
6 private Random random;
7 private bool aGagne;
8 private int nbParties;
9 private int nbPartiesGagnees;
10
11 public Grattage ()
12 {
13 InitializeComponent ();
14 random = new Random ();
15 }
472
CORRECTION
16
17 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
18 {
19 Init();
20
21 base.OnNavigatedTo(e);
22 }
23 }
Nous dclarons dans un premier temps plusieurs variables qui vont nous servir dans la
classe. Il y a notamment un gnrateur de nombre alatoires, initialis dans le construc-
teur. Ensuite, cela se passe dans la mthode Init(). Il faut dans un premier temps
crer plein de petits rectangles acher par-dessus chaque TextBlock :
1 private void Init()
2 {
3 textBlockChoisi = null;
4 TextBlock [] textBlocks = new[] { TextBlock1 , TextBlock2 ,
TextBlock3 };
5
6 int gagnant = random.Next(0, 3);
7 for (int cpt = 0; cpt < textBlocks.Length; cpt++)
8 {
9 TextBlock tb = textBlocks[cpt];
10 if (cpt == gagnant)
11 tb.Text = "Gagn !";
12 else
13 tb.Text = "Perdu !";
14 }
15
16 foreach (TextBlock textBlock in textBlocks)
17 {
18 double x = (double)textBlock.GetValue(Canvas.
LeftProperty);
19 double y = (double)textBlock.GetValue(Canvas.
TopProperty);
20
21 nbRects = 0;
22 for (double j = 0; j < textBlock.Height; j +=
largeurRectangle)
23 {
24 for (double i = 0; i < textBlock.Width; i +=
largeurRectangle)
25 {
26 double width = largeurRectangle;
27 double height = largeurRectangle;
28 if (i + width > textBlock.Width)
29 width = textBlock.Width - i;
30 if (j + height > textBlock.Height)
31 height = textBlock.Height - j;
473
CHAPITRE 31. TP : JEUX DE HASARD (GRATTAGE ET SECOUAGE)
32 Rectangle r = new Rectangle { Fill = new
SolidColorBrush(Colors.Gray), Width = width ,
Height = height , Tag = textBlock };
33 r.SetValue(Canvas.LeftProperty , i + x);
34 r.SetValue(Canvas.TopProperty , j + y);
35 ContentPanel.Children.Add(r);
36 nbRects ++;
37 }
38 }
39 }
40 }
Le principe est de rcuprer la position de chaque TextBlock dans le Canvas puis de g-
nrer plein de petits rectangles qui couvrent la surface du TextBlock. Chaque rectangle
est positionn dans le Canvas et ajout celui-ci. Notez que jen prote pour rattacher
chaque rectangle son TextBlock grce la proprit Tag, cela sera plus simple par
la suite pour dterminer quel rectangle on peut supprimer. Remarquons au passage
que nous utilisons le gnrateur de nombre alatoire pour dterminer quel TextBlock
est le gagnant. Viens ensuite le grattage en lui-mme. Cest lors du dmarrage de la
gestuelle drag & drop que nous allons pouvoir dterminer le TextBlock choisi. Comme
je lavais indiqu, jutilise la mthode FindElementsInHostCoordinates partir des
coordonnes du doigt. Puis, je peux utiliser le mme principe lors de lexcution de la
gestuelle, rcuprer le Rectangle cette position et lenlever du Canvas.
1 public partial class Grattage : PhoneApplicationPage
2 {
3 [...]
4 private void GestureListener_DragStarted(object sender ,
DragStartedGestureEventArgs e)
5 {
6 if (textBlockChoisi == null)
7 {
8 aGagne = false;
9 Point position = e.GetPosition(Application.Current.
RootVisual);
10 IEnumerable <UIElement > elements = VisualTreeHelper.
FindElementsInHostCoordinates(new Point(position
.X, position.Y), Application.Current.RootVisual)
;
11 textBlockChoisi = elements.OfType <TextBlock >().
FirstOrDefault ();
12 }
13 }
14
15 private void GestureListener_DragDelta(object sender ,
DragDeltaGestureEventArgs e)
16 {
17 if (textBlockChoisi != null)
18 {
19 Point position = e.GetPosition(Application.Current.
474
CORRECTION
RootVisual);
20
21 IEnumerable <UIElement > elements = VisualTreeHelper.
FindElementsInHostCoordinates(new Point(position
.X, position.Y), Application.Current.RootVisual)
;
22 foreach (Rectangle element in elements.OfType <
Rectangle >().Where(r => r.Tag == textBlockChoisi
))
23 {
24 ContentPanel.Children.Remove(element);
25 }
26 }
27 }
28
29 private void GestureListener_DragCompleted(object sender ,
DragCompletedGestureEventArgs e)
30 {
31 if (textBlockChoisi != null)
32 {
33 double taux = nbRects / 3.0;
34 double nbRectangles = ContentPanel.Children.OfType <
Rectangle >().Count(r => r.Tag == textBlockChoisi
);
35 if (nbRectangles <= taux)
36 {
37 if (textBlockChoisi.Text == "Perdu !")
38 MessageBox.Show("Vous avez perdu");
39 else
40 {
41 aGagne = true;
42 MessageBox.Show("Flicitations");
43 }
44 }
45 }
46 }
47 }
Enn, quand la gestuelle est termine, je peux dterminer combien il reste de rectangles
qui recouvrent le TextBlock choisi, et au-dessous dun certain taux, je peux acher si
cest gagn ou pas. Reste plus qu rinitialiser tout pour orir la possibilit de rejouer :
1 public partial class Grattage : PhoneApplicationPage
2 {
3 [...]
4 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
5 {
6 if (aGagne)
7 nbPartiesGagnees ++;
8 nbParties ++;
475
CHAPITRE 31. TP : JEUX DE HASARD (GRATTAGE ET SECOUAGE)
9 Resultat.Text = nbPartiesGagnees + " parties gagnes
sur " + nbParties;
10 Init();
11 }
12 }
Et voil, le grattage est termin. Passons maintenant la partie secouage. Cot XAML
cest plutt simple :
1 <Grid x:Name="LayoutRoot" Background="Transparent">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="Auto"/>
4 <RowDefinition Height="*"/>
5 </Grid.RowDefinitions >
6
7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12 ,17,
0,28">
8 <TextBlock x:Name="ApplicationTitle" Text="Secouage"
Style="{StaticResource PhoneTextNormalStyle}"/>
9 </StackPanel >
10
11 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12 ,0"
>
12 <Grid.RowDefinitions >
13 <RowDefinition Height="100" />
14 <RowDefinition Height="100" />
15 <RowDefinition Height="100" />
16 <RowDefinition Height="*" />
17 </Grid.RowDefinitions >
18 <TextBlock Text="Secouez le tlphone ..." />
19 <ProgressBar x:Name="Barre" Grid.Row="1" Visibility="
Collapsed" />
20 <TextBlock x:Name="Resultat" Grid.Row="2"
HorizontalAlignment="Center" />
21 <TextBlock x:Name="Total" Grid.Row="3" />
22 </Grid >
23 </Grid >
Tout se passe dans le code-behind, la premire chose est dinitialiser lacclromtre
et le gnrateur de nombres alatoires. Jutilise galement un DispatcherTimer pour
faire mariner un peu lutilisateur avant de lui fournir le rsultat :
1 public partial class Secouage : PhoneApplicationPage
2 {
3 private Accelerometer accelerometre;
4 private const double ShakeThreshold = 0.7;
5 private DispatcherTimer timer;
6 private Random random;
7 private int nbParties;
8 private int nbPartiesGagnees;
9 private Vector3 derniereAcceleration;
476
CORRECTION
10 private int cpt;
11
12 public Secouage ()
13 {
14 InitializeComponent ();
15 accelerometre = new Accelerometer ();
16 accelerometre.CurrentValueChanged +=
accelerometre_CurrentValueChanged;
17 timer = new DispatcherTimer { Interval = TimeSpan.
FromSeconds(2) };
18 random = new Random ();
19 }
20
21 protected override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
22 {
23 accelerometre.Start ();
24 timer.Tick += timer_Tick;
25 base.OnNavigatedTo(e);
26 }
27
28 protected override void OnNavigatedFrom(System.Windows.
Navigation.NavigationEventArgs e)
29 {
30 accelerometre.Stop();
31 timer.Tick -= timer_Tick;
32 base.OnNavigatedFrom(e);
33 }
34 }
Attention, noubliez pas darrter lacclromtre lorsque nous nen avons plus
besoin an dconomiser la batterie.
Il ne reste plus qu grer la dtection du secouage. Comme je vous lai indiqu, il sut
de comparer la dirence dacclration suivant un axe entre deux mesures. Si celle-ci
dpasse un certain seuil, alors il y a un premier secouage, si par contre elle repasse
sous un autre seuil, la dtection est interrompue. Jai x arbitrairement ces valeurs
0.8 et 0.1 car je trouve quelles simulent des valeurs acceptables. Pour mesurer la
dirence dacclration, je prends la valeur absolue de la dirence entre la dernire
valeur dacclration sur un axe et la prcdente. Si un changement brutal est dtect,
alors on incrmente le compteur. Sil dpasse 4 alors nous considrons quil sagit dun
vrai secouage de tlphone.
1 public partial class Secouage : PhoneApplicationPage
2 {
3 [...]
4 private void accelerometre_CurrentValueChanged(object
sender , SensorReadingEventArgs <AccelerometerReading > e)
477
CHAPITRE 31. TP : JEUX DE HASARD (GRATTAGE ET SECOUAGE)
5 {
6 Dispatcher.BeginInvoke (() =>
7 {
8 Vector3 accelerationEnCours = e.SensorReading.
Acceleration;
9
10 if (derniereAcceleration == null)
11 {
12 derniereAcceleration = accelerationEnCours;
13 return;
14 }
15 double seuilMax = 0.8;
16 double seuilMin = 0.1;
17 int maxSecouage = 3;
18 if (cpt <= maxSecouage && (
19 Math.Abs(accelerationEnCours.X -
derniereAcceleration.X) >= seuilMax ||
20 Math.Abs(accelerationEnCours.Y -
derniereAcceleration.Y) >= seuilMax ||
21 Math.Abs(accelerationEnCours.Z -
derniereAcceleration.Z) >= seuilMax))
22 {
23 Resultat.Text = string.Empty;
24 cpt ++;
25 if (cpt > maxSecouage)
26 {
27 cpt = 0;
28 Barre.Visibility = Visibility.Visible;
29 Barre.IsIndeterminate = true;
30 timer.Start();
31 }
32 }
33 else
34 {
35 if (Math.Abs(accelerationEnCours.X -
derniereAcceleration.X) >= seuilMin ||
36 Math.Abs(accelerationEnCours.Y -
derniereAcceleration.Y) >= seuilMin ||
37 Math.Abs(accelerationEnCours.Z -
derniereAcceleration.Z) >= seuilMin)
38 {
39 cpt = 0;
40 }
41 }
42 derniereAcceleration = accelerationEnCours;
43 });
44 }
45 }
ce moment-l, je dmarre le timer ainsi que lanimation de la barre de progression.
478
ALLER PLUS LOIN
Il ne reste plus qu grer la suite du jeu :
1 public partial class Secouage : PhoneApplicationPage
2 {
3 [...]
4 private void timer_Tick(object sender , EventArgs e)
5 {
6 timer.Stop();
7 Barre.Visibility = Visibility.Collapsed;
8 Barre.IsIndeterminate = false;
9 int nombre = random.Next(0, 3);
10 if (nombre == 1)
11 {
12 // nombre gagnant
13 Resultat.Text = "Gagn !";
14 nbPartiesGagnees ++;
15 }
16 else
17 {
18 Resultat.Text = "Perdu !";
19 }
20 nbParties ++;
21 Total.Text = nbPartiesGagnees + " parties gagnes sur "
+ nbParties;
22 }
23 }
Et voil. Un petit jeu qui nous a permis de plonger doucement dans la gestuelle et dans
lutilisation de lacclromtre !
Aller plus loin
Ici, je suis rest trs sobre sur linterface (qui a dit trs moche ?). Mais il serait tout
fait pertinent damliorer cet aspect-l de lapplication. Pourquoi ne pas utiliser des
images de ds et des transformations pour raliser un lancer de ds majestueux ?
De mme, plutt que dutiliser des rectangles lors du grattage, on pourrait utiliser des
images ainsi que la classe WriteableBitmap - http://msdn.microsoft.com/fr-fr/
library/system.windows.media.imaging.writeablebitmap(v=vs.95).aspx pour ef-
facer des lments de limage. . . Je nen parle pas ici car cela sort de la porte de ce
cours, mais cest une ide creuser. En ce qui concerne le secouage, jai propos un
algorithme ultra simpliste permettant de dtecter ce genre de mouvement. Il existe une
bibliothque dveloppe par des personnes Microsoft qui permet de dtecter les se-
couages. Il sagit de la Shake Gesture Library, que vous pouvez tlcharger ici - http://
www.codeproject.com/Articles/176021/Shake-Gestures-Library-A-Windows-Phone-Recipe.
Nous aurons tout fait intrt lutiliser ici. Lalgorithme de dtection est plus per-
tinent et pourquoi rinventer la roue alors que dautres personnes lont dj fait pour
nous.
479
CHAPITRE 31. TP : JEUX DE HASARD (GRATTAGE ET SECOUAGE)
480
Chapitre 32
La golocalisation
Dicult :
De plus en plus de matriels technologiques sont quips de systmes de localisation,
notamment grce aux GPS. Cest galement le cas des tlphones quips de Windows
Phone dont les spcications imposent la prsence dun GPS. Mais le systme de localisation
est un peu plus pouss que le simple GPS, qui a ses limites. En eet, on se trouve souvent
lintrieur dun immeuble ou entours par des gros murs qui peuvent bloquer le signal
du GPS. . . heureusement, la triangulation base des rseaux WIFI peut prendre la relve
pour indiquer la position dun tlphone. Nous allons pouvoir exploiter la position de notre
utilisateur et raliser ainsi des applications golocalises, nous allons voir dans ce chapitre
comment faire.
481
CHAPITRE 32. LA GOLOCALISATION
Avec Windows Phone 7, on utilisait une premire version du service de localisation grce
au GeoCoordinateWatcher - http://msdn.microsoft.com/fr-fr/library/system.
device.location.geocoordinatewatcher.aspx. Windows 8 a propos une refonte du
service de localisation et cest tout naturellement que Windows Phone 8 en a prot.
Les deux fonctionnent globalement de la mme faon, mais celui de Windows Phone
8 supporte par dfaut lasynchronisme avanc avec await et async. Cest celui-ci que
nous allons tudier. Sachez quand mme que si vous projetez de faire en sorte que votre
application fonctionne avec Windows Phone 7.X et 8, vous aurez intrt utiliser la
premire version du service de localisation.
Remarquez que vous devrez indiquer dans votre application un descriptif de votre
politique dutilisation des donnes golocalises, soit directement dans une page, soit
en donnant un lien vers cette politique. De mme, votre application devra fournir un
moyen de dsactiver explicitement lutilisation du service de localisation.
Dterminer sa position
Il est trs facile de rcuprer sa position, on parle de golocalisation. Pour ce faire, on
pourra utiliser la classe Geolocator - http://msdn.microsoft.com/en-us/library/
windows/apps/windows.devices.geolocation.geolocator qui est le point daccs
au service de localisation. Nous aurons besoin dans un premier temps dindiquer que
notre application utilise le service de localisation en rajoutant la capacit ID_CAP_LOCATION.
Il sut de la slectionner en double-cliquant sur le chier WMAppManifest.xml, comme
indiqu sur la gure 32.1.
Figure 32.1 Activer la capacit de golocalisation
482
DTERMINER SA POSITION
Ensuite, il faut avoir une instance de la classe Geolocator et potentiellement indiquer
des paramtres comme la prcision. Utilisons dans un premier temps ce XAML :
1 <StackPanel >
2 <Button Click="Button_Click_1" Content="Obtenir la
position du tlphone"/>
3 <TextBlock x:Name="Latitude"/>
4 <TextBlock x:Name="Longitude"/>
5 </StackPanel >
Et dans le code-behind, nous pouvons obtenir notre position avec :
1 private async void Button_Click_1(object sender ,
RoutedEventArgs e)
2 {
3 Geolocator geolocator = new Geolocator ();
4 geolocator.DesiredAccuracyInMeters = 50;
5
6 try
7 {
8 Geoposition geoposition = await geolocator.
GetGeopositionAsync(TimeSpan.FromMinutes(5),
TimeSpan.FromSeconds(10));
9
10 Dispatcher.BeginInvoke (() =>
11 {
12 Latitude.Text = geoposition.Coordinate.Latitude.
ToString ();
13 Longitude.Text = geoposition.Coordinate.Longitude.
ToString ();
14 });
15 }
16 catch (UnauthorizedAccessException)
17 {
18 MessageBox.Show("Le service de location est dsactiv
dans les paramtres du tlphone");
19 }
20 catch (Exception ex)
21 {
22 }
23 }
Grce la mthode GetGeopositionAsync nous obtenons la position du tlphone, et
ce, de manire asynchrone (notez lemploi des mots-cls await et async), ce qui vite
de bloquer linterface utilisateur. Nous pouvons ensuite exploiter lobjet Geoposition
obtenu en retour et notamment ses proprits Latitude et Longitude. Dans cet objet,
nous obtenons galement dautres informations, comme laltitude (en mtres au-dessus
du niveau de la mer), lorientation (en degrs par rapport au nord), la vitesse (en mtres
par secondes) ; cette dernire donne ayant peu de sens lorsque la golocalisation est
demande une unique fois.
483
CHAPITRE 32. LA GOLOCALISATION
Sauf quune position, a change au fur et mesure ! Eh oui, en voiture, dans le train, etc.
On peut avoir besoin dtre noti dun changement de position; ce qui peut tre trs
pratique dans une application de navigation ou pour enregistrer un parcours de course
pied. Dans ce cas, il faut sabonner lvnement PositionChanged qui nous fournira
une nouvelle position chaque fois. Nous aurons galement besoin de nous abonner
lvnement StatusChanged qui nous permettra de connatre les changements de statut
du matriel :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private Geolocator geolocator;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8 }
9
10 protected override void OnNavigatedTo(NavigationEventArgs e
)
11 {
12 geolocator = new Geolocator { DesiredAccuracy =
PositionAccuracy.High , MovementThreshold = 20 };
13 geolocator.StatusChanged += geolocator_StatusChanged;
14 geolocator.PositionChanged +=
geolocator_PositionChanged;
15
16 base.OnNavigatedTo(e);
17 }
18
19 protected override void OnNavigatedFrom(NavigationEventArgs
e)
20 {
21 geolocator.PositionChanged -=
geolocator_PositionChanged;
22 geolocator.StatusChanged -= geolocator_StatusChanged;
23 geolocator = null;
24
25 base.OnNavigatedFrom(e);
26 }
27
28 private void geolocator_StatusChanged(Geolocator sender ,
StatusChangedEventArgs args)
29 {
30 string status = "";
31
32 switch (args.Status)
33 {
34 case PositionStatus.Disabled:
35 status = "Le service de localisation est d
sactiv dans les paramtres";
484
DTERMINER SA POSITION
36 break;
37 case PositionStatus.Initializing:
38 status = "En cours d'initialisation";
39 break;
40 case PositionStatus.Ready:
41 status = "Service de localisation prt";
42 break;
43 case PositionStatus.NotAvailable:
44 case PositionStatus.NotInitialized:
45 case PositionStatus.NoData:
46 break;
47 }
48
49 Dispatcher.BeginInvoke (() =>
50 {
51 Statut.Text = status;
52 });
53 }
54
55 private void geolocator_PositionChanged(Geolocator sender ,
PositionChangedEventArgs args)
56 {
57 Dispatcher.BeginInvoke (() =>
58 {
59 Latitude.Text = args.Position.Coordinate.Latitude.
ToString ();
60 Longitude.Text = args.Position.Coordinate.Longitude
.ToString ();
61 });
62 }
63 }
Il faut toujours vrier la bonne disponibilit du GPS, car il peut arriver que lutilisa-
teur veuille explicitement le dsactiver. Cest le cas par exemple lorsque le statut est
gal Disabled. Pour acher le statut, jai lgrement modi mon XAML :
1 <TextBlock x:Name="Statut"/>
2 <TextBlock x:Name="Latitude"/>
3 <TextBlock x:Name="Longitude"/>
Remarque : il ny a pas de mthode pour dmarrer le service de localisation comme il
pouvait y avoir la mthode Start() avec le service de localisation de Windows Phone
7. Le dmarrage seectue lorsquon sabonne lvnement PositionChanged. Ce qui
implique que lorsquon nen aura plus besoin, il sera possible darrter lutilisation
du service de localisation en se dsabonnant de ce mme vnement. Cela permet
dconomiser la batterie. Cest ce que jai fait dans mon exemple en dmarrant le
service de navigation lorsque jarrive sur la page et en le dsactivant lorsque je quitte
la page.
Et voil, dans la mthode geolocator_PositionChanged, nous recevons un objet nous
fournissant les coordonnes de la position du tlphone, comme vu plus haut, et nous
485
CHAPITRE 32. LA GOLOCALISATION
avons des relevs successifs de la position du tlphone.
Remarquons quil est possible de dnir leort que doit faire le service de localisation
pour dterminer notre position. Il sut de crer le Geolocator en aectant sa proprit
DesiredAccuracy. Il existe deux modes : prcision forte ou prcision par dfaut. Vous
aurez compris que la prcision forte sobtient avec :
1 DesiredAccuracy = PositionAccuracy.High
Et que la prcision par dfaut sobtient avec
1 DesiredAccuracy = PositionAccuracy.Default
En mode par dfaut, le tlphone utilise essentiellement les bornes wi et les antennes
radios pour faire une triangularisation, ce qui est relativement peu consommateur de
batterie. En mode de prcision forte, le tlphone va utiliser lensemble des moyens
dont il dispose pour nous golocaliser en ngligeant la consommation de batterie. Il
utilisera notamment la puce GPS pour un reprage par satellite.
noter que lon peut indiquer partir de quelle distance (en mtres par rapport la
dernire position trouve) le service de localisation envoie un vnement pour nous in-
diquer un changement de position. Cela se fait via la proprit MovementThreshold qui
est 0 mtre par dfaut, ce qui implique quun vnement de changement de position
est envoy chaque changement de position. Nous avons galement notre disposition
la proprit DesiredAccuracyInMeters qui permet dindiquer le niveau de prcision
souhait (en mtres) pour les donnes renvoyes depuis le service de localisation.
Utiliser la golocalisation dans lmulateur
Oui mais un GPS, cest trs bien sur un tlphone. . . mais sur un mulateur ?
Comment on fait ? Il peut quand mme nous fournir une position ?
Pour le vrier, dmarrons lmulateur et rcuprons la position comme nous lavons
vu. Nous obtenons une latitude de 47,669444 et une longitude de -122,123889, qui
correspond la position. . . des btiments de Microsoft. Hasard?
En fait, ceci se passe dans les outils supplmentaires de lmulateur, le dernier bouton
en bas de la barre situe droite de lmulateur. Il est possible de changer les valeurs
et mme de dnir des itinraires pour simuler des dplacements, cela se passe dans
longlet Localisation, comme indiqu la gure 32.2.
En quelques clics, je dnis ma position et mon tour de France. Il sera alors trs facile
de faire changer lmulateur de position pendant son excution, soit manuellement, soit
en jouant un itinraire pralablement enregistr. . . Pratique pour simuler des positions
ou des changements de position tout en restant confortablement install sur son PC
avec son dbogueur.
486
UTILISER LA GOLOCALISATION DANS LMULATEUR
Figure 32.2 Simuler la golocalisation dans les outils de lmulateur
487
CHAPITRE 32. LA GOLOCALISATION
Utiliser la golocalisation avec le contrle Map
La golocalisation prend tout son intrt utilise concomitamment avec le contrle Map
vu dans la partie prcdente. tant donn que le service de localisation fourni un objet
avec une latitude et une longitude (de type Geocoordinate - http://msdn.microsoft.
com/fr-fr/library/windows/apps/windows.devices.geolocation.geocoordinate),
il est trs facile dutiliser les coordonnes GPS de notre utilisateur sur la carte, par
exemple ici je centre la carte sur la position de lutilisateur :
1 private void geolocator_PositionChanged(Geolocator sender ,
PositionChangedEventArgs args)
2 {
3 Dispatcher.BeginInvoke (() =>
4 {
5 Latitude.Text = args.Position.Coordinate.Latitude.
ToString ();
6 Longitude.Text = args.Position.Coordinate.Longitude.
ToString ();
7
8 Carte.Center = new GeoCoordinate(args.Position.
Coordinate.Latitude , args.Position.Coordinate.
Longitude);
9 });
10 }
Attention, il y a une dirence entre la classe Geocoordinate, issue du
service de localisation, et la classe GeoCoordinate que nous utilisons avec
le contrle de carte. Notez la subtile dirence de casse et les espaces de
noms dirents, savoir respectivement Windows.Devices.Geolocation
et System.Device.Location.
Remarquons quil faut utiliser le dispatcher pour revenir sur le thread dinterface an
de mettre jour cette dernire.
En rsum
Le service de localisation est accessible partir du moment o il a t dclar
et accept par lutilisateur.
La classe Geolocator permet dobtenir les informations issues du service de
localisation.
On peut utiliser le contrle de carte pour acher sa position, en utilisant la
classe GeoCoordinate.
488
Chapitre 33
Les Tasks du tlphone
Dicult :
Utiliser les capteurs du tlphone nest pas le seul moyen daccder aux fonctionnalits
internes du tlphone. Les Task, que lon peut traduire en tches, sont une solution per-
mettant daccder dautres applications du tlphone. Il sagit par exemple de la pos-
sibilit de slectionner un contact dans le rpertoire de lutilisateur, denvoyer un SMS,
de prendre une photo, etc. Nous allons dcouvrir dans ce chapitre quil y a deux sortes
de tches, les choosers et les launchers, elles sont situes dans lespace de nom : using
Microsoft.Phone.Tasks;
489
CHAPITRE 33. LES TASKS DU TLPHONE
Les choosers
Les choosers, comme le nom le suggre aux anglophones, permettent de choisir une
information. Plus prcisment, il sagira de dmarrer une fonctionnalit qui va nous
renvoyer quelque chose dexploitable, par exemple un contact dans le rpertoire. Voici
une liste des choosers des Windows Phone 8 :
Chooser Description
AddressChooserTask Dmarre lapplication Contacts pour
choisir une adresse physique
AddWalletItemTask Dmarrer lapplication Wallet
(portefeuille) an de permettre dy
ajouter un produit
CameraCaptureTask Dmarre lappareil photo pour pouvoir
prendre une photo
EmailAddressChooserTask Dmarre lapplication Contacts pour
choisir une adresse email
GameInviteTask Permet dinviter des autres joueurs
participer un jeu en ligne
PhoneNumberChooserTask Dmarre lapplication Contacts pour
choisir un numro de tlphone
PhotoChooserTask Permet de slectionner une photo du
tlphone
SaveContactTask Dmarre lapplication Contacts pour
enregistrer un contact
SaveEmailAddressTask Dmarre lapplication Contacts pour
enregistrer un email
SavePhoneNumberTask Dmarre lapplication Contacts pour
enregistrer un numro de tlphone
SaveRingtoneTask Dmarre lapplication Sonneries
Je ne vais pas tous vous les prsenter en dtail, car ce serait un peu fastidieux, dautant
plus que la description est globalement assez explicite. Sachez cependant que lmu-
lateur ne permet pas de simuler toutes les tches et que vous aurez parfois besoin
dun tlphone pour vous rendre vraiment compte du rsultat. Limportant est que les
choosers renvoient un lment exploiter. Donc globalement, il faudra instancier la
tche, sabonner lvnement de n de tche et exploiter le rsultat. Par exemple,
pour slectionner une photo disponible dans le tlphone, nous pourrons utiliser le code
suivant :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private PhotoChooserTask photoChooserTask;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
490
LES CHOOSERS
8 photoChooserTask = new PhotoChooserTask ();
9 photoChooserTask.Completed +=
photoChooserTask_Completed;
10 }
11
12 private void photoChooserTask_Completed(object sender ,
PhotoResult e)
13 {
14 if (e.TaskResult == TaskResult.OK)
15 {
16 BitmapImage image = new BitmapImage ();
17 image.SetSource(e.ChosenPhoto);
18 Photo.Source = image;
19 }
20 }
21
22 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
23 {
24 photoChooserTask.Show();
25 }
26 }
Comme vous pouvez le constater, la photo slectionne est dans le paramtre de lv-
nement. Celui-ci possde galement un rsultat de tche, par exemple, nous naurons
une valeur dans la proprit ChosenPhoto que si lutilisateur est all au bout de la
tche, et qugalement le rsultat soit OK. Cot XAML, nous pourrons avoir :
1 <StackPanel >
2 <Button Content="Choisir la photo" Tap="Button_Tap" />
3 <Image x:Name="Photo" />
4 </StackPanel >
Dans lmulateur, nous avons quelques valeurs bouchonnes pour cette tche, voyez
plutt sur la gure 33.1.
Illustrons encore les choosers avec la tche CameraCaptureTask qui permet de prendre
une photo depuis votre application :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private CameraCaptureTask cameraCaptureTask;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8 cameraCaptureTask = new CameraCaptureTask ();
9 cameraCaptureTask.Completed +=
cameraCaptureTask_Completed;
10 }
11
491
CHAPITRE 33. LES TASKS DU TLPHONE
Figure 33.1 Choix dune image depuis lmulateur
12 private void cameraCaptureTask_Completed(object sender ,
PhotoResult e)
13 {
14 if (e.TaskResult == TaskResult.OK)
15 {
16 BitmapImage image = new BitmapImage ();
17 image.SetSource(e.ChosenPhoto);
18 Photo.Source = image;
19 }
20 }
21
22 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
23 {
24 cameraCaptureTask.Show();
25 }
26 }
Ici aussi, lmulateur fonctionne en mode bouchon et nous propose une image factice
pour simuler la prise dune photo, comme on peut le voir sur la gure 33.2.
Vous pourrez prendre la photo depuis lmulateur en cliquant avec le bouton droit.
492
LES LAUNCHERS
Figure 33.2 Simulation de prise de photo
Attention, vous ne pourrez pas utiliser la tche CameraCaptureTask sur votre
tlphone lorsque celui-ci est branch votre PC.
Les launchers
Les launchers permettent de dmarrer une application sur le tlphone, par exemple
envoyer un mail ou un SMS. Ils fonctionnent comme les choosers mais nattendent pas
dinformations en retour.
Ici aussi, les descriptions parlent delles-mmes. Dans notre application de lecteur de
ux RSS, il aurait par exemple t possible dutiliser le WebBrowserTask au lieu dem-
barquer le contrle WebBrowser dans nos pages. Il sutilise ainsi :
1 WebBrowserTask webBrowserTask = new WebBrowserTask { Uri = new
Uri("http ://fr.openclassrooms.com/informatique/cours/
apprenez -a-developper -en-c", UriKind.Absolute) };
2 webBrowserTask.Show();
qui dmarre donc Internet Explorer avec la page demande (voir la gure 33.3).
493
CHAPITRE 33. LES TASKS DU TLPHONE
Launcher Description
BingMapsDirectionsTask Permet de dmarrer lapplication carte
de Windows Phone 7 pour acher un
itinraire
BingMapsTask Permet de dmarrer la carte de
Windows Phone 7, centre sur une
position
ConnectionSettingsTask Permet dacher la page de
conguration du rseau
EmailComposeTask Permet de composer un nouvel email
via lapplication de messagerie
MapDownloaderTask Permet de tlcharger les cartes pour
une utilisation hors ligne
MapsDirectionsTask Permet de dmarrer lapplication de
carte pour acher un itinraire entre
deux points
MapsTask Permet de dmarrer lapplication de
carte centre sur un emplacement
MapUpdaterTask Permet de tlcharger les mises jour
de cartes
MarketplaceDetailTask Permet dacher le dtail dune
application dans le Marketplace
MarketplaceHubTask Dmarre lapplication Marketplace
MarketplaceReviewTask Permet datteindre la che des avis
dune application
MarketplaceSearchTask Ache les rsultats dune recherche
Marketplace
MediaPlayerLauncher Dmarre le lecteur de mdia
PhoneCallTask Permet de passer des appels
SaveAppointmentTask Permet denregistrer un rendez-vous
SearchTask Dmarre une recherche sur le web
ShareLinkTask Partage un lien sur un rseau social
ShareMediaTask Permet de partager une photo ou
vido avec les applications qui se sont
enregistres pour les exploiter
ShareStatusTask Partage un message de statut sur un
rseau social
SmsComposeTask Permet de composer un SMS
WebBrowserTask Dmarre le navigateur web
494
LES LAUNCHERS
Figure 33.3 Le launcher WebBrowserTask ache une page web
Il est possible dutiliser le WebBrowserTask pour demander Internet Explo-
rer de nous acher un document Word par exemple.
Tous les launchers fonctionnent de la mme faon, par exemple pour pr-remplir un
SMS avant envoi :
1 SmsComposeTask smsComposeTask = new SmsComposeTask { To = "+
33123456789", Body = "Bon anniversaire !" };
2 smsComposeTask.Show();
la gure 33.4, vous pouvez observer le rendu dans lmulateur.
Voyons enn un autre launcher bien pratique qui nous permet dacher un itinraire
sans passer par les API de la carte que nous avons prcdemment vues :
1 MapsDirectionsTask mapsDirectionsTask = new MapsDirectionsTask
();
2 LabeledMapLocation emplacement = new LabeledMapLocation("Tour
Eiffel", null);
3 mapsDirectionsTask.End = emplacement;
4 mapsDirectionsTask.Show();
Regardez la gure 33.5 pour le rendu.
noter que dans ce cas, il prend la position de lutilisateur comme point de dpart pour
495
CHAPITRE 33. LES TASKS DU TLPHONE
Figure 33.4 Composition dun SMS pr-rempli
Figure 33.5 Calcul ditinraire grce au launcher
496
ETAT DE LAPPLICATION
calculer litinraire. Vous pouvez aecter la proprit mapsDirectionsTask.Start an
de prciser un point de dpart dirent de la position courante de lutilisateur. Vous
pouvez galement spcier des coordonnes GPS comme point darrive, et dans ce
cas-l, la chane passe est utilise comme tiquette :
1 GeoCoordinate tourEiffel = new GeoCoordinate { Latitude = 48.
858115 , Longitude = 2.294710 };
2 LabeledMapLocation emplacement = new LabeledMapLocation("Tour
Eiffel", tourEiffel);
Il est de bon ton dencadrer la mthode Show() dun launcher ou dun chooser
par un try/catch, surtout si lappel la mthode Show() est fait dans
un bouton. Si vous dmarrez deux tches en mme temps, par exemple en
appuyant deux fois rapidement sur le bouton, vous aurez une exception qui
fera planter lapplication.
Etat de lapplication
Comme nous lavons dj appris, lorsquest dmarre une nouvelle application, lappli-
cation en cours passe en mode suspendu et peut potentiellement tre termine. Cela
veut dire que lorsque nous dmarrons un chooser ou un launcher, il est possible que
votre application soit arrte. Il faut donc que vous veilliez enregistrer ltat de votre
application au cas o celle-ci serait arrte. Mais en plus, dans le cas du chooser, il
pourrait arriver que votre application soit termine avant davoir rcupr la rponse
du chooser, ce qui pose un problme. Pour viter cela, en instanciant un chooser, Win-
dows Phone est capable de vrier la prsence dune information dans celui-ci. Cela
implique que lvnement de n de choix soit dni sur une variable dinstance de la
classe et non dans une mthode, comme ce que jai montr dans les exemples de choo-
ser. On ne doit pas dclarer un chooser par exemple dans le constructeur de notre page.
Linstanciation correcte du chooser doit donc tre :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 private EmailAddressChooserTask emailAddressChooserTask;
4
5 public MainPage ()
6 {
7 InitializeComponent ();
8 emailAddressChooserTask = new EmailAddressChooserTask ()
;
9 emailAddressChooserTask.Completed +=
emailAddressChooserTask_Completed;
10 }
11
12 private void emailAddressChooserTask_Completed(object
sender , EmailResult e)
497
CHAPITRE 33. LES TASKS DU TLPHONE
13 {
14 if (e.TaskResult == TaskResult.OK)
15 MessageBox.Show("Adresse choisie : " + e.Email);
16 }
17
18 private void Button_Tap(object sender , System.Windows.Input
.GestureEventArgs e)
19 {
20 emailAddressChooserTask.Show();
21 }
22 }
an davoir une chance de rcuprer la slection.
En rsum
Les launchers et les choosers orent une solution pour interagir avec dautres
applications du tlphone trs facilement.
Ils permettent davoir une exprience utilisateur propre et cohrente pour utiliser
les applications internes du tlphone.
Un chooser doit tre dclar dans la porte dune page.
498
Chapitre 34
Les tuiles
Dicult :
Les tuiles, ce sont les icnes reprsentant nos applications prsentes sur la page daccueil
dun Windows Phone. Elles sont un raccourci pour dmarrer les applications prsentes dans
notre tlphone, un peu comme les icnes prsentes sur le bureau de nos vieux Windows.
Pour linstant, rien dextraordinaire vous me direz !
Mais elles sont un peu plus quune simple icne permettant de dmarrer une application.
Elles peuvent avoir une icne mais galement du texte fournissant des informations sur
lapplication ou son contexte. Elles peuvent galement tre animes et sont une des grandes
forces de Windows Phone. Dailleurs, Windows 8 sest empress de se les rcuprer.
Prsentes en une seule taille avec Windows Phone 7.5, elles se dclinent en trois tailles
partir de Windows Phone 7.8, pour le plus grand plaisir des utilisateurs qui les ont adoptes
avec intrt.
Dcouvrons prsent ces fameuses tuiles.
499
CHAPITRE 34. LES TUILES
Que sont les tuiles ?
Les tuiles, ce sont les icnes reprsentant nos applications prsentes sur la page daccueil
dun Windows Phone (ou sur la page daccueil de lmulateur, comme la gure 34.1) :
Figure 34.1 Les tuiles de la page daccueil dans lmulateur
Lorsque lon clique dessus, notre application est lance. Lorsque lon tlcharge (ou
dveloppe) une application, la tuile nest pas tout de suite prsente sur laccueil. Cest
lutilisateur de choisir explicitement de ly mettre en lpinglant sur la page daccueil.
Cela se fait en allant dans la liste des applications et en appuyant longtemps sur lappli-
cation. Cela fait apparatre un menu contextuel qui propose de supprimer lapplication,
de lpingler sur la page daccueil ou daller la noter sur le Windows Phone Store. Il
est galement possible dpingler une application depuis lmulateur suivant le mme
principe, en cliquant longtemps sur lapplication. Par exemple dans la gure 34.2, pour
pingler lapplication DemoChooser, je clique dessus et un menu droulant apparat.
Note : Pour accder la liste des applications de lmulateur, le plus simple
est de cliquer sur le bouton de menu et de faire bouger lcran sur la droite.
Dans lmulateur, on ne peut bien sr pas noter les applications et dautant plus celles
que nous sommes en train de dvelopper !
Une fois lapplication pingle, nous pouvons aller sur lcran daccueil et nous aurons
une magnique tuile (voir gure 34.3).
500
QUE SONT LES TUILES ?
Figure 34.2 pingler une application
Figure 34.3 Notre application est pingle et nous voyons sa tuile sur la page dac-
cueil
501
CHAPITRE 34. LES TUILES
Des tuiles pour tous les gots
Les tuiles existent en direntes tailles. Il y a les petites, les moyennes et les larges.
Si les applications lont prvu, il est possible de redimensionner ces tuiles sur notre
cran daccueil. Voici par exemple dans la gure 34.4 la tuile permettant daccder aux
images en taille large.
Figure 34.4 Une tuile en taille large
Pour redimensionner la tuile, il faut faire un toucher long sur celle-ci. Deux icnes
apparaissent alors droite de la tuile, comme le montre la gure 34.5.
La premire icne, en haut droite de la tuile, permet de dspingler la tuile. Mais ici,
cest la seconde, en bas droite de la tuile, qui nous intresse et qui permet de passer
dans la taille infrieure, ici la taille moyenne, puis la petite taille dans la gure 34.6.
On peut constater que chaque taille ore une exprience dirente fournissant plus
ou moins dinformations, voire une information dirente en fonction des souhaits de
lutilisateur. Si vous essayez de redimensionner dautres tuiles, vous verrez quelles ne
supportent pas toutes les trois tailles, cest une question de choix du crateur de lap-
plication. De mme, les tuiles peuvent tre de plusieurs styles dirents. Nous venons
de voir la tuile de lapplication images qui, dans son format large et moyen, ache des
images qui dlent sur la tuile. On appelle ce format le cycle tile template , que
lon peut traduire en modle de tuile cyclique. Elle permet de faire dler entre 1 et 9
images. Il existe trois modles en tout que nous allons dcouvrir dans ce chapitre :
Le modle de tuile cyclique (cycle tile template)
502
DES TUILES POUR TOUS LES GOTS
Figure 34.5 Redimensionnement des tuiles
Figure 34.6 Tuiles en tailles moyenne et petite
503
CHAPITRE 34. LES TUILES
Le modle de tuile qui se retourne (ip tile template)
Le modle de tuile icne (iconic tile template)
Les tuiles ont les tailles suivantes :
- Flip et cycle Iconic
Petite 159x159 110x110
Moyenne 336x336 202x202
Large 691x336 -
Nul besoin de vous soucier des direntes rsolutions, Windows Phone soccupe de
redimensionner tout pour nous, vous navez besoin que dajouter les images pour la
rsolution XWGA.
Personnaliser les tuiles par dfaut
Nous venons de voir comment pingler notre application sur la page daccueil. Celle-
ci prend par dfaut lapparence de limage se trouvant dans le rpertoire du projet
Assets\Tiles\FlipCycleTileMedium.png, que lon peut retrouver dans lexplorateur de
solutions illustr dans la gure 34.7.
Figure 34.7 Les images par dfaut des tuiles
Cette tuile senrichit du titre de lapplication (voir gure 34.8).
Figure 34.8 Image de la tuile par dfaut
504
PERSONNALISER LES TUILES PAR DFAUT
Plus prcisment, elle est construite grce aux paramtres prsents dans le chier
WMAppManifest.xml, que lon obtient en dpliant le rpertoire properties du projet
et en double-cliquant dessus (voir gure 34.9).
Figure 34.9 Paramtrage de la tuile par dfaut, dans WMAppManifest.xml
Nous pouvons voir que le modle de la vignette est Flip et que lapplication ne supporte
que les tuiles de taille petite et moyenne. Dailleurs, si vous essayez de redimensionner
la tuile sur la page daccueil, vous ne pourrez pas lavoir en large. Pour cela, vous
pouvez cocher la case prise en charge des grandes vignettes et choisir une image
pour la grande taille, par exemple FlipCycleTileLarge.png qui est (comme par hasard)
la bonne taille et qui se trouve dans le rpertoire Assets/Tiles avec les autres images
de tuiles.
Note : pour voir les changements dans lmulateur, vous allez devoir ds-
pingler la tuile et la r-pingler.
Mais lditeur du chier WMAppManifest.xml nest pas complet. Enn, disons quon
peut faire plus de choses directement en modiant le contenu du chier XML. Si vous
louvrez, vous verrez notamment la section Tokens contenant la dnition des tuiles :
1 <Tokens >
2 <PrimaryToken TokenID="DemoTuilesToken" TaskName="_default">
3 <TemplateFlip >
4 <SmallImageURI IsRelative="true" IsResource="false">
Assets\Tiles\FlipCycleTileSmall.png </ SmallImageURI
>
5 <Count >0</Count >
6 <BackgroundImageURI IsRelative="true" IsResource="
false">Assets\Tiles\FlipCycleTileMedium.png </
BackgroundImageURI >
7 <Title >DemoTuiles </Title >
8 <BackContent >
9 </BackContent >
10 <BackBackgroundImageURI >
505
CHAPITRE 34. LES TUILES
11 </BackBackgroundImageURI >
12 <BackTitle >
13 </BackTitle >
14 <LargeBackgroundImageURI IsRelative="true" IsResource
="false">Assets\Tiles\FlipCycleTileLarge.png </
LargeBackgroundImageURI >
15 <LargeBackContent />
16 <LargeBackBackgroundImageURI IsRelative="true"
IsResource="false">
17 </LargeBackBackgroundImageURI >
18 <DeviceLockImageURI >
19 </DeviceLockImageURI >
20 <HasLarge >True </HasLarge >
21 </TemplateFlip >
22 </PrimaryToken >
23 </Tokens >
On y retrouve les diverses urls relatives vers nos images de tuiles, mais aussi dautres
choses. Modions par exemple la balise count pour mettre la valeur 3 la place de 0 :
1 <Count >3</Count >
Modions galement les balises BackContent et BackTitle :
1 <BackContent >Ma super appli </ BackContent >
2 <BackTitle >Vive les tuiles </BackTitle >
Nous obtenons le rsultat dans la gure 34.10.
Sur la partie gauche de limage, nous pouvons voir un petit 3, qui correspond la balise
Count. Cela permet, pourquoi pas, dindiquer quil y a 3 lments nouveaux venir
consulter dans notre application. La partie droite de limage correspond au dos de la
tuile. Rappelez-vous, notre application utilise le modle de tuile Flip qui se retourne
pour fournir dautres informations. Ici, nous avons ach du texte, mais il est galement
possible dacher une image grce la balise BackBackgroundImageURI. Notez que
si vous changez la taille de la tuile, vous verrez que le dos de la tuile ne sache quen
grande ou moyenne taille et quil ne sache pas en petite taille. Mais tout ceci est bien
statique . . . notamment par rapport au chire en haut droite. On ne peut pas envisager
de dterminer quil y aura 3 nouveaux lments tout le temps, ds la cration de
lapplication. Heureusement, il est galement possible de modier la tuile pour mettre
jour quelques informations lorsque lapplication se ferme, et rappeler lutilisateur
o il en tait lorsquil la rouvre. Pour eectuer ces mises jour, il faut accder la
tuile concerne via la classe statique ShellTile - http://msdn.microsoft.com/fr-fr/
library/windowsphone/develop/hh220861(v=vs.105).aspx, avec le code suivant :
1 public MainPage ()
2 {
3 InitializeComponent ();
4
5 ShellTile tuileParDefaut = ShellTile.ActiveTiles.First ();
6
506
PERSONNALISER LES TUILES PAR DFAUT
Figure 34.10 La tuile, de face et de dos
7 if (tuileParDefaut != null)
8 {
9 FlipTileData flipTileData = new FlipTileData
10 {
11 Title = "Ma tuile",
12 Count = 4,
13 BackTitle = "Nouveau titre",
14 BackContent = "Ouvrez vite !",
15 };
16
17 tuileParDefaut.Update(flipTileData);
18 }
19 }
Une fois la mise jour de la tuile faite, nous pourrons avoir un nouveau rendu, illustr
dans la gure 34.11.
Du coup, je vous montre la tuile en grande taille. Notez la prsence du chire 4 en
haut droite qui correspond la proprit Count. Mettre 0 ou null dans la proprit
eacera le nombre qui apparat.
Attention : le fait de mettre jour la tuile par dfaut par code npingle pas
pour autant lapplication sur lcran daccueil. Il faut que ce soit une action
volontaire de lutilisateur. Cela changera juste son apparence.
507
CHAPITRE 34. LES TUILES
Figure 34.11 La tuile cre par code, en grande taille
Et les autres modles de tuiles alors ?
Jy arrive. Car eectivement, nous navons vu que les tuiles qui se retournent ( ip ),
il reste encore les tuiles cycliques ( cycle ) et les tuiles icnes ( iconic ). Sachez ds
prsent que le principe de cration est globalement le mme. Pour les tuiles cycliques
( cycle ), vous pouvez faire dler de 1 9 images. Changez le modle dans lditeur
et vous pourrez voir que vous allez pouvoir remplir jusqu 9 images (voir gure 34.12).
Jen ai prot pour mettre quelques images de notre mascotte prfre dans la gure
34.13. Une fois la mascotte pingle, nous pourrons voir les images dler.
Pour mettre jour limage qui sache par dfaut sur la tuile, on utilisera la classe Cy-
cleTileData - http://msdn.microsoft.com/fr-fr/library/windowsphone/develop/
microsoft.phone.shell.cycletiledata(v=vs.105).aspx et notamment la proprit
CycleImages qui est un tableau dUri pointant sur des images acher. Notez que la
proprit Count est galement disponible pour ce modle de tuile.
Reste les tuiles icnes ( iconic , voir gure 34.14).
Le rsultat des tuiles icnes en grande taille est illustr dans la gure 34.15.
Remarque, ici jai modi la balise Count et la balise Message :
1 <Count >1</Count >
508
PERSONNALISER LES TUILES PAR DFAUT
Figure 34.12 Modication du modle de tuile cyclique
Figure 34.13 Les images de Zozor dlent dans la tuile
509
CHAPITRE 34. LES TUILES
Figure 34.14 Modication du modle de tuiles icnes
Figure 34.15 Tuile icne en grande taille
510
CRER DES TUILES SECONDAIRES
2 <Message >Venez vite dcouvrir Zozor !</Message >
noter quon utilisera la classe IconicTileData - http://msdn.microsoft.com/fr-fr/
library/windowsphone/develop/microsoft.phone.shell.iconictiledata(v=vs.105)
.aspx pour crer la tuile icne par code.
Attention : il nest pas possible de changer dynamiquement (en utilisant du
code) le modle de tuile par dfaut que nous venons de changer par linterface.
Si vous souhaitez le faire une fois votre application termine et dploye sur
un tlphone, il vous faudra mettre jour votre application et la dployer
nouveau.
Crer des tuiles secondaires
La tuile principale permet de lancer lapplication. Il ny a quune faon pour les obtenir :
pingler lapplication depuis le menu, comme nous lavons vu. Les tuiles secondaires
permettent de dmarrer lapplication dune faon particulire. Elles servent en gn-
ral accder des fonctionnalits de lapplication, comme un raccourci. Ainsi, il est
possible de crer des tuiles qui vont naviguer directement sur une page prcise de lap-
plication, avec pourquoi pas des paramtres. Reprenez par exemple notre dernier TP,
qui contenait un jeu de grattage et un jeu de secouage . . . Quand jai ralis ces jeux,
ctait un peu insupportable de devoir passer chaque fois par le menu pour lancer
une application et tester une petite modication. Que je suis triste de ne pas avoir
eu une telle fonctionnalit de tuiles secondaires ! Avec elles, jaurai pu facilement crer
des raccourcis vers les pages de mon choix . . . Alors, rparons tout de suite cette er-
reur et rajoutons sur la page principale deux boutons permettant de crer nos tuiles
secondaires :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="auto" />
4 <RowDefinition Height="*" />
5 </Grid.RowDefinitions >
6 <StackPanel >
7 <Button Content="Grattage ..." Tap="Button_Tap" />
8 <Button Content="Secouage ..." Tap="Button_Tap_1" />
9 </StackPanel >
10 <StackPanel Grid.Row="1" VerticalAlignment="Bottom">
11 <Button Content="Crer tuile grattage" Tap="
Button_Tap_2" />
12 <Button Content="Crer tuile secouage" Tap="
Button_Tap_3" />
13 </StackPanel >
14 </Grid >
Nous utiliserons grosso modo le mme code et le mme principe pour crer une tuile
secondaire :
511
CHAPITRE 34. LES TUILES
1 private void Button_Tap_2(object sender , System.Windows.Input.
GestureEventArgs e)
2 {
3 ShellTile tuileGrattage = ShellTile.ActiveTiles.
FirstOrDefault(elt => elt.NavigationUri.ToString ().
Contains("Grattage.xaml"));
4 if (tuileGrattage == null)
5 {
6 FlipTileData tuile = new FlipTileData
7 {
8 SmallBackgroundImage = new Uri("/Assets/Tiles/
gratter -petit.png", UriKind.Relative),
9 BackgroundImage = new Uri("/Assets/Tiles/gratter -
moyen.png", UriKind.Relative),
10 Title = "Grattage",
11 BackContent = "Accs direct au gratage",
12 };
13
14 ShellTile.Create(new Uri("/Grattage.xaml", UriKind.
Relative), tuile , false);
15 }
16 }
17
18 private void Button_Tap_3(object sender , System.Windows.Input.
GestureEventArgs e)
19 {
20 ShellTile tuileSecouage = ShellTile.ActiveTiles.
FirstOrDefault(elt => elt.NavigationUri.ToString ().
Contains("Secouage.xaml"));
21 if (tuileSecouage == null)
22 {
23 FlipTileData tuile = new FlipTileData
24 {
25 SmallBackgroundImage = new Uri("/Assets/Tiles/
secouer -petit.png", UriKind.Relative),
26 BackgroundImage = new Uri("/Assets/Tiles/secouer -
moyen.png", UriKind.Relative),
27 Title = "Secouage",
28 BackContent = "Accs direct au secouage",
29 };
30
31 ShellTile.Create(new Uri("/Secouage.xaml", UriKind.
Relative), tuile , false);
32 }
33 }
Pour viter dajouter plusieurs fois la mme tuile, on pourra se baser sur la proprit
NavigationUri des tuiles existantes, an de vrier si elles ont dj t ajoutes. Il ne
reste plus qu cliquer sur nos boutons. Vous verrez que lorsque la tuile secondaire
est cre, nous sommes renvoys sur la page daccueil pour voir le rsultat (voir gure
512
CRER DES TUILES SECONDAIRES
34.16), ce qui implique que lapplication passe dans un mode dsactiv. Pour la r-
activer, il faudra soit faire un retour arrire, soit pourquoi pas utiliser nos nouvelles
tuiles.
Figure 34.16 Les tuiles secondaires de notre application de jeu
Et ainsi, nous accdons directement la page XAML indique lors de la cration de
la tuile secondaire, qui permet de naviguer directement sur la page. Pratique non ?
Remarquez que vous pouvez galement passer des paramtres la page, comme ce
que nous avions fait dans le chapitre sur la navigation. Ici, ce nest pas utile car nous
avons deux pages distinctes, mais nous pourrions avoir la mme page qui ache une
che produit dune application de vente que lon souhaiterait charger avec des produits
dirents . . . Par exemple :
1 string idProduit = "telehd";
2 ShellTile tuileProduit = ShellTile.ActiveTiles.FirstOrDefault(
elt => elt.NavigationUri.ToString ().Contains("idproduit=" +
idProduit));
3 if (tuileProduit == null)
4 {
5 FlipTileData tuile = new FlipTileData
6 {
7 Title = "Tl HD",
8 BackContent = "Accs direct la tl de vos rves ..."
,
9 };
10
513
CHAPITRE 34. LES TUILES
11 ShellTile.Create(new Uri("/VoirProduit.xaml?idproduit=" +
idProduit , UriKind.Relative), tuile , false);
12 }
Vous pouvez voir ce que donne ce bout de code sur la gure 34.17.
Figure 34.17 La tuile secondaire
Je vous renvoie au chapitre sur la navigation pour exploiter la query string, avec :
1 NavigationContext.QueryString.TryGetValue("idproduit", out
valeur);
Bien sr, vous pouvez crer des tuiles secondaires dans tous les modles que vous
souhaitez. Illustrons par exemple le modle cyclique :
1 ShellTile secondeTuile = ShellTile.ActiveTiles.FirstOrDefault(
elt => elt.NavigationUri.ToString ().Contains("VieZozor.xaml"
));
2 if (secondeTuile == null)
3 {
4 CycleTileData tuile = new CycleTileData
5 {
6 CycleImages = new Uri[]
7 {
8 new Uri("/zozor_01.png", UriKind.Relative),
9 new Uri("/zozor_02.png", UriKind.Relative),
10 new Uri("/zozor_03.png", UriKind.Relative),
514
MODIFIER ET SUPPRIMER UNE TUILE
11 new Uri("/zozor_04.png", UriKind.Relative),
12 },
13 Title = "Accdez la vie de zozor"
14 };
15
16 ShellTile.Create(new Uri("/VieZozor.xaml", UriKind.Relative
), tuile , false);
17 }
Modier et supprimer une tuile
Nous avons vu quil tait possible de modier des tuiles via la mthode Update. Ceci est
valable pour la tuile principale, mais galement pour les tuiles secondaires. Par exemple,
le code ci-dessous montre comment mettre jour une tuile secondaire dune application
de vente en ligne en achant le changement de stock de lun de ses produits :
1 ShellTile tuileProduit = ShellTile.ActiveTiles.FirstOrDefault(
elt => elt.NavigationUri.ToString ().Contains("idproduit=" +
idProduit));
2 if (tuileProduit != null)
3 {
4 FlipTileData tuile = new FlipTileData
5 {
6 Title = "Tl HD",
7 BackContent = "Plus que 2 produits en stock !!!",
8 };
9
10 tuileProduit.Update(tuile);
11 }
Il nest par contre pas possible de modier lURL de la page acher. Dans ce cas,
il faudra la supprimer puis la recrer. Supprimer une tuile secondaire est trs facile, il
sut dutiliser la mthode Delete. Par exemple, si nous souhaitons supprimer la tuile
du secouage, nous pourrons crire :
1 ShellTile tuileSecouage = ShellTile.ActiveTiles.FirstOrDefault(
elt => elt.NavigationUri.ToString ().Contains("Secouage.xaml"
));
2 if (tuileSecouage == null)
3 tuileSecouage.Delete ();
Lutilisateur pourra bien sr faire la mme chose tout seul depuis lcran daccueil.
Attention, on peut supprimer une tuile secondaire, par contre il est impossible
de supprimer la tuile principale par code.
515
CHAPITRE 34. LES TUILES
Remarque, il est trs courant de mettre jour une tuile via un agent qui
tourne en tche de fond. Cela ore la possibilit dinformer lutilisateur que
quelque chose de nouveau sest pass dans son application et quil serait bien
de lancer lapplication pour le dcouvrir, comme lapplication de mail qui
ache le nombre de mails non-lus. Nous dcouvrirons les agents tournant en
tche de fond dans un chapitre ultrieur.
En rsum
Les tuiles se trouvent sur la page daccueil dun Windows Phone et sont un
raccourci volu permettant de dmarrer une application.
Elles sont disponibles en plusieurs tailles : petite, moyenne ou grande.
Il existe plusieurs modles de tuiles : tuile icne ( iconic ), tuile cyclique ( cy-
clic ), tuile qui se retourne ( ip ).
Il est possible de crer des tuiles secondaires, qui permettent daccder une
application laide de raccourcis supplmentaires.
516
Chapitre 35
Les notications
Dicult :
Le principe des notications nest pas vraiment nouveau mais est globalement plutt simple.
Imaginons que jinstalle une application qui me permette de consulter les cours de la plate-
forme OpenClassrooms. Ca y est, jai lu tous les cours qui mintressent et jai hte que de
nouveaux cours voient le jour pour que je puisse assouvir ma soif dapprendre. Sauf que je
ne vais pas dmarrer lapplication toutes les 5 minutes histoire de voir si un nouveau cours
est en ligne . . . a serait bien si quelquun me prvenait ds quun nouveau cours est mis
en ligne. Et tout a, mme si lapplication nest pas dmarre ou pingle . . .
517
CHAPITRE 35. LES NOTIFICATIONS
Voil, le principe de la notication. Cela consiste en la rception dun petit message sur
notre tlphone avec une information. La rception du message peut tre signale par
un bruit ou une vibration, puis le message reste ach quelques secondes pour nous
donner le temps de le lire. Mieux, si nous cliquons sur le message, notre application
est automatiquement dmarre. En revanche, un des inconvnients est justement que
la notication ne sache que quelques secondes et si on est loin du tlphone, il ny
a aucun moyen pour voir le contenu si on la rat (en tout cas lheure o jcris ces
lignes, car il y aurait des rumeurs de cration de centre de notication . . .).
Mais les notications sont tout de mme bien pratiques, donc plongeons nous tout
de suite dans le vif du sujet pour crer nos propres alertes et rester au courant des
nouveauts de nos applications prfres !
Le principe darchitecture des notications
Pour recevoir une notication, il faut que quelquun lenvoie. Forcment ! Et pour que
ce quelquun lenvoie, il faut quon lui dise que a nous intresse de recevoir des noti-
cations. Donc, le principe global peut se rsumer dans les tapes suivantes :
Lapplication Windows Phone dclare un canal pour recevoir des notications.
Lapplication Windows Phone indique lmetteur (le crateur de lapplication)
quelle souhaite recevoir des notications et lui donne lidentiant unique du
tlphone sur lequel elle tourne ainsi que le canal.
Lmetteur enregistre lidentiant et le canal et lajoute la liste des toutes les
applications souhaitant recevoir des notications.
Lmetteur souhaite envoyer un message : pour chaque tlphone souhaitant
recevoir des notications, le message est envoy au service de notication de
Microsoft (le Microsoft Push Notication Service) grce au canal.
Le service de notication envoi le message chaque tlphone.
Le message sache sur le tlphone de lutilisateur.
Il y a donc trois intervenants dans ce mcanisme :
Le tlphone, qui reoit les notications, ainsi que lapplication installe dessus
(votre application!),
Le service de notication, cr par le dveloppeur qui souhaite envoyer des no-
tications (VOUS!),
Le service de notication de Microsoft, qui soccupe denvoyer vraiment le mes-
sage au tlphone.
Sachez que le message peut tre de plusieurs types.
Cela peut tre un message systme qui apparat mme si lapplication na pas
dmarre. Il apparat en haut du tlphone et si lon clique dessus alors lappli-
cation dmarre. Il sagit des notications Toast.
Cela peut tre un message qui va modier lapparence dune tuile. Ce message
a peu dintrt depuis Mango car les tuiles peuvent tre pilotes par code facile-
ment, comme nous lavons vu prcdemment, mais il peut quand mme trouver
son intrt. Il sagit des notications Tile.
518
LE PRINCIPE DE CRATION DU SERVEUR DE NOTIFICATION
Enn, cela peut tre un message qui apparat alors que lapplication est en cours
dutilisation. Si lapplication nest pas lance, alors le message est ignor. Il sagit
des notications Raw.
On peut rsumer larchitecture avec le schma de la gure 35.1, qui comprend 4 grandes
tapes :
1. La connexion stablit et une URL est cre pour la communication.
2. Communication de lURL.
3. Envoi du message.
4. Envoi du message sur le tlphone.
Figure 35.1 Architecture des notications
Le principe de cration du serveur de notication
Je vais dcrire ici le principe de cration du serveur de notication sachant que nous
nallons pas le raliser car il sort de la porte de ce cours. Mais ne vous inquitez pas,
dans ce chapitre nous ferons comme si le serveur avait t cr et nous nous occuperons
de ce qui se passe juste aprs un envoi de notication. Ce serveur de notication
consiste en gnral en un site web ou des services web, car ceux-ci doivent tre toujours
disponibles en ligne, nimporte quel moment. Celui-ci peut-tre bien sr un serveur
base de produits Microsoft (avec un logiciel de serveur IIS et des composants WCF),
mais il peut tout aussi bien tre en PHP, Ruby ou ce que vous matrisez. Le principe est
de fournir une URL permettant denregistrer un identiant unique de tlphone ainsi
519
CHAPITRE 35. LES NOTIFICATIONS
que le canal (en fait, seul le canal est vraiment indispensable). Un tlphone souhaitant
recevoir des notications va senregistrer auprs du service de notication de Microsoft
et recevra une URL identiant le canal en retour. LURL est de la forme :
http://db3.notify.live.net/throttledthirdparty/01.00/
AAE17kNJdrSwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXQTg1QkZDMkUxREQ
Le tlphone appelle ensuite le serveur de notication pour lui fournir cette URL ainsi
que son identiant unique. Le serveur devra tre capable de stocker cet identiant
ainsi que lURL et devra galement permettre de modier lURL si lidentiant est
dj stock. Le serveur va donc servir stocker une liste didentiants associs des
URL et la maintenir jour. Puis, lorsque nous voudrons envoyer une notication
tous les utilisateurs de notre application, il sura de parcourir cette liste et denvoyer
un message au serveur de Microsoft, via lURL du canal, contenant le message. Cest
ensuite le serveur de Microsoft qui soccupe denvoyer la notication chaque tlphone,
grce ce canal.
Et voil, en fait cest trs simple.
Dans lidal, le serveur devra galement permettre de dsabonner un tlphone ne sou-
haitant plus recevoir de notications, car il est indispensable que votre application
propose son utilisateur un moyen darrter de recevoir des notications. De mme,
lorsque le serveur de notication envoie la requte Microsoft permettant lenvoi du
message, ce dernier lui rpond en lui indiquant notamment si le tlphone est injoi-
gnable. Cela pourra correspondre au fait que lapplication est dsinstalle par exemple.
ce moment-l, il faudra mettre jour la liste des identiants et des URL an de sup-
primer le couple identiant-canal, pour ne plus tenter de lui envoyer de notications.
Nhsitez pas crer votre propre serveur de notication, avec le langage de votre
choix, et pourquoi pas proposer les sources dun tel serveur an que chacun puisse
sen servir pour hberger son serveur de notication.
Les dirents messages de notications
Nous avons vu les dirents types de notication :
Toast,
Tile,
Raw.
Pour dclencher une telle notication, il faut envoyer un message au serveur de Mi-
crosoft contenant du XML, ou du texte simple, en fonction du type de notication.
Ce message devra tre envoy avec la mthode POST, dans un format XML (content-
type= text/xml ) et contenir des en-ttes HTTP personnalises. Il y a plusieurs
lments passer dans les en-ttes HTTP, plus ou moins obligatoires. Par exemple,
il est possible et facultatif de fournir un identiant de message via len-tte HTTP
MessageID. En revanche, nous devons obligatoirement fournir dans len-tte le type
de notication. Cela se fait avec lattribut X-Windows-Phone-Target. Par exemple, on
ajoute le code ci-dessous dans len-tte pour une notication de type toast :
520
LES DIFFRENTS MESSAGES DE NOTIFICATIONS
1 X-WindowsPhone -Target:type
Le message de notication envoy au serveur de Microsoft peut tre de trois types
dirents :
Message de type toast, pour les notications toast.
Message de type token, pour les notications tile.
Message de type raw, pour les notications raw.
Remarque : si le type de notication nest pas prcis, alors la notication
sera de type raw.
Nous devons galement indiquer le dlai denvoi, qui varie selon le type de notication
comme le montre le tableau suivant.
- Envoi immdiat Dlai de 450
secondes (7
minutes et demie)
Dlai de 15
minutes
Tile 1 11 21
Toast 2 12 22
Raw 3 13 23
Par exemple, pour envoyer une notication Toast immdiatement, je devrais avoir
len-tte HTTP suivante :
1 X-WindowsPhone -Target:toast
2 X-NotificationClass:2
Ensuite, reste le corps du message.
Pour envoyer un message de type raw, cest trs simple. Il sut denvoyer le
message tel quel, pas besoin dXML.
Pour envoyer un message de type toast, nous aurons besoin de dmarrer lap-
plication dans un contexte particulier. Pour cela, il nous faudra excuter une
requte query string dans une page XAML de lapplication. Il faudra envoyer le
XML suivant avec cette page XAML comme Paramtre :
<?xml version="1.0" encoding="utf-8"?>
<wp:Notification xmlns:wp="WPNotification">
<wp:Toast>
<wp:Text1>Titre</wp:Text1>
<wp:Text2>Sous titre</wp:Text2>
<wp:Param>paramtre</wp:Param>
</wp:Toast>
</wp:Notification>
Enn, pour envoyer un message de type tile, nous aurons le XML suivant :
<?xml version="1.0" encoding="utf-8"?>
<wp:Notification xmlns:wp="WPNotification">
521
CHAPITRE 35. LES NOTIFICATIONS
<wp:Tile>
<wp:BackgroundImage>Url image de fond</wp:BackgroundImage>
<wp:Count>Numro en haut droite</wp:Count>
<wp:Title>Titre</wp:Title>
<wp:BackBackgroundImage>Url image de fond du dos de la tuile</wp:BackBackgroundImage>
<wp:BackTitle>Titre du dos de la tuile</wp:BackTitle>
<wp:BackContent>Contenu du dos de la tuile</wp:BackContent>
</wp:Tile>
</wp:Notification>
Nous allons voir dans le chapitre suivant comment envoyer ces beaux messages et
surtout ce quil faut faire ct Windows Phone pour crer un canal et ragir aux
notications.
Note : Si vous devez mettre des caractres spciaux dans vos messages, alors
vous devez les encoder en XML, par exemple < devient &lt ;
Cration du client Windows Phone recevant la noti-
cation
Avant toute chose, vous devez dclarer que votre application utilise des notications.
Cela se fait en utilisant la capacit ID_CAP_PUSH_NOTIFICATION que nous allons
voir luvre dans cette section. Il faut ensuite crer ou utiliser un canal depuis notre
application Windows Phone. Un canal est identi par son nom. La premire chose est
de tenter de le rcuprer sil existe dj, sinon il faut le crer. Voici comment utiliser
un canal pour recevoir une notication Toast :
1 public MainPage ()
2 {
3 InitializeComponent ();
4
5 string nomCanal = "TestCanalOpenClassroomsNico";
6 HttpNotificationChannel canal = HttpNotificationChannel.
Find(nomCanal);
7
8 if (canal == null)
9 {
10 // si le canal n'est pas trouv, on le cre
11 canal = new HttpNotificationChannel(nomCanal);
12
13 canal.ChannelUriUpdated += canal_ChannelUriUpdated;
14 canal.ErrorOccurred += canal_ErrorOccurred;
15
16 // On s'abonne cet vnement si on veut tre averti
de la reception de la notification toast lorsque l'
application
522
CRATION DU CLIENT WINDOWS PHONE RECEVANT LA NOTIFICATION
17 // est ouverte , sinon on ne la recoit pas
18 canal.ShellToastNotificationReceived +=
canal_ShellToastNotificationReceived;
19
20 canal.Open();
21
22 // Permet de dclarer le canal pour recevoir les toasts
23 canal.BindToShellToast ();
24 }
25 else
26 {
27 // le canal est dj cr, on l'utilise
28 canal.ChannelUriUpdated += canal_ChannelUriUpdated;
29 canal.ErrorOccurred += canal_ErrorOccurred;
30 canal.ShellToastNotificationReceived +=
canal_ShellToastNotificationReceived;
31
32 // On affiche le canal dans la console de sortie pour
pouvoir l'exploiter ensuite dans notre appli de test
d'envoi
33 // normalement , on l'aurait envoy notre serveur de
notification , avec l'identifiant unique du tlphone
34 Debug.WriteLine(canal.ChannelUri.ToString ());
35 }
36 }
Si le canal existe dj, alors on obtient son URL qui normalement devra tre envoye
notre serveur de notifcation. Ici, je vais simplement lacher dans la console de sortie
pour viter de devoir crer un serveur de notication. Je vais ainsi pouvoir rcuprer
lURL et lutiliser dans une application tierce qui enverra la requte au serveur de
notication de Microsoft. Pour linstant, implmentez les vnements ainsi :
1 private void canal_ShellToastNotificationReceived(object sender
, NotificationEventArgs e)
2 {
3 // optionnel , cet vnement est lev quand l'appli est
ouverte et qu 'on recoit la notif
4 }
5
6 private void canal_ErrorOccurred(object sender ,
NotificationChannelErrorEventArgs e)
7 {
8 Dispatcher.BeginInvoke (() => MessageBox.Show(string.Format(
"Une erreur est survenue {0}, {1} ({2}) {3}", e.
ErrorType , e.Message , e.ErrorCode , e.ErrorAdditionalData
)) );
9 }
10
11 private void canal_ChannelUriUpdated(object sender ,
NotificationChannelUriEventArgs e)
523
CHAPITRE 35. LES NOTIFICATIONS
12 {
13 // On affiche le canal dans la console de sortie pour
pouvoir l'exploiter ensuite dans notre appli de test d'
envoi
14 // normalement , on l'aurait envoy notre serveur de
notification , avec l'identifiant unique du tlphone
15 Debug.WriteLine(e.ChannelUri.ToString ());
16 }
Vous aurez besoin de :
1 using Microsoft.Phone.Notification;
Puis dmarrez lapplication en debug, lURL sache dans la fentre de sortie de Visual
Studio comme dans la gure 35.2.
Figure 35.2 Url du canal dans la fentre de sortie
Je lai un peu masque ici, mais elle a la forme :
http://db3.notify.live.net/throttledthirdparty/01.00/
AAHmJDXpe47LTI0ct6NNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXg1QTg1QkZDMkUxREQ
Sauvegardez cette URL dans un coin, nous allons en avoir besoin. Nous pouvons arrter
lapplication mais sans arrter lmulateur. Le canal est cr. Remarquez que si vous
redmarrez lapplication, nous rcuprrons le canal dj cr et obtenons nouveau la
mme URL.
Si vous vous souvenez de ce dont nous avons parl juste avant, cest cette URL qui
devra tre utilise pour envoyer un message au serveur de notication de Microsoft.
Par souci de simplicit, ici je vais utiliser directement lURL pour envoyer ma requte
en POST, mais vous aurez compris que le rle de notre serveur est de stocker ces
URL dans une liste et denvoyer le message toutes les URL que nous avons stockes,
correspondant aux utilisateurs qui souhaitent recevoir nos notications.
524
CRATION DU CLIENT WINDOWS PHONE RECEVANT LA NOTIFICATION
Nous devons donc envoyer dsormais une requte en POST cette url, pour cela nous
allons crer une petite application console grce Visual Studio Express 2012 pour
Windows Desktop, que vous pouvez tlcharger gratuitement cet emplacement -
http://www.microsoft.com/fr-fr/download/details.aspx?id=34673 (je vous fait
grce de linstallation qui ne devrait pas poser de problme).
Note : Vous pouvez bien sr implmenter un vrai serveur de notication si
vous le souhaitez, mais pour la dmonstration ce sera plus simple denvoyer
un simple message en POST ainsi.
Ici, vu que je me suis abonn aux notications toast (grce canal.BindToShellToast()),
il faut que jenvoie un message toast, par exemple :
1 <?xml version="1.0" encoding="utf -8"?>
2 <wp:Notification xmlns:wp="WPNotification">
3 <wp:Toast >
4 <wp:Text1 >Texte 1 youpi </wp:Text1 >
5 <wp:Text2 >Texte 2 joie </wp:Text2 >
6 <wp:Param >/ MainPage.xaml?cle=parametre </wp:Param >
7 </wp:Toast >
8 </wp:Notification >
Le principe est donc de faire une requte POST, avec les bons headers, contenant le
message de type toast, et de le poster lurl rcupre. Voici le code C# permettant
de raliser ceci dans une application console :
1 try
2 {
3 // url o envoyer le message
4 // normalement , il faudrait rcuprer la liste des urls
stockes sur le serveur de notification
5 // et envoyer le message toutes ces urls
6 string urlOuEnvoyerMessage = "http :// db3.notify.live.net/
throttledthirdparty/01.00/
AAHmJDXpe47LTI0ct6NNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXg1QTg1QkZDMkUxREQ
";
7
8 HttpWebRequest requete = (HttpWebRequest)WebRequest.Create(
urlOuEnvoyerMessage);
9 requete.Method = "POST"; // envoi en POST
10 string messageToastAEnvoyer = @"<?xml version=""1.0""
encoding=""utf -8""?>
11 <wp:Notification xmlns:wp=""WPNotification"">
12 <wp:Toast >
13 <wp:Text1 >Texte 1 youpi </wp:Text1 >
14 <wp:Text2 >Texte 2 joie </wp:Text2 >
15 <wp:Param >/ MainPage.xaml?cle=parametre </wp:
Param >
16 </wp:Toast >
17 </wp:Notification >";
525
CHAPITRE 35. LES NOTIFICATIONS
18
19 byte[] message = Encoding.Default.GetBytes(
messageToastAEnvoyer);
20 requete.ContentLength = message.Length;
21 requete.ContentType = "text/xml";
22 requete.Headers.Add("X-WindowsPhone -Target", "toast"); //
notification de type toast
23 requete.Headers.Add("X-NotificationClass", "2"); // envoi
immdiat
24
25 using (Stream requestStream = requete.GetRequestStream ())
26 {
27 requestStream.Write(message , 0, message.Length);
28 }
29
30 // envoi de la notification , et rcupration du retour
31 HttpWebResponse response = (HttpWebResponse)requete.
GetResponse ();
32 string statutNotification = response.Headers["X-
NotificationStatus"];
33 string statutCanal = response.Headers["X-SubscriptionStatus
"];
34 string statutMateriel = response.Headers["X-
DeviceConnectionStatus"];
35
36 // affiche le rsultat de la requte
37 Console.WriteLine(statutNotification + " | " +
statutMateriel + " | " + statutCanal);
38
39 // gestion d'erreur ultra simplifie
40 if (string.Compare(statutNotification , "Dropped",
StringComparison.CurrentCultureIgnoreCase) == 0)
41 {
42 // il faut arrter de tenter d'envoyer des messages
ce tlphone
43 }
44 }
45 catch (Exception ex)
46 {
47 Console.WriteLine("Erreur d'envoi : " + ex);
48 }
Et nous verrons la notication Toast sacher sur notre Windows Phone (voir gure
35.3).
Et ce qui est intressant, cest que si lon clique sur la notication toast, alors notre
application se lance et navigue sur la page passe en paramtre. Ceci nous permet ga-
lement de rcuprer les paramtres de la query string (voir code et gure qui suivent).
1 protected override void OnNavigatedTo(NavigationEventArgs e)
2 {
526
CRATION DU CLIENT WINDOWS PHONE RECEVANT LA NOTIFICATION
Figure 35.3 La notication Toast sache dans lmulateur
3 string valeur;
4 if (NavigationContext.QueryString.TryGetValue("cle", out
valeur))
5 {
6 MessageBox.Show(valeur);
7 }
8 base.OnNavigatedTo(e);
9 }
Pour avoir le rsultat prsent dans la gure 35.4.
Attention, il est important de traiter le retour du message en fonction des
codes derreurs que nous obtenons en rponse de lenvoi de la notication.
Les erreurs peuvent tre de diverses sortes. On peut par exemple dtecter
si lutilisateur a dsinstall lapplication, cela voudra dire quil nest plus n-
cessaire de lui envoyer de message et quil va falloir enlever cette url de la
liste de notre serveur de notication. Cest ce que jai fait dans lexemple de
code prcdent, de manire minimale je le reconnais. Vous pouvez consul-
ter les codes derreurs cet emplacement - http://msdn.microsoft.com/
fr-fr/library/windowsphone/develop/ff941100(v=vs.105).aspx.
noter que si lapplication est ouverte, alors le message toast ne sache pas en haut de
lcran. Lapplication peut cependant tre notie de la rception dun message toast
527
CHAPITRE 35. LES NOTIFICATIONS
Figure 35.4 Utilisation de la query string
en sabonnant lvnement ShellToastNoticationReceived et ainsi faire ce quelle
dsire, par exemple acher le message :
1 private void canal_ShellToastNotificationReceived(object sender
, NotificationEventArgs e)
2 {
3 // optionnel , cet vnement est lev quand l'appli est
ouverte et qu 'on recoit la notif
4 string message = e.Collection["wp:Text1"] + e.Collection["
wp:Text2"];
5 Dispatcher.BeginInvoke (() => MessageBox.Show(message));
6 }
Ici, nous utilisons simplement la bote de message MessageBox.Show pour acher le
message de la notication reue. Vous pouvez en faire ce que vous voulez, lacher
dans un TextBlock, ou juste traiter le message.
Pour les autres types de notications, le principe est le mme. Veuillez toujours
faire attention au type de notications que vous envoyez dans les en-ttes HTTP, ainsi
quau dlai denvoi. De mme, pour quun tlphone puisse recevoir les notications
dun certain type, pensez dclarer le canal comme tel. Par exemple, nous avons vu
que pour recevoir des notications toasts, nous utilisions :
1 canal.BindToShellToast ();
Pour les notications tiles, il faudra utiliser :
528
CRATION DU CLIENT WINDOWS PHONE RECEVANT LA NOTIFICATION
1 canal.BindToShellTile ();
Pour les notications raw, il ny a rien de spcial faire sur le canal. Il faudra par
contre sabonner lvnement HttpNoticationReceived :
1 [...]
2 canal.HttpNotificationReceived +=
canal_HttpNotificationReceived;
3 [...]
4 private void canal_HttpNotificationReceived(object sender ,
HttpNotificationEventArgs e)
5 {
6 using (System.IO.StreamReader reader = new System.IO.
StreamReader(e.Notification.Body))
7 {
8 string message = reader.ReadToEnd ();
9 Dispatcher.BeginInvoke (() => MessageBox.Show("
Notification raw reue : " + message));
10 }
11 }
Remarque : Il est demand de pouvoir dsactiver les notications depuis lap-
plication. Pensez rajouter une interface qui permet lutilisateur de se
dsabonner.
En rsum
Les notications permettent denvoyer un message ou une demande de mise
jour de tuile.
La notication de type toast peut-tre reue mme si lapplication nest pas
dmarre.
Le dveloppeur aura besoin de crer un serveur de notication, accessible
tout moment, an de maintenir une liste de canaux de communication avec les
tlphones intresss pour recevoir des notications.
529
CHAPITRE 35. LES NOTIFICATIONS
530
Chapitre 36
TP : Amliorer lapplication mto
avec golocalisation et tuiles
Dicult :
Que de nouvelles fonctionnalits dcouvertes. Cest le moment rv pour les mettre en
pratique et amliorer notre superbe application mto de la partie prcdente.
Nous allons jouer avec les tuiles et la golocalisation. Vous tes prt ? Alors cest parti !
531
CHAPITRE 36. TP : AMLIORER LAPPLICATION MTO AVEC
GOLOCALISATION ET TUILES
Instructions pour raliser le TP
Franchement, une application mto o il faut absolument saisir le nom de la ville o
nous nous trouvons, vous conviendrez avec moi que ce nest pas terrible ! Alors que
nos tlphones possdent un GPS intgr. . . Nous allons donc proposer lutilisateur
dacher la mto correspondant sa position. Donc premire chose faire, rajouter
un bouton dans la barre dapplication qui achera la mto votre position. Ensuite,
imaginons que je veuille rapidement connatre la mto de Paris et de Toulouse, histoire
de savoir o il vaut mieux que je passe le week-end. Comme cest quelque chose que
je fais rgulirement, jai besoin de la possibilit de rajouter un raccourci vers ces
villes. Mon application va donc permettre dpingler des villes depuis la page de choix
de villes. Si la ville a dj t choisie, il faut que le bouton soit gris. Bien sr, le
dmarrage de lapplication via des tuiles secondaires achera directement la mto de
la ville choisie. La tuile contiendra forcment le nom de la ville. Je vous laisse libre de
choisir le modle de tuile qui vous fait plaisir.
Voici un programme intressant.
Attention avant de vous lancer, il va vous manquer quelque chose. Le GPS fournit une
position avec une longitude et une latitude alors que nous interrogions le service web
de mto avec un nom de ville en entre. Donc, soit il vous faut donc une solution pour
transformer une position GPS en un nom de ville (on appelle cela du gocodage invers),
soit il faudrait que le service web accepte dutiliser des coordonnes GPS. Et vous savez
quoi ? Il laccepte. Cest la classe ! Cest le mme principe, il sut de remplacer le nom
de la ville par les coordonnes sous la forme ci-dessous, avec la premire coordonne,
la latitude, et la seconde, la longitude.
1 http://free.worldweatheronline.com/feed/weather.ashx?q=44.
839073 ,-0.579113&format=json&num_of_days=5&key=MA_CLE_API
En rsum, je vous propose de raliser les lments suivants : 1. Utiliser le GPS pour
permettre de vous golocaliser, 2. Rajouter un bouton dans la barre dapplication pour
acher la mto votre position, 3. Rajouter deux tuiles de raccourci achant la
mto Paris et Toulouse.
Voil, vous avez tout. vous de jouer.
Correction
Je suis certain que vous vous en tes trs bien sorti avec ce petit exercice sympathique.
Voici ma correction, je ne vais pas tout re-dtailler mais simplement les choses qui ont
chang par rapport au TP prcdent dapplication mto.
1. Utiliser le GPS pour vous golocaliser Nous avons premirement besoin duti-
liser le GPS an de nous golocaliser. Vous devez utiliser la classe Geolocator, via par
exemple une variable prive :
1 private Geolocator geolocator;
532
CORRECTION
Vous initialisez cette variable geolocator dans le constructeur :
1 public MainPage ()
2 {
3 InitializeComponent ();
4 geolocator = new Geolocator ();
5 DataContext = this;
6 }
Ici, nul besoin davoir une prcision importante, la localisation approximative
sut.
2. Rajouter un bouton dapplication pour acher la mto votre position
On rajoute galement un bouton dans la barre dapplication. Il possde une image
(gps.png) et un texte (Ma position), et appelle une mthode (Position_Click) lorsquon
clique dessus :
1 <phone:PhoneApplicationPage.ApplicationBar >
2 <shell:ApplicationBar IsVisible="True">
3 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/gps.png" Text="Ma position" Click="Position_Click"
/>
4 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/add.png" Text="Ajouter" Click="Ajouter_Click"/>
5 <shell:ApplicationBarIconButton IconUri="/Assets/Icones
/feature.settings.png" Text="Choisir" Click="
Choisir_Click"/>
6 </shell:ApplicationBar >
7 </phone:PhoneApplicationPage.ApplicationBar >
Pour la peine, je me suis ralis une petite image pour symboliser le GPS. Vous ne
manquerez pas dadmirer ma matrise de Paint (image dans le chapitre suivant) ! Nou-
bliez pas de changer les proprits de limage pour mettre laction de gnration
Contenu , et la proprit Copier dans le rpertoire Copier si plus rcent .
Lorsque lon clique sur le bouton, une mthode est appele pour dmarrer le service de
localisation :
1 private async void Position_Click(object sender , EventArgs e)
2 {
3 ChargementEnCours = true;
4 try
5 {
6 Geoposition geoposition = await geolocator.
GetGeopositionAsync(TimeSpan.FromMinutes(5),
TimeSpan.FromSeconds(10));
7 string position = geoposition.Coordinate.Latitude.
ToString(NumberFormatInfo.InvariantInfo) + "," +
geoposition.Coordinate.Longitude.ToString(
NumberFormatInfo.InvariantInfo);
533
CHAPITRE 36. TP : AMLIORER LAPPLICATION MTO AVEC
GOLOCALISATION ET TUILES
8 WebClient client = new WebClient ();
9 string resultatMeteo = await client.
DownloadStringTaskAsync(new Uri(string.Format("http
:// free.worldweatheronline.com/feed/weather.ashx?q={
0}& format=json&num_of_days=5&key=MA_CLE_API",
position , UriKind.Absolute)));
10 TraiteResultats(resultatMeteo);
11 NomVille = position;
12 }
13 catch (Exception)
14 {
15 MessageBox.Show("Vous devez activer le GPS pour pouvoir
utiliser cette fonctionnalit");
16 ChargementEnCours = false;
17 }
18 }
Noubliez pas dactiver la capacit ID_CAP_LOCATION, qui sert autoriser
lutilisation du GPS.
Notez la prsence du mot cl async dans la signature de la mthode. Il y a galement
un petit try/catch pour vrier que le GPS est utilisable. Et puis jappelle le service de
localisation pour obtenir la position de lutilisateur, que je fournis au service web. La
mthode TraiteResultats contient la logique dachage qui a t factorise, car utilise
deux endroits :
1 private void TraiteResultats(string resultats)
2 {
3 RootObject resultat = JsonConvert.DeserializeObject <
RootObject >( resultats);
4 List <Meteo > liste = new List <Meteo >();
5 foreach (Weather temps in resultat.data.weather.OrderBy(w
=> w.date))
6 {
7 Meteo meteo = new Meteo { TemperatureMax = temps.
tempMaxC + " C", TemperatureMin = temps.tempMinC +
" C" };
8 DateTime date;
9 if (DateTime.TryParse(temps.date , out date))
10 {
11 meteo.Date = date.ToString("dddd dd MMMM");
12 meteo.Temps = GetTemps(temps.weatherCode);
13 WeatherIconUrl2 url = temps.weatherIconUrl.
FirstOrDefault ();
14 if (url != null)
15 {
16 meteo.Url = new Uri(url.value , UriKind.Absolute
);
534
CORRECTION
17 }
18 }
19 liste.Add(meteo);
20 }
21 ListeMeteo = liste;
22 ChargementEnCours = false;
23 }
3. Rajouter deux tuiles secondaires achant la mto Paris et Toulouse
Reste maintenant grer lpinglage des villes. Pour ajouter un bouton, modions la
page XAML ChoisirVille que nous avons construite dans le TP prcdent :
1 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12 ,0,12,0">
2 <Grid.RowDefinitions >
3 <RowDefinition Height="auto" />
4 <RowDefinition Height="*" />
5 </Grid.RowDefinitions >
6 <toolkit:ListPicker x:Name="Liste" ItemsSource="{Binding
ListeVilles}"
7 Header="Ville choisie :"
8 CacheMode="BitmapCache">
9 </toolkit:ListPicker >
10 <Button Grid.Row="1" VerticalAlignment="Bottom" Content="
Epingler" x:Name="BoutonEpingle" Tap="BoutonEpingle_Tap"
/>
11 </Grid >
Le clic sur le bouton ajoutera une tuile secondaire :
1 private void BoutonEpingle_Tap(object sender , System.Windows.
Input.GestureEventArgs e)
2 {
3 string ville = (string)IsolatedStorageSettings.
ApplicationSettings["DerniereVille"];
4 ShellTile tuileVille = ShellTile.ActiveTiles.FirstOrDefault
(elt => elt.NavigationUri.ToString ().Contains("ville=" +
ville));
5 if (tuileVille == null)
6 {
7 FlipTileData tuile = new FlipTileData
8 {
9 Title = "Mto " + ville ,
10 };
11
12 ShellTile.Create(new Uri("/MainPage.xaml?ville=" +
ville , UriKind.Relative), tuile , false);
13 BoutonEpingle.IsEnabled = false;
14 }
15 }
Bien sr, dans la query string, on indique le nom de la ville an de pouvoir lexploiter
535
CHAPITRE 36. TP : AMLIORER LAPPLICATION MTO AVEC
GOLOCALISATION ET TUILES
au dmarrage de lapplication. Dans lvnement permettant de choisir sa ville, on en
prote pour dsactiver les boutons des villes qui ont dj une tuile de raccourci :
1 private void Liste_SelectionChanged(object sender ,
SelectionChangedEventArgs e)
2 {
3 if (Liste.SelectedItem != null)
4 {
5 IsolatedStorageSettings.ApplicationSettings["
DerniereVille"] = (string)Liste.SelectedItem;
6 ShellTile tuileVille = ShellTile.ActiveTiles.
FirstOrDefault(elt => elt.NavigationUri.ToString ().
Contains("ville=" + (string)Liste.SelectedItem));
7 BoutonEpingle.IsEnabled = tuileVille == null;
8 }
9 }
Il ne reste plus qu exploiter linformation passe en query string au dmarrage de
lapplication an de charger la mto de la bonne ville. On peut le faire avec la mthode
OnNavigatedTo par exemple :
1 protected async override void OnNavigatedTo(System.Windows.
Navigation.NavigationEventArgs e)
2 {
3 string ville;
4 if (NavigationContext.QueryString.TryGetValue("ville", out
ville))
5 {
6 NavigationContext.QueryString.Remove("ville");
7 IsolatedStorageSettings.ApplicationSettings["
DerniereVille"] = ville;
8 }
9
10 if (IsolatedStorageSettings.ApplicationSettings.Contains("
DerniereVille"))
11 {
12 Information.Visibility = Visibility.Collapsed;
13 ChargementEnCours = true;
14 NomVille = (string)IsolatedStorageSettings.
ApplicationSettings["DerniereVille"];
15 WebClient client = new WebClient ();
16 try
17 {
18 ChargementEnCours = false;
19 string resultatMeteo = await client.
DownloadStringTaskAsync(new Uri(string.Format("
http :// free.worldweatheronline.com/feed/weather.
ashx?q={0}& format=json&num_of_days=5&key=
MA_CLE_API", NomVille.Replace(' ', '+')),
UriKind.Absolute));
20
536
ALLER PLUS LOIN
21 TraiteResultats(resultatMeteo);
22 }
23 catch (Exception)
24 {
25 MessageBox.Show("Impossible de rcuprer les
informations de mto, vrifiez votre connexion
internet");
26 }
27 }
28 else
29 Information.Visibility = Visibility.Visible;
30
31 base.OnNavigatedTo(e);
32 }
Remarquez quune fois que jai extrait lventuelle ville passe en paramtre
dans la query string, je la supprime an que lapplication ne soit pas bloque
sur cette ville.
Et le tour est jou. Voici une belle application mto qui exploite les infos de goloca-
lisation et qui nous permet mme davoir des raccourcis vers nos villes favorites. Pas
mal comme TP, non?
Aller plus loin
Vous aurez remarqu que lorsquon consulte la mto par rapport ses coordonnes
GPS, on ne dispose plus du nom de la ville. En gnral, ce nest pas trop grave
car nous savons o nous sommes . . . mais on pourrait amliorer notre application
pour acher le nom de la ville o nous nous trouvons, et pas les coordonnes GPS.
Il sut dutiliser le gocodage invers jen ai parl en introduction du TP
et il se trouve quil existe des services gratuits de gocodage invers. Prenons par
exemple celui de Google qui est assez facile utiliser : si vous naviguez sur le lien sui-
vant - http://maps.googleapis.com/maps/api/geocode/json?latlng=44.839073,
-0.579113&sensor=true vous pourrez obtenir du code JSON qui nous indique notam-
ment dans quelle ville nous nous trouvons. Il ny a plus qu modier notre code pour
faire lappel ce service web et nous pourrons obtenir la ville o nous sommes, ce qui
nous permettra dailleurs de la stocker dans le dossier local :
1 private async void Position_Click(object sender , EventArgs e)
2 {
3 ChargementEnCours = true;
4 WebClient client = new WebClient ();
5 string position;
6 try
7 {
8 Geoposition geoposition = await geolocator.
GetGeopositionAsync(TimeSpan.FromMinutes(5),
537
CHAPITRE 36. TP : AMLIORER LAPPLICATION MTO AVEC
GOLOCALISATION ET TUILES
TimeSpan.FromSeconds(10));
9 position = geoposition.Coordinate.Latitude.ToString(
NumberFormatInfo.InvariantInfo) + "," + geoposition.
Coordinate.Longitude.ToString(NumberFormatInfo.
InvariantInfo);
10 string resultatMeteo = await client.
DownloadStringTaskAsync(new Uri(string.Format("http
:// free.worldweatheronline.com/feed/weather.ashx?q={
0}& format=json&num_of_days=5&key=MA_CLE_API",
position , UriKind.Absolute)));
11 TraiteResultats(resultatMeteo);
12 }
13 catch (Exception)
14 {
15 MessageBox.Show("Vous devez activer le GPS pour pouvoir
utiliser cette fonctionnalit");
16 ChargementEnCours = false;
17 return;
18 }
19 try
20 {
21 string json = await client.DownloadStringTaskAsync(new
Uri(string.Format("http :// maps.googleapis.com/maps/
api/geocode/json?latlng ={0}& sensor=true", position),
UriKind.Absolute));
22
23 GeocodageInverse geocodageInverse = JsonConvert.
DeserializeObject <GeocodageInverse >(json);
24 if (geocodageInverse.status == "OK")
25 {
26 AddressComponent adresse = (from result in
geocodageInverse.results
27 from addressComponent
in result.
address_components
28 from type in
addressComponent.
types
29 where type == "locality
"
30 select addressComponent
).FirstOrDefault ();
31 if (adresse == null)
32 {
33 MessageBox.Show("Impossible de dterminer le g
ocodage invers");
34 ChargementEnCours = false;
35 }
36 else
37 {
538
ALLER PLUS LOIN
38 NomVille = adresse.long_name;
39 IsolatedStorageSettings.ApplicationSettings["
DerniereVille"] = adresse.long_name;
40 }
41 }
42 }
43 catch (Exception)
44 {
45 MessageBox.Show("Impossible de dterminer le gocodage
invers");
46 }
47 }
Vous commencez avoir lhabitude du langage JSON maintenant. Bien sr,
vous allez devoir gnrer les classes correspondantes mais faites attention, car
vous avez dj un objet RootObject qui a t gnr juste avant. . . Il faudra
donc le renommer.
Le rsultat est montr dans la gure 36.1.
Figure 36.1 Gocodage invers sur lapplication mto
Moi, je suis fan . . . et vous ?
539
CHAPITRE 36. TP : AMLIORER LAPPLICATION MTO AVEC
GOLOCALISATION ET TUILES
540
Chapitre 37
Une application uide = une
application propre !
Dicult :
La performance est un point crucial prendre en compte lors du dveloppement dapplica-
tions pour Windows Phone. Les ressources du tlphone sont beaucoup moins importantes
que nos PC de dveloppement. Aussi, il est important dy faire attention an de faire en
sorte que son application soit ractive et ne paraisse pas bloque. Vous devez bien sr
veiller ce que vos algorithmes soient un minimum optimiss et ne pas vous dire oh, ce
nest pas grave, le processeur du tlphone va moptimiser tout a. . . . De mme, vous
devez comprendre le mcanisme des threads pour pouvoir tirer le meilleur de votre Windows
Phone et obtenir lapplication la plus uide possible.
541
CHAPITRE 37. UNE APPLICATION FLUIDE = UNE APPLICATION PROPRE!
Un thread, cest quoi ?
On peut traduire Thread par l dexcution ou tche . Il sagit dun processus
qui peut excuter du code dans notre application, en loccurrence le thread principal
est celui que nous utilisons pour excuter notre code C#. Il y aussi le thread princi-
pal dinterface, que lon nomme UI Thread. Windows Phone possde un autre thread
en relai du principal, cest le thread de composition, appel Composition Thread (ou
Compositor Thread).
Dautres threads sont notre disposition, ce sont des threads qui tournent en arrire-
plan, de manire asynchrone. Nous nous en sommes dj servis sans le savoir en utilisant
la programmation asynchrone, par exemple lorsque nous tlchargeons des donnes avec
les classes WebClient ou HttpWebRequest. Ces oprations asynchrones se font sur un
thread secondaire.
Le thread dinterface
Le thread dinterface (UI Thread) va servir mettre jour linterface ; ce quon voit
lcran. En loccurrence, il va servir crer les objets depuis le XAML et dessiner
tous les contrles. Il gre galement toutes les interactions avec lutilisateur, notam-
ment tous les touchers. Il est donc trs important que ce thread soit le moins charg
possible an que lapplication reste ractive, notamment aux actions de lutilisateur. Si
ce thread contient une longue srie de codes excuter, alors linterface sera bloque
et lutilisateur ne pourra plus rien faire, ce qui est fortement dplaisant et risque de le
faire trs vite dsinstaller votre application. . . Essayez plutt de rpartir les tches, en
imaginant que vous avez deux boutons dans votre page : lun qui fait une action longue
et lautre qui ache simplement un message dans une bote. Voici le code de la bote
contenant les deux boutons :
1 <StackPanel >
2 <Button Content="Lancer le calcul" Tap="Button_Tap" />
3 <Button Content="Cliquez -moi" Tap="Button_Tap_1" />
4 </StackPanel >
Voici le code-behind des deux boutons :
1 private void Button_Tap(object sender , RoutedEventArgs e)
2 {
3 List <int > nombrePremiers = new List <int >();
4 for (int i = 0; i < 2000000; i++)
5 {
6 if (EstNombrePremier(i))
7 nombrePremiers.Add(i);
8 }
9 }
10
11 private void Button_Tap_1(object sender , RoutedEventArgs e)
12 {
542
LE THREAD DINTERFACE
13 MessageBox.Show("Clic");
14 }
15
16 private bool EstNombrePremier(int nombre)
17 {
18 if (( nombre % 2) == 0)
19 return nombre == 2;
20 int racine = (int)Math.Sqrt(nombre);
21 for (int i = 3; i <= racine; i+=2)
22 {
23 if (nombre % i == 0)
24 return false;
25 }
26 return nombre != 1;
27 }
Le premier bouton permettra de dterminer les nombres premiers de 0 jusqu 2000000,
le deuxime achera un simple message, dans une bote de dialogue. Si vous dmar-
rez lapplication et cliquez sur le premier bouton, vous ne pourrez pas cliquer sur le
deuxime bouton tant que le premier calcul nest pas termin. De plus, on voit ltat
du bouton que celui-ci reste cliqu tant que le traitement long nest pas termin. Nous
avons donc bloqu le thread UI en eectuant un calcul trop long. De ce fait, lappli-
cation nest plus capable de traiter correctement les entres utilisateurs, comme le clic
sur le deuxime bouton, tant donn que le thread UI est surcharg par le long calcul.
An que le code soit plus court, nous allons remplacer le long calcul par une mise
en veille du thread courant grce la mthode Thread.Sleep(), que nous retrouverons
dans lespace de noms :
1 using System.Threading;
Ceci nous permet de simuler un traitement long tout en conomisant des lignes de
codes, do le code-behind devient :
1 private void Button_Tap(object sender , RoutedEventArgs e)
2 {
3 Thread.Sleep(TimeSpan.FromSeconds(4));
4 }
5
6 private void Button_Tap_1(object sender , RoutedEventArgs e)
7 {
8 MessageBox.Show("Clic");
9 }
Ceci me permet de simuler un traitement qui dure 4 secondes.
Ok, cest bien beau, mais notre interface semble toujours bloque et incapable de traiter
le clic sur le deuxime bouton.
543
CHAPITRE 37. UNE APPLICATION FLUIDE = UNE APPLICATION PROPRE!
Utiliser un thread darrire-plan
Une solution pour rsoudre ce problme serait dutiliser un thread darrire-plan. Ce ne
sera donc plus le thread UI qui va grer le calcul mais un thread qui tourne en arrire-
plan. Cest un peu le mme principe quavec une opration asynchrone, comme lorsque
nous eectuions un tlchargement, notre code qui sexcute utilisera une partie de la
mmoire pour fonctionner de manire plus ou moins parallle au thread UI, ce qui lui
permettra de continuer pouvoir traiter les actions de lutilisateur. On pourra utiliser
pour cela la classe Thread - http://msdn.microsoft.com/fr-fr/library/system.
threading.thread(v=vs.95).aspx. Il sut dinclure une mthode dans le thread (ici
je passe une expression lambda, qui le met en pause pendant 4 secondes), dappeler
la mthode Start, et Windows Phone soccupera dexcuter notre mthode dans un
thread darrire-plan. Cela donnera :
1 public partial class MainPage : PhoneApplicationPage
2 {
3 public MainPage ()
4 {
5 InitializeComponent ();
6 }
7
8 private void Button_Tap(object sender , RoutedEventArgs e)
9 {
10 Thread thread = new Thread (() => Thread.Sleep(TimeSpan.
FromSeconds(4)));
11 thread.Start();
12 }
13
14 private void Button_Tap_1(object sender , RoutedEventArgs e)
15 {
16 MessageBox.Show("Clic");
17 }
18 }
Note : Cette faon de crer des threads nest pas la plus optimale, nous
verrons dautres solutions pour crer des threads.
Maintenant, si vous dmarrez votre application, vous pourrez voir que lexcution du
code long ne bloque plus le traitement du clic sur lautre bouton. joie, merci les
threads ! En fait, notre code est un peu bte ! On fait des calculs mais ils ne nous
servent rien ici . . . Je suis sr que, comme moi, vous seriez trs curieux de connatre
le plus grand nombre premier infrieur 10 millions, nest-ce pas ? Ok, ressortons notre
mthode, utilisons notre thread et achons le rsultat dans un TextBlock :
1 <StackPanel >
2 <Button Content="Lancer le calcul" Tap="Button_Tap" />
3 <Button Content="Cliquez -moi" Tap="Button_Tap_1" />
544
UTILISER UN THREAD DARRIRE-PLAN
4 <TextBlock x:Name="Resultat" />
5 </StackPanel >
Le calcul sera fait ainsi :
1 private void Button_Tap(object sender , RoutedEventArgs e)
2 {
3 Thread thread = new Thread (() =>
4 {
5 int max = 0;
6 for (int i = 0; i < 10000000; i++)
7 {
8 if (EstNombrePremier(i))
9 max = i;
10 }
11 Resultat.Text = "Rsultat : " + max;
12 });
13 thread.Start();
14 }
Sauf que, si vous dmarrez lapplication, que vous lancez le calcul, votre application
va se mettre planter avec une belle erreur du nom de UnauthorizedAccessException
(que lon peut apercevoir dans la gure 37.1).
Figure 37.1 Leve dexception lors de laccs au TextBlock
Pourquoi cette erreur ?
Pour une simple et bonne raison et je crois quon peut la mettre en avertissement :
Seul le thread UI a le droit de mettre jour linterface. Si nous tentons de
mettre jour un lment de linterface depuis un autre thread, comme un
thread darrire-plan, nous aurons une erreur.
545
CHAPITRE 37. UNE APPLICATION FLUIDE = UNE APPLICATION PROPRE!
Utiliser le Dispatcher
Nous avons dj rapidement vu comment