Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

StringFormat : une simplification Xaml trop peu utilisée

[new:15/01/2013]Mettre en page des éléments variables ou formatés en XAML peut parfois sembler fastidieux, c’est oublier qu’il existe des astuces de Binding comme le StringFormat qui simplifient beaucoup les choses…

De Silverlight à Windows Phone 8 et WinRT

Le principe est le même et les options sont semblables. Cet article s’applique ainsi à toutes les versions de XAML implémentant StringFormat. Le nombre de “saveurs” de XAML étant désormais important (WPF, WP7, WP8, Silverlight, WinRT… et chacune variant parfois selon l’historique de ses versions), il sera toujours intéressant de vérifier ponctuellement que telle ou telle option est disponible dans la version de XAML que vous utilisez, plutôt que de vous arracher les cheveux ou de me traiter de tous les noms derrière mon dos Sourire

Le code à la Papa

Je vois souvent du code écrit “à la papa”. Il s’agit d’un méfait plus répandu que le célèbre code Spaghetti (Cf Le Retour du Spaghetti Vengeur) et donc ayant un pouvoir de nuisance presque aussi grand. S’il reste moins “grave” techniquement parlant, puisqu’il respecte en apparence le langage et les bonnes pratiques, il est insidieux et complique la maintenance, voire l’écriture du code, lorsqu’il n’oblige pas à écrire du code là où il en est nul intérêt ni besoin.

Un simple exemple : Afficher un texte du genre “Bonjour machin”, où “machin” n’est bien sûr pas un innocent blanchi par la justice récemment mais un nom quelconque. J’aurais donc pu écrire “Bonjour truc”. Mais pas “Bonjour zinzin”, un zinzin est un objet et on ne dit pas bonjour aux objets à moins d’avoir sa carte de fidélité au club des membres actifs de Sainte-Anne.

Bref, supposons cette situation simple.

Ce qu’on voit souvent c’est un bricolage du genre :

<StackPanel Orientation="Horizontal">
     <TextBlock Text="Bonjour "/>
     <TextBlock Text="{Binding UserName}"/>
</StackPanel>

 

On remarque l’utilisation de deux TextBlock, un fixe, l’autre bindé à la source de données. Mais on note aussi la présence sournoise d’un StackPanel pour englober tout cela.

Autant d’objets en mémoire, autant de code écrit rendant le tout indigeste.

Certes c’est “légal”, c’est là toute l’astuce du code à papa, il a l’air inoffensif et légitime… Son défaut principal ? En être resté à l’époque de la machine à vapeur de sa jeunesse…

StringFormat à la rescousse

Plutôt qu’une bonne grosse poignée de code bien lourde à digérer, on peut résumer en une seule ligne avec un seul objet le code ci-dessus :

<TextBlock Text=”{Binding UserName, StringFormat=’Bonjour {0}’}” />

 

Forcément, c’est plus élégant… ça prend moins de place dans le fichier XAML, ça rend la lecture plus aisée, donc la maintenance plus sure et plus facile, et en mémoire un seul objet est créé au lieu de trois. Ce qui signifie aussi que la circulation des évènements (Bubbling et Tunnelling, l’un ou les deux selon la saveur de XAML) s’en trouve fluidifiée en cas de gestion d’un clic, d’un mouvement de souris, etc.

Rien que des avantages donc. Et grâce à une option du Binding : StringFormat.

Il n’y a pas que le nom de l’utilisateur qui se prête ainsi au jeu des simplifications, de très nombreux cas se présentent où les données retournées par le Modèle ou le ViewModel ne se prêtent pas instantanément à une présentation agréable pour l’utilisateur. Imaginez la lecture du capteur de position GPS par exemple, si vous affichez la latitude sans prendre de précaution, des tonnes de chiffres après la virgule viendront s’étendre sur votre belle mise en page pour la ruiner (ce qui est vrai avec  tous les Double ou même Float)…

J’ai vu des développeurs exposer de telles propriétés en String dans leurs ViewModels pour avoir la possibilité de les formater correctement. Que dire d’autre que “Beurk !”…

La mise en page c’est la mise en page, le code d’un ViewModel ou d’un Modèle ne doit en rien être adapté pour l’affichage. C’est à la Vue de la faire. Donc à XAML.

Ainsi, la fameuse latitude sera bien plus lisible si on restreint son affichage à, par exemple, 3 décimales, comme suit :

<TextBlock Text=”{Binding MyGeoposition.Latitude, StringFormat=\{0:F3\}}” />

 

Vous percevez j’en suis certain l’intérêt.

Support multi langue

Le support de toutes les langues du monde est une tâche difficile, généralement un logiciel se limite à deux ou trois traductions possibles. Encore faut-il bien gérer l’affichage des nombres, des dates et tout ce qui est en rapport avec la culture locale de l’utilisateur…

Pour un américain, une date sera lisible si elle est écrite ainsi ;

Tuesday, December, 11, 2012

Ce qui est ridicule pour un français qui préfère largement :

Mardi, 11 décembre 2012

Mais un espagnol n’y trouvera pas son compte, lui qui écrit :

martes, 11 de diciembre de 2012

Allez-vous vous amuser à prendre en compte tous ces cas particuliers ? Non, et vous le savez, l’une des force du framework .NET est de connaitre ces subtilités là à votre place, loué soit-il.

Hélas XAML est un peu plus comme les américains “ah bon, tout le monde ne parle pas l’anglais en mâchant du chewing-gum, une pizza Hut dans une poche et un saut de popcorn dans la main ?”.

Donc XAML a du sécher les cours de langues car hélas il a un petit problème de synchronisation avec la belle mécanique de localisation mise en œuvre dans le framework .NET.

