Mon incompétence en terme d’IHM étant assez importante,
j’ai suivi récemment une formation sur les outils de modélisation WPF, et je
dois dire que cela m’a assez bien réconcilié avec le monde de l’interface
graphique.
Cela a surtout démystifié pas mal d'aprioris que j’avais sur
le sujet, et il est vrai que Microsoft a fait de très gros efforts pour
permettre à tout un chacun de créer de jolies interfaces, même pour les
amoureux des programmes en mode console comme moi.
Avec cet article, je vais tenter de vous montrer comment on
peut facilement faire un contrôle graphique en partant d’une page blanche, et
ce sans aucune compétence particulière en graphisme.
Introduction
Pour commencer, voici l’environnement de base que nous
allons utiliser :
- Visual Studio 2012
- Microsoft .NET 4.0
- Langage C#
-
Blend for Visual studio (normalement installé en
même temps que VS 2012)
Le composant graphique que nous allons réaliser sera une horloge
à aiguille avec les spécificités suivantes :
- Les aiguilles se placent aux bons endroits en fonction d’un TimeSpan passé en propriété
- Un bouton permet de changer le cadran de l’horloge via un panel de choix qui s’ouvrira avec une petite animation.
Voici à quoi cela ressemblera lorsque ce sera terminé :
Ceux d’entre vous qui font du Winform et qui ne connaissent
pas WPF peuvent trouver ça irréalisable, surtout en partant de zéro !
Ne vous inquiétez pas, une fois que vous aurez lu cet
article, vous ne voudrez plus faire vos IHM autrement qu’avec du WPF tant la
manipulation graphique est simple, et donne en peu de temps des résultats
bluffants !
Au travail
Nous allons commencer par ouvrir Visual studio et créer un
nouveau projet en .NET 4.0 de type « WPF User Control Library » que
nous allons appeler « MaLibrairie »
Une fois le projet créé, vous arrivez dans Visual studio à quelque chose qui doit ressembler à ceci :
Cliquez sur « UserControl1.xaml » et renommez le fichier
en « MonHorloge.xaml »
Si Visual ne vous a pas fait de refactor automatique,
n’oubliez pas de renommer aussi le « UserControl1 » dans
« MonHorloge.xaml » ainsi que dans « MonHorloge.xaml.cs »
Voilà, une fois ces détails réalisés et enregistrés, nous
allons pouvoir commencer le « design » de notre contrôle d’horloge.
Pour cela, ouvrez l’application « Blend » qui se trouve
dans Démarrer à
Tous les programmes à
Microsoft Visual Studio 2012 à
Blend for Visual Studio 2012
Dans la fenêtre d’accueil, cliquez sur « Open Project »
Allez chercher votre solution puis cliquez sur
« Ouvrir »
Vous allez vous retrouver dans un logiciel qui ressemble
plus à photoshop qu’a un IDE.
Bienvenue dans la partie visible de l’IceBerg :)
Vue d’ensemble de Blend
Ok, faisons un peu le tour du propriétaire :
Pour que nous soyons dans la même configuration, je vous
conseille de cliquer dans le menu « Window » à « Workspace » à
« Animation »
A votre droite vous avez 4 onglets : « Properties,
Projets, Ressources et Data ». Les onglets qui vont le plus nous
intéresser sont les deux premiers. L’onglet « properties » va
permettre de manipuler les propriétés graphiques des éléments que nous allons
ajouter dans notre composant, et l’onglet « Project » est
l’équivalent de l’explorateur de solution sous visual studio
Au centre, vous serez face au designer de votre contrôle graphique. Celui-ci est vide et vous regarde d’un air menaçant, mais vous
verrez qu’il est très sympa pour peu qu’on apprenne à le connaitre.
C’est ici que nous allons ajouter, manipuler et agencer des formes et des images pour que notre
contrôle ressemble à quelque chose.
En bas, plusieurs onglets avec des noms obscures tels que
« Assets, Triggers, States, Parts et Objects and Timeline » sont
présents.
Tous ces outils permettent de créer des animations. Nous
verrons comment les utiliser lorsque nous traiterons de la palette de
configuration de notre horloge.
Sur la gauche, vous avez une palette d’outils un peu comme
ce qui vous est proposée dans visual studio pour le design.
Nous utiliserons cette palette pour ajouter des composants à
notre layout de design au centre.
Commencement
Alors, par quoi commencer pour faire notre horloge ?
Dans un premier temps, nous allons mettre en place le cadran.
Pour cela rien de plus simple, allez sur « google image » puis faites
quelques recherches pour trouver votre bonheur.
Choisissons un cadran avec une taille qui soit la même aussi
bien en largeur qu’en hauteur. Celui en gris me parait très bien.
Tout d’abord, téléchargez l’image sur votre disque
Une fois l’image téléchargée, allez dans l’onglet
« Projects » de blend, puis créez un dossier appelé
« Cadrans » à votre projet.
Renommez l’image que vous avez téléchargée en
« cadran1.jpg » puis glissez-la de votre disque au dossier que vous
venez de créer dans blend.
Allez dans la barre d’outils située à gauche, puis cliquez
sur le bouton « Assets » représenté par deux petites flèches sur la
droite, puis tapez « Image » dans le panel de recherche qui apparait.
Faite glisser le composant Image dans le designer situé au
centre de l’application.
Pour que le composant image prenne toute la place, cliquez
sur l’onglet « Properties » situé à droite.
Cliquez ensuite sur le carré blanc des propriétés « Width »,
« height » et « Margin » puis sélectionnez
« Reset »
Sélectionnez aussi l’option « Stretch » pour
« HorizontalAlignement » et « VerticalAlignement »
Nous allons maintenant assigner notre image de cadran au
composant, pour ce faire, allez dans la propriété « Source » puis
sélectionnez « Cadran1.jpg »
Voila ! Notre cadran d’horloge est opérationnel !
Passons maintenant à la deuxième partie, celle de la
disposition des aiguilles.
Pour faire simple, nous allons utiliser des rectangles que
nous allons paramétrer pour être en mesure de tourner autour du point central.
Let’s do it :
Cliquez une nouvelle fois sur le bouton « Assets »
de votre barre d’outils puis tapez le mot « Rectangle » dans le champ
de recherche.
Prenez le composant « Rectangle » et glissez-le
dans la zone de dessin.
Ajustez-le à l’aide de votre souris pour que celui-ci soit
disposé comme une aiguille sur le cadran pointant vers midi.
Dans l’onglet « properties », assignez une couleur
rouge à ce rectangle
Maintenant, voici la partie magique. Nous allons paramétrer
le rectangle pour que celui-ci puisse tourner autour de l’axe central du
cadran.
Pour que vous vous rendiez bien compte du délire, ouvrez la
partie « Transform » dans l’onglet des propriétés de votre rectangle,
puis choisissez le sous onglet « Rotate » représenté par une flèche
qui fait un demi-cercle sur la gauche.
Dans cet onglet, vous allez trouver une propriété
« angle ».
Si vous vous amusez à faire varier sa valeur, vous
remarquerez que le rectangle tourne sur lui-même, l’axe de rotation étant en
son centre.
Notre but est donc de changer le point de rotation pour que
notre rectangle ne tourne plus en fonction de son centre, mais en fonction de
sa base.
Remettez la propriété « Angle » à 0, puis cliquez
sur l’onglet « Center Point »
Les propriétés X et Y représentent les coordonnées du point
de rotation. Celles-ci sont sous forme de ratio (valeur décimale entre 0 et 1)
le point 0,0 étant en haut à gauche de la forme et le point 1,1 en bas à
droite.
Ainsi, si je veux que mon point de rotation se fasse au
centre de la base de mon rectangle, X doit avoir la valeur 0.5 et Y la valeur
1.
Pour le vérifier, remettez-vous sur l’onglet
« Rotate » et jouez une nouvelle fois avec la propriété
« Angle ». Normalement vous verrez votre rectangle tourner autour du
centre du cadran comme une aiguille.
Cool n’est-ce pas ?
En considérant que nous venons de faire l’aiguille des
minutes, faite de même pour l’aiguille des heures et des secondes. Nous dirons
que l’aiguille des heures sera de couleur verte, et l’aiguille des secondes de
couleur bleu.
Allez-y, je vous attends…
Voilà, au bout de quelques minutes, vous devriez avoir ce
résultat (en partant du principe que tous vos angles ont des valeurs
différentes :
Maintenant que toutes nos aiguilles sont placées sur notre
cadran, et qu’elles sont capables de tourner correctement, nous allons créer
une propriété à notre contrôle afin de placer les aiguilles par code en fonction
d’un TimeSpan.
Pour ce faire, nous allons devoir jouer sur les propriétés
« Angle » de chacune de nos aiguilles, il est donc important de les
nommer pour pouvoir les manipuler plus tard.
Sélectionnez par exemple l’aiguille rouge, puis retournez
dans l’onglet « Rotate » de la fenêtre des propriétés.
Cliquez sur le petit carré blanc situé à droite de
« Angle », et choisissez le menu « Go to source »
Le code Xaml lié à notre rectangle s’affiche dans Blend avec
la propriété « Angle » sélectionnée.
Pour manipuler celle-ci depuis l’extérieur il existe
plusieurs possibilités.
L’une d’entre elle consiste à faire du « data binding », c’est-à-dire de la liaison de données. C’est un mécanisme très puissant qui permet de découpler les données de l’IHM afin de pouvoir faire du code testable.
Dans notre cas, le code que nous voulons ajouter n’est pas
du code métier qu’il est nécessaire de tester, mais purement et simplement du
code de manipulation graphique, c’est pourquoi nous opterons pour du code
« Behind », c’est-à-dire embarqué à notre contrôle.
Pour faciliter la manipulation de la propriété
« Angle » par le code behind, nous allons la nommer afin de pouvoir y
accéder plus facilement.
Rajoutez dans le code xaml un attribut nommé
« x :name » auquel nous donnerons le nom
« AngleMinutes »
Nous ferons exactement la même chose avec
« AngleSecondes » et « AngleHeures »
Nous allons maintenant passer à la partie programmation,
celle que vous préférez.
Pour cela, retournons dans Visual Studio que nous avons laissé
ouvert en arrière-plan. (N’oubliez pas au préalable de bien tout sauvegarder
dans blend)
Normalement, une boite de dialogue d’avertissement doit
apparaître dans VS.
Cliquez sur le bouton « Reload All »
Le designer de Visual Studio vous montre le contrôle que nous
venons de créer dans « Blend », il s’agit maintenant de créer la
propriété qui va bien pour que notre horloge soit contrôlable depuis
l’extérieur.
Pour cela, WPF nous impose de créer une
« DependencyProperty ».
Ouvrez « MonHorloge.xaml.cs » puis tapez
« propdp » + tabulation.
Un snippet de visual studio vous génère un bout de code un
peu obscure tel que :
Première étape : on modifie le code pour proposer un
TimeSpan du nom « Time »
Deuxième étape : lorsque le programmeur assignera cette
propriété, nous voulons pouvoir définir la valeur des angles de nos aiguilles.
Pour cela, le 4ème paramètre de notre fonction
« Register » permet d’ajouter une CallBack à son constructeur qui
sera appelée lorsque la DépendencyProperty sera définie. C’est exactement ce que
nous voulons :)
Voici comment faire :
public static readonly DependencyProperty TimeProperty = DependencyProperty.Register("Time", typeof (TimeSpan), typeof (MonHorloge), new PropertyMetadata(default(TimeSpan), PropertyChangedCallback)); private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { throw new NotImplementedException(); }
Il ne reste plus qu’à taper le code qui va bien dans la
Callback.
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { var component = dependencyObject as MonHorloge; var timeSpan = (TimeSpan)dependencyPropertyChangedEventArgs.NewValue; if (component != null && timeSpan != null) { component.AngleHeures.Angle = (timeSpan.TotalMinutes/60/12)*360; component.AngleMinutes.Angle = (timeSpan.TotalMinutes%60)/60*360; component.AngleSecondes.Angle = (360/60)*timeSpan.Seconds; } }
A partir de là, nous avons déjà une première version
d’horloge fonctionnelle !
Teste de la première version de notre contrôle
Pour la tester, créer un nouveau projet d’application WPF.
Ajouter « MaLibrairie » dans ses références :
Compilez le projet, puis allez dans la
« Toolbox ».
Le contrôle « MonHorloge » Apparait en haut de la
barre d’outils !
Prenez le contrôle et glissez le dans le designer de votre
fenêtre principale
Notre horloge apparait !
Par contre, un petit détail risque de vous chiffonner.
Si vous redimensionnez la taille de l’horloge, les aguilles
ne se trouvent plus au centre du cadran.
Ceci est dû au fait que nous avons dessiné notre composant
dans une grille qui travaille avec des positions relatives. Pour régler ce
problème, il suffit de remplacer notre grille par un « Canvas » afin
que nos aiguilles travaillent avec des positions absolues.
Pour cela, ouvrez l’horloge dans VisualStudio, puis
remplacez les tags <Grid></Grid> par <Canvas></Canvas>
dans le code xaml
Enregistrez et recompilez.
Lorsque vous retournerez dans le designer de votre projet de
test, tout rentrera dans l’ordre.
Maintenant que ce petit détail est réglé, vous aimeriez voir
les aiguilles tourner, non ?
Rien de plus simple !
Commencez par donner un nom à cette horloge, par exemple
« HorlogeFr » en utilisant la fenêtre de propriétés de Visual studio.
Ouvrez ensuite « MainWindows.cs », puis créez un
DispatcherTimer pour définir l’heure toute les secondes.
public partial class MainWindow : Window { readonly DispatcherTimer _timer = new DispatcherTimer(); public MainWindow() { InitializeComponent(); SetHorlogeFr(); _timer.Interval = new TimeSpan(0,0,1); _timer.IsEnabled = true; _timer.Tick += timer_Tick; } void timer_Tick(object sender, EventArgs e) { SetHorlogeFr(); } private void SetHorlogeFr() { HorlogeFr.Time = DateTime.Now.TimeOfDay; } }
Comme vous pouvez le voir, à chaque seconde, nous assignons
à la DependencyProperty « Timer » de notre contrôle horloge l’heure
qu’il est afin que la position des aiguilles se recalcule.
Il ne vous reste plus qu’à démarrer votre projet de test
pour constater le résultat.
Alors ? Pas mal pour des mecs qui ne font que du mode
console :)
A ce stade, on a déjà un truc bien, mais pour explorer
encore un peu plus WPF, nous allons rajouter la possibilité de changer le
cadran d’horloge à la volée, le tout en passant par un petit panel de
configuration animé.
Panneau de configuration du cadran
Donc, pour commencer, nous allons retourner sous Blend, qui
soit dit en passant tournait en fond de tâche.
Blend a détecté que le projet a été modifié depuis la
dernière fois. Normal, car nous avons changé la grille en canvas.
Cliquez sur le bouton « Yes to all » pour accepter tous les changements.
Cliquez sur le bouton « Yes to all » pour accepter tous les changements.
Je rappelle que notre but est de pouvoir changer le cadran
de l’horloge à la volée. La première chose à faire consiste donc à trouver
d’autres cadrans, et à les dimensionner selon la taille du cadran originale.
Partons sur google Image à la recherches de quelques cadrans
supplémentaires :
Je vais prendre par exemple le cadran avec un cheval ailé.
Je vois que ses dimensions sont en 1616x1616 alors que le
cadran original était en 500x500.
Le problème c’est que je ne sais pas à quoi correspondent
ces dimensions.
Je vais vous montrer comment nous allons régler le problème
très simplement avec Blend et MSPaint.
En premier lieu, j’enregistre cette image sur mon disque
dur, puis je la glisse dans le répertoire « Cadrans » de ma solution
Je renomme l’image en cadran2.jpg, puis je fais un
clique-droit à
« Edit externally » sur cadran1.jpg
Celui-ci s’ouvre dans Paint
Cliquez
sur « Image » puis « Redimentionner », une fenêtre
s’affiche.
Choisissez
le bouton radio « Pixels »
Nous voyons que notre image de référence fait 225x225
pixels. Voici donc la taille dans laquelle la nouvelle image doit être
redéfinie.
Pour cela, on referme Paint, puis on retourne sous Blend
pour faire un clic droit à
« Edit externally » sur cadran2.jpg
On refait « Image » puis « Redimentionner » à bouton radio « Pixels », et on entre la valeur 225 dans
« Horizontal ». La valeur « Vertical » se met
automatiquement à 225 elle aussi.
Cliquez
sur OK
Il ne
reste plus qu’a enregistrer l’image redimentionnée, et à refermer Paint.
Touvez
deux ou trois autres cadrans sur google, et mettez les à la bonne taille en
utilisant cette méthode.
Ajout de la liste
Une fois ceci fait, nous allons passer à l’incrustation
d’une liste et d’un bouton dans notre contrôle, autant vous dire qu’on va devoir
manipuler un peu le designer et le code xaml généré pour arriver à nos fins.
Donc, voici comment se présente votre composant dans Blend
Nous allons créer une grille avec deux colonnes.
La première contiendra le canvas qui contient notre horloge,
et la deuxième notre liste de choix.
Dans l’onglet « Object and Timeline », faites un
clic droit sur « canevas » puis choisissez « Group into à Grid »
Sélectionnez ensuite « UserControl » pour activer
les outils de manipulation dans le designer.
Dans le designer, sélectionnez le carré sur le côté droit,
puis étirez jusqu’à avoir un espace suffisant pour ajouter une grille.
Dans l’onglet « Object and Timeline »,
sélectionnez « Grid » pour activer les outils de manipulations dans
le designer, puis ajouter une nouvelle colonne à votre grille en cliquant sur
le bord supérieur droit de l’horloge.
Allez ensuite dans la barre d’outils, et choisissez un
composant de type « ListBox »
Faite glisser la « ListBox » dans la deuxième
colonne de votre grille
Nous allons maintenant aller changer quelques petites
propriétés directement en xaml.
Cliquez sur le petit bouton « code » situé dans la
barre du coin supérieur droit du designer.
Un éditeur xaml va apparaitre, le code doit ressembler à peu
près à ceci :
Nous allons changer ce code pour que :
-
Le canvas soit sur la première colonne, et ne
déborde pas sur la deuxième
-
Le ListeBox soit sur la deuxième colonne, et ne
déborde pas sur la première
-
La deuxième colonne de la grille soit en taille
automatique pour s’adapter à la taille du listBox
Tout cela pourrait se faire avec les propriétés de design,
mais c’est beaucoup plus rapide de passer directement par le xaml.
D’ailleurs, une fois que vous serez familiarisé avec Blend,
vous remarquerez que beaucoup de choses peuvent directement être faite en xaml,
ce qui fait gagner pas mal de temps.
En premier lieu, voici les modifications à apporter au
niveau des définitions de colonnes :
Descendez tout en bas, et supprimez tous les attributs du
nœud « ListBox » à l’exception de
« Grid.Column= »1 » »
Voilà pour cette partie.
En retournant dans le designer, votre composant doit
ressembler à ceci.
Template et Animation
Alors, maintenant nous allons commencer à entrer dans le
dur, là ou WPF apporte pas mal d’avantages par rapport à du Winform standard.
Si je vous dis que dans notre ListBox, je veux afficher
chaque candran sous forme d’un libellé, que me répondez-vous ?
Facile !
Ok, maintenant si je vous dis que le libellé doit avoir une
police un peu stylé ?
Jouable !
Très bien, et si je vous dis que je veux un aperçu de
l’image à gauche de chaque libellé qui soit assez gros pour voir quelque
chose ?
Ça se complique !
Et si en plus je veux qu’au survol de la souris, l’image
s’agrandisse pour avoir un meilleur aperçu ?
Oula ! On n’est
pas chez Apple ici !
Grace à WPF, vous pouvez prendre n’importe quel contrôle de
base et le redessiner comme bon vous semble grâce aux templates ! C’est ça
qui est magique !
Mais comment faire ?
Faites un clic droit sur l’objet « ListBox » dans
l’onglet « Object and Timeline », et choisissez le menu « Edit
Additional Templates à
Edit generated Items (ItemTemplate ) » à «Create Empty»
Une boite de dialogue s’ouvre.
Choisissez dans la ComboBox de « This document »
le choix « ListBox » car seul ce contrôle se verra appliquer le
template (pas besoin de partager le template à tous les composants du contrôle)
En cliquant sur « OK », le designer ne montre plus le contrôle de l’horloge, mais affiche a quoi va ressembler graphiquement le Template
Donc là, pour ceux qui n’auraient pas compris, Blend nous
donne la possibilité de dessiner à quoi va ressembler chaque item de notre
ListBox !
Il suffit donc de concaténer
une image avec un TextBox, et le tour est joué !
Dans « Object and Timeline », faites un clic droit
sur « Grid » et choisissez « Change Layout Type à Stackpanel». Cela
permettra d’avoir quelque chose de plus rigide pour construire notre item
Augmentez le zoom de votre designer pour pouvoir insérer des
composants au stackpanel
Allez chercher dans la barre d’outils une image et glissez
la dans le stackpanel.
Glissez-y ensuite un TextBlock.
Votre template va ressembler à quelque chose comme ça :
Nous voulons que le texte soit à droite de l’image, nous
sélectionnerons donc le stackpanel dans « Objects and Timeline » puis
nous irons dans la fenêtre des propriétés dans la partie « Layout »
changer la propriété « Orientation » de « Vertical » à
« Horizontal »
Voici l’impact sur le designer
Comme vous pouvez le constater, le texte n’est pas centré.
Nous allons donc nous en occuper.
Cliquez sur le TextBlock puis ouvrez l’onglet
« Properties ». Dans la partie « Layout » choisissez
« Left » pour « HorizontalAlignement » et
« Center » pour « VerticalAlignement »
Le TextBlock dans le designer devient tout de suite beaucoup
mieux :
Pour avoir une meilleure vision de à quoi cela va
ressembler, cliquez sur le composant « Image » puis dans les
« Properties », choisissez un cadran dans la combobox proposée par la
propriété « Source » de la partie « Common »
Ceci permet de bien prendre conscience du rendu final.
Attention, cette affectation est temporaire, vous devrez la
remplacer par un data binding lorsque les manipulations seront terminées.
Bien. Jusque-là les choses se sont assez bien passées.
Mais maintenant, comment faire pour que l’image s’agrandisse
lors d’un survol de la souris ?
Une fois de plus, le moteur WPF va nous sauver la vie en
nous permettant de mettre en place ce genre d’effet sans taper une ligne de
code.
Tout d’abord, commençons par mettre l’image du cadran à une
taille raisonnable, disons 50x50.
Cliquez sur l’image et changez les propriétés With et Height
Très bien.
Maintenant, nous voulons que lorsque l’utilisateur passe sa
souris au-dessus de l’image, celle-ci s’agrandit, et lorsqu’il sort le curseur
de l’image, celle-ci reprend son état initial. Facile :)
Pour faire cela avec WPF, nous allons mapper des
« StoryBoard » aux événements « OnMouseEnter » et
« OnMouseLeave » de notre image.
Mais c’est quoi un storyboard ?
Pour faire simple, c’est une ressource éditable qui se
présente sous la forme d’une ligne de temps, un peu comme dans les logiciels de
montage vidéo.
Cette ligne de temps permet de spécifier à WPF des propriétés qui doivent changer dans le temps. Et là où c’est bien fait, c’est que WPF s’occupe de la transition graphique à votre place.
Cette ligne de temps permet de spécifier à WPF des propriétés qui doivent changer dans le temps. Et là où c’est bien fait, c’est que WPF s’occupe de la transition graphique à votre place.
Ici par exemple, nous allons créer un storyboard pour que la
taille de l’image passe de 50x50 à 150x150 en 200ms. Il nous suffira simplement
de créer une image clé dans laquelle notre composant possède les nouvelles
dimensions, et WPF s’occupe de tout pour nous !!
Allez zou, je vous montre comment faire.
Dans les onglets situés en bas de Blend, cliquez sur
l’onglet Triggers. Et sélectionnez dans l’onglet « Objects and
Timeline » le composant « image »
Cliquez sur le bouton « + Event » pour créer un
nouvel évènement à mapper à un storyboard.
Dans les listes déroulantes situées à côté de
« When », changez « target-element » par
« image » et changez « Loaded » par
« MouseEnter »
Cliquez sur le bouton « + » situé à droit des
listes déroulantes.
Normalement ce message apparait :
Cliquez sur « OK » pour créer un storyboard qui
sera lié avec cet évènement
Nous venons ici de créer un storyboard du nom de
« OnMouseEnter1 », celui-ci possède un petit rond rouge sur sa gauche
ce qui signifie qu’il est en cours d’enregistrement. D’ailleurs, vous remarquez
aussi que le designer est entouré d’un cadre rouge avec une petite annotation
en haut.
A ce stade, nous allons définir le comportement graphique
qui va-t-être joué lorsque la souris va passer au-dessus de notre image.
Cliquez sur le composant « image » dans
« Objects and timeline » puis déplacez le curseur de votre ligne de
temps à 0:00.200
Allez dans les propriétés de votre image, et changez le
« Width » et le « height » pour qu’ils soient tous les deux
à 150
Vous remarquez dans la ligne de temps qu’une image clé est
apparue.
Et aussi que l’image dans le designer est plus grosse.
Pour voir l’effet que cela va donner, cliquez sur le bouton
« Play » de la ligne de temps de votre storyboard.
Normalement, vous voyez dans le designer l’image passez de
50x50 à 150x150.
Cool non ?
Faisons maintenant l’inverse, c’est-à-dire que lorsque je
vais retirer ma souris de l’image, celle-ci va se rétracter.
Ajoutez un nouvel évènement en cliquant sur le
bouton « +Event »
Dans les listes déroulantes situées à côté de
« When », changez « target-element » par
« image » et changez « Loaded » par
« MouseLeave »
Si vous ne voyez pas « Image » dans les choix de
la liste de « target-element », prenez garde à bien avoir cliqué sur
« image » dans « Objects and Timeline »
Je vais vous montrer comment gagner un peu de temps en
évitant de récréer complétement un storyboard.
Il suffit de dire à blend de dupliquer notre premier
storyboard, puis de l’inverser :)
Dans « Objects and Timeline », cliquez sur le
petit menu déroulant à la droite du « + » situé au niveau du nom du
storyboard puis cliquez sur « Duplicate »
Renommez le nouveau storyboard de
« OnMouseEnter_Copy1 » en « OnMouseLeave 1»
Déroulez une nouvelle fois le petit menu et choisissez « Reverse »
Il ne vous reste plus qu’à assigner ce nouveau storyboard à
votre évènement « MouseLeave » :)
Cliquez sur le « + » situé à droite de votre
événement.
Puis choisissez-le storyboard « OnMouseLeave1 »
Et voilà ! Vous venez en quelques clics de créer une
petite animation sympa sans effort !
Bon, pourquoi ne pas continuer sur notre lancée et
maintenant faire l’ouverture de la liste de paramétrage de cadran ?
Sortez du designer de template en cliquant sur
« MaListe »
Bouton de paramétrage
Nous allons ajouter un bouton dans le coin supérieur droit
de l’horloge qui nous permettra d’ouvrir la liste à droite afin de choisir un
cadran approprié.
Dans votre barre d’outils, recherchez un contrôle de
type « Button »
Glissez le bouton dans le coin supérieur droit de l’horloge
Vous conviendrez que ce bouton n’est pas très sexy.
Ce que nous voulons, c’est un petit bouton assez discret
contenant une image représentative.
Pour trouver notre image, allons sur www.iconfinder.com à la recherche d’une icône
gratuite pour notre bouton.
Celle du milieu semble bien. Je clique dessus afin de la
télécharger au format 16x16
Une fois celle-ci enregistrée sur mon disque, je la renomme
« param_button.png » puis je la glisse directement dans mon projet
Blend.
Passons au paramétrage du bouton.
Cliquez dessus dans le designer et allez dans la fenêtre des
propriétés.
Effacez en premier lieu le contenu de la propriété
« Content », puis définissez le « Width » et le
« Height » à 16
Pour définir l’image du bouton, allez dans la partie
« Brush » puis cliquez sur « Background ».
Choisissez le bouton onglet « Tile brush » puis
mettez en « imageSource » notre « param_button.png »
téléchargée précédemment.
Définissez aussi le « Stretch » à
« None »
Il ne vous reste plus qu’à placer le bouton en haut à droite
du composant horloge
Maintenant, nous allons définir ce qui doit se passer lors d’un
clique sur ce bouton.
Pour rappel, nous voulons que la liste située à droite de
l’horloge s’étende vers la droite pour pouvoir sélectionner un cadran. Nous
allons donc mapper un storyboard qui fait cette action à l’évènement
« Click » de notre bouton.
C’est parti !
Cliquez sur le bouton « + Event » de l’onglet
« Triggers »
Après avoir bien vérifié que l’élément « Button »
est sélectionné dans « Object and Timeline », choisissez dans les
listes déroulantes à côté de When « Button » et « Click »,
puis cliquez sur le bouton «+ »
Un message proposant de créer un nouveau storyboard
apparait. Cliquez sur OK.
Un storyboard « OnClick1 » a été créé.
Sélectionnez le composant « MaListe » dans
« Object and Timeline », puis déplacez le curseur de l’image clé sur
0 :00.300
Dans la fenêtre « Properties » de
« MaListe », essayez de changer la valeur de la propriété
« Width »
Si la valeur est paramétrée en « Auto » comme dans
la capture d’écran, un message d’erreur apparait vous expliquant qu’il n’est
pas possible d’animer une propriété qui possède une valeur auto-calculée.
Dans ce cas, il faut fermer le storyboard et appliquer une
valeur fixe à la propriété « Width » de votre liste.
Une fois la propriété défini, re-sélectionnez le storyboard
« OnClick1 » dans « Object and Timeline »
Sélectionnez le composant « MaListe » dans
« Object and Timeline », puis déplacez le curseur de l’image clé sur
0 :00.300
Dans la fenêtre « Properties » de
« MaListe », changez la valeur de la propriété « Width ».
Normalement, vous n’avez plus le message d’erreur vu
précédemment.
Une image clé vient d’apparaitre dans le storyboard.
Vous pouvez maintenant cliquer sur le bouton
« play » pour visualiser l’animation.
Voilà, nous venons de faire en sorte que la liste se déploie
sur la droite lorsque l’on clique sur le bouton.
Nous allons maintenant mettre en œuvre le mécanisme de rétractation de la liste qui se produira lorsque la souris sortira de celle-ci.
Nous allons maintenant mettre en œuvre le mécanisme de rétractation de la liste qui se produira lorsque la souris sortira de celle-ci.
Nous allons ajouter un évènement dans les triggers en
cliquant sur le bouton « +Event »
Après avoir pris soins de sélectionner « MaListe »
dans « Objects and Timeline », on déroule les listes de choix à coté
de « When » pour définir l’événement « MouseLeave » de
« Maliste »
Ensuite nous dupliquons le storyboard « OnClick1 »
Puis nous le renommons « OnListMouseLeave »
Nous inversons le storyboard pour donner l’effet de
rétractation.
Puis nous assignons ce storyboard à l’évenement
« MouseLeave » défini précédemment.
Voila ! Tous nos comportements graphiques sont
définis !
Il ne nous reste plus qu’à passer à la partie programmation
pour ajouter des items à la liste de choix, puis à définir quelques options de
« binding », et le tour est joué !
Databinding
Fermez le programme « Blend » et retournez dans
VisualStudio.
Double cliquez sur « MonHorloge.xaml » pour
visualiser le code Xaml de votre horloge
Si vous regardez ce code, vous trouverez tous les éléments
que nous avons définis dans blend. Les storyboard, les évènements de clique,
les boutons, les templates, tout y est.
Nous allons jeter un œil à ce code pour variabiliser les
parties liées aux images de cadans, qui pour l’instants sont toutes définies en
dur.
Par exemple le cadran principal est défini pour être le
fichier cadran1.jpg
Nous avions aussi défini ce même fichier dans le « item
template » de notre liste afin d’avoir une meilleure visualisation.
Nous voyons aussi dans ce même bloque de code que le texte
est défini en dur.
Donc, quel est le plan d’action ?
Dans un premier temps, nous allons variabiliser le texte et
l’image de nos items de liste, puis ensuite nous allons lier l’image du cadran
principal avec l’image de la sélection courante dans notre liste.
Pour variabiliser les items, nous allons utiliser le
mécanisme de « Data Binding » utilisé par WPF.
Ce système très puissant permet de dire à un composant
graphique qu’il doit aller puiser une valeur dans une propriété dont le nom lui
est indiqué.
Mais attention, le data binding est une arme à double
tranchant car celui-ci est sous forme de couplage faible.
C’est-à-dire que nous allons indiquer à WPF : « Pour la propriété graphique X, tu appliqueras la valeur Y contenue dans la propriété de classe de nom Z »
C’est-à-dire que nous allons indiquer à WPF : « Pour la propriété graphique X, tu appliqueras la valeur Y contenue dans la propriété de classe de nom Z »
Et WPF nous fait confiance. Il n’ira pas vérifier à la
compilation que le membre est bien lié à une classe dont l’une des propriétés
possède bien le nom Z. C’est à nous de nous débrouiller pour lui fournir les
bonnes informations.
Voyez comment nous allons définir le binding pour la source
de l’image ainsi que pour le texte de notre TextBlock :
Nous venons d’indiquer à WPF : « Tu trouveras le
chemin de l’image dans la propriété ‘Image’ et le texte à afficher de la
propriété ‘Texte’ de l’item que nous te passerons »
Grâce à ce procédé, nous pouvons ajouter des items sous
forme de classes anonymes à notre liste. Tant que celles-ci possèdent nos deux
propriétés, WPF n’y vois aucun inconvénient !
public MonHorloge() { InitializeComponent(); MaListe.Items.Add(new { Image = "Cadrans/cadran1.jpg", Texte = "Standard"}); MaListe.Items.Add(new { Image = "Cadrans/cadran2.jpg", Texte = "Romain" }); MaListe.Items.Add(new { Image = "Cadrans/cadran3.jpg", Texte = "Jaguar" }); MaListe.Items.Add(new { Image = "Cadrans/cadran4.jpg", Texte = "Emeraude" }); MaListe.Items.Add(new { Image = "Cadrans/cadran5.jpg", Texte = "Classique" }); }
L’avantage avec le databinding, c’est que celui-ci permet
aussi d’aller chercher des informations dans les propriétés d’un sous composant
de notre arborescence. C’est exactement ce dont nous avons besoins pour définir
notre cadran principal !
Allez dans le code WPF de l’image, et définissez le binding
de la façon suivante :
La syntaxe indique la chose suivante : « tu iras
chercher l’image à afficher dans la propriété ‘SelectedItem.Image’ de l’élément
‘MaListe’ »
Une fois ceci fait, on a presque terminé.
Effectivement, il faut définir dans le code au moins un
« SelectedItem » par défaut, sinon notre horloge n’aura pas de cadran
au démarrage.
Pour cela, il suffit de rajouter la ligne de code suivante à
la fin du constructeur de « MonHorloge.cs »
MaListe.SelectedItem = MaListe.Items[0]
Et voilà, c’est enfin terminé !
Maintenant que vous
disposez d’un contrôle d’horloge, Vous pouvez l’utiliser dans toutes vos applications qui en
ont besoins comme bon vous semble !
Conclusion
Nous venons de voir comment WPF facilite grandement la conception d'IHM pour votre application, mais ce n'est pas tout !
Car grâce au langage Xaml et aux mécanismes de "Data binding", WPF permet enfin un vrai découplage entre votre code et votre IHM, ce qui présente encore plein d'autres avantages :
- Vous pouvez intégrer un graphiste/designer à votre projet sans que celui-ci possède nécessairement de grosses compétences en développement.
- Le découplage total permet de pousser la testabilité de votre logiciel sur la partie interface, notamment grâce au pattern MVVM.
- Les interfaces que vous réalisez en Xaml sont compatibles avec toutes les technologies de développement Microsoft.
Sympa ton article ! Boudoux qui fait de l'UI : ça me redonne espoir. Le monde n'est plus ce qu'il est, il change. Hollande aura peut-être un truc intéressant à dire bientôt...
RépondreSupprimerMerci bien, le changement est au cœur de la vie d'un développeur :) Malheureusement pour Hollande, comme sa méthode de gestion est basée sur des estimations de croissance, je doute qu'il ait bientôt quelque chose d'intéressant à dire. Il faudrait peut être que ses conseillers lui parlent du #NoEstimates ;)
RépondreSupprimer@+
Super ton article ! Ravi de voir que tu commences à passer dans le monde obscur du design/graphisme des applications WPF ! L'exemple de l'horloge possède des problématiques intéressantes.
RépondreSupprimerJe voudrais juste ajouter que même si c'est possible (théoriquement), il est très difficile de faire du XAML sans connaître un minimum comment coder / avoir des notions de programmation. Cet avantage avancé par Microsoft, de mon point de vue, n'ai pas du tout une réalité. Dans le monde réel, ce sont les développeurs WPF, Windows Phone, et Windows Store Application qui font aussi la partie graphique et donc les composants UI. Et d'ailleurs c'est mieux, au moins ils correspondent vraiment aux besoins des fonctionnalités.
Par contre, cet avantage est beaucoup plus visible dans le monde HTML, CSS.
Hollande ? NoEstimates ? Plutôt dur à appliquer en politique !
++