Pour s’en sortir, rien de compliqué, mais encore faut-il le savoir.

Il suffit d’écrire dans le constructeur de la Vue le code suivant :

 

this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);

 

Il est clair que cette petite synchronisation aurait du être corrigée depuis longtemps, mais les équipes qui font XAML ont tellement été trimbalées par ci et par là à tout refaire à zéro comme pour WinRT que forcément l’éclatement du même code en différentes saveurs ne facilite pas la consolidation de l’existant. Quand on vous dit qu’il faut travailler proprement pour simplifier la maintenance, ce n’est pas juste pour vous embêter, vous avez ici la preuve éclatante des effets dévastateurs d’un manquement à cette rigueur…

Le mini langage dans le mini langage dans le langage

C’est un peu mon premier reproche quand j’ai abordé Xaml il y a déjà longtemps, je m’y suis fait, mais je reste toujours aussi critique sur certains choix que je trouve un peu gênant. Notamment cette impression de “poupées russes”. Xaml est un langage. Le Binding est une astuce proposant son propre mini langage avec ses options, ses variantes, etc. Et StringFormat se place dans le Binding en offrant lui aussi ses petites variantes “perso” sans aucune véritable homogénéité avec le reste.

Mais avec le temps on s’y habitue sauf que malgré tout il faut garder une anti-sèche toujours planquée dans un coin pour ne rien oublier !

StringFormat ne se contente pas de placer une chaîne dans une autre avec un marqueur de position “{0}”, il possède de nombreuses options bien pratiques !

Chaînes

Par exemple avec les chaînes il est possible d’indiquer un cadrage gauche ou droit dans un espace défini :

StringFormat=\{0,10\} donnera "   Bonjour"
StringFormat=\{0,-20\} donnera "Bonjour   "

 

Le premier 0 indique le paramètre, le chiffre après la virgule est le nombre d’espaces dans lequel le champ doit être justifié, positif pour un cadrage à droite, négatif dans l’autre cas.

Très honnêtement je déconseille fortement cette option, seules les secrétaires de plus de 60 ans qui ont connu les machines à écrire mécaniques s’amusent à cadrer du texte avec la barre d’espace… Sur les traitements de texte on utilise des tabulations, et avec XAML on utilise tout simplement une mise en page correcte !

Mais bon, cela doit pouvoir servir. Ca existe en tout cas.

Nombres

Les options concernant les nombres sont bien entendu plus intéressantes et surtout se justifient pleinement.

Pour un double qui possède la valeur 15695,2569 les effets des différents formatages seront les suivants :

StringFormat=\{0:C\} : 15 695,26 €
 
StringFormat=\{0:F\} : 15695,26
 
StringFormat=\{0:N\} : 15 695,26
 
StringFormat=\{0:E\} : 1,56952569E+004
 
StringFormat=\{0:P\} : 1 569 525,69%

 

En ajoutant un nombre derrière la lettre du format on peut indiquer le nombre de décimales voulues ( de 0 à autant que cela a de sens). Le nombre est collé à la lettre. Par exemple StringFormat=\{0:F3\} pour un formatage de type F avec 3 décimales.

On note l’anti-slash pour “escaper” l’accolade américaine ouvrante et fermante, ce qui est obligé puisque ces accolades sont contenues à l’intérieur d’un Binding qui lui-même les utilise déjà pour autoriser sa propre présence en XAML… (on en revient au langage dans le langage dans le langage…).

Dates

StringFormat est bien utile aussi pour les dates, objet complexe dont les conventions d’écriture sont très nombreuses et possédant dans chaque culture ses propres variantes selon qu’on veuille faire court ou long.

Le principe est le même que pour les nombres sauf qu’on ne peut pas passer de chiffre après la lettre de format, puisqu’il n’y a pas de décimales…

Le plus simple des formatages est obtenu avec “d” minuscule. Il formate la date sans l’heure en mode compact “1/1/2013” par exemple.

La lettre “D” majuscule formate la date longue (“Mardi 11 décembre 2012”).

Le petit “f” rajoute l’heure à “D” en format court (“3:25”)

le grand “F” fait comme le petit “f” mais l’heure est cette fois-ci en format long (“16:12:30”)

Le petit “g” formate la date en mode court et l’heure en mode court.

Le grand “G” formate la date en mode court mais l’heure en mode long.

Le grand “M” formate le nom du mois et le jour “15 Décembre”

le grand “R” format le nom du jour court, le nom du mois court, et l’heure longue en GMT (“Ma, 1er Jan 2013 22:15:20 GMT”)

Bien entendu, il reste possible de fabriquer son propre format date et heure en utilisant les traditionnels “hh / HH, mm, …”. Cela se justifie dans quelques cas. Hélas il est fréquent qu’ayant oublié les nombreuses variantes exposées ci-dessus on s’adonne à la facilité d’un formatage personnalisé dont les composantes sont plus logiques et faciles à retenir. Mais c’est mal. Si on utilise un formatage existant, il faut utiliser la lettre de format.

D’autres références

Vous trouverez les références complètes sur MSDN bien entendu.

Voici quelques adresses :

 

Conclusion

StringFormat n’est pas l’astuce du siècle, tout juste une façon de vous rappeler que XAML est un langage “à tiroir” et qu’il faut prendre le temps de bien connaitre toutes ses subtilités car la plupart font gagner du temps et rendent le code plus lisible et plus maintenable.

C’est aussi une façon de vous rappeler que le Binding est un langage à lui tout seul (cf. mon article en PDF + code Le Binding Xaml – Maîtriser sa syntaxe et éviter ses pièges près de 80 pages tout de même !)

Un bon code n’est pas fait seulement de grandes théories, mais aussi de petites attentions…

Stay Tuned (et Joyeux Noël !)

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