Accueil Nos publications Blog [TechDays 2012] : Fast and Furious XAML Apps !

[TechDays 2012] : Fast and Furious XAML Apps !


Pour l’édition 2012 des TechDays, plusieurs sessions étaient axées sur XAML et l’expérience utilisateur. Voici un compte-rendu d’une session animée par le très sympathique toulousain Cyril Sansus, responsable Nouvelles Interfaces Utilisateurs chez Bewise, sur l’optimisation du code XAML. Quelles sont les bonnes pratiques pour réaliser des applications fluides et performantes en Silverlight, Windows Phone et WPF ? Vous le saurez en lisant ce qui suit !

Cette présentation se concentre sur les problèmes de performances, et les optimisations possibles, le tout accompagné d’exemples concrets.

Cyril nous rappelle tout d’abord les trois facteurs d’adoption et d’adhérence de l’utilisateur :

  • Fluidité
  • Performance
  • Réactivité

Nous verrons comment, à travers des exemples concrets, remplir ces conditions avec des solutions simples et les pièges à éviter.

Expérience de chargement

On rentre dans le vif du sujet avec l’expérience du chargement de données au démarrage d’une application. Une petite TODO list est présentée :

Pour réaliser cette todo-list, plusieurs outils sont à notre disposition dans le framework. On va utiliser BusyIndicator pour le retour utilisateur comme quoi une action est en cours, l’asynchronisme pour ne pas freezer l’interface et le célèbre Thread.Sleep pour simuler la lenteur lors des tests.

Optimisation !

Passons maintenant aux choses sérieuses avec les optimisations possibles et fortement conseillées par Cyril.

Asynchronisme

L’ensemble des mécanismes permettant de faire ceci est cité :

  • Thread
  • Threadpool
  • Backgroundworker
  • Délégué asynchrone
  • TPL
  • Async

Mais, quand doit-on utiliser de l’asynchronisme ? Les utilisations les plus classiques sont l’accès aux WebServices, les WebRequest, l’utilisation des Socket, File Isolated Storage, l’accès aux bases de données, ou encore lors de traitements lourds.
Premier conseil : ne pas utiliser les Threads, et leur préférer le Threadpool ! Une petite démo nous montre l’utilisation des objets Task et TaskScheduler, pour un résultat optimum : un bel écran de chargement !
<br /> Task.Factory.StartNew(OnLoad).ContinueWith(t => { OnLoadCompleted(); isBusy= false; },<br /> TaskScheduler.FromCurrentSynchronisationContext())<br />

A retenir :

  • Retour utilisateur : il faut l’avertir que l’application n’a pas planté !
  • Facilitez-vous l’asynchronisme.
  • Attention au LazyLoading, il faut le désactiver !
  • Ralentissez vos traitements, afin de détecter des problèmes de latence.

XAML

Un des principaux problèmes est le temps de chargement d’un fichier XAML. Cela résulte visuellement en des animations saccadées et un blocage suffisamment long pour être perceptible. Deux solutions s’offrent à nous :

  • différer le chargement
  • faire du chargement à la volée

Ceci permet d’augmenter la performance perçue. Cyril nous montre également un exemple avec une liste de boutons. Voici quelques idées d’optimisations :

  • déporter le code style dans un autre fichier XAML (merci les ResourceDictionary !)
  • remplacer le UserControl par un custom control

Sans optimisation, chaque bouton met 2ms pour se charger. Après optimisation, le résultat est sans appel : 0.0086ms pour charger un bouton, à multiplier par un nombre très grand si vous manipulez d’énormes listes, et vous verrez que ces optimisations sont indispensables pour rendre votre application vivante et fluide.

A retenir

  • Le temps de chargement du XAML peut pénaliser les performances
  • Utiliser les ResourceDictionary
  • Ne jamais mettre de UserControl dans des DataTemplates, ça ne sert à rien !

Layout

On enchaîne sur un morceau de choix : le Layout. C’est ce qui calcule la taille et la position de chaque élément. Il est essentiel de savoir que le gestionnaire de layout est appelé très fréquemment : scroll, resize, load, margin, … Un mauvais layout a pour conséquences un redimensionnement lent, des animations saccadées et un temps de chargement rallongé.

Optimisation cruciale : supprimez tout ce qui est inutile !! Cyril insiste sur ce point, 99% des éléments “UserControls” sont inutiles en WPF. C’est un héritage des Windows Forms et ne doit pas être utilisé dans un code full WPF.
Pour des résultats optimaux, il faut mesurer les perfs. Une bonne méthode est de chronométrer l’update du Layout avec l’event LayoutUpdated, mais il existe également les WPF Performance Tools, ainsi que d’autres outils d’éditeurs tiers comme Snoop.

Animations

Les animations consomment du temps cpu, elles interagissent avec le layout. Il faut penser à ajuster le framerate de celles-ci. Cyril nous fait une démo d’une utilisation incorrecte des animations, où l’on utilise des animations basées sur les propriétés Margin et Canvas, puis une démo basée sur la fonction RenderTransform. Là encore, le gain de performance est incontestable.

Conseil important : utiliser RenderTransform !!! Cette méthode ne fait pas appel au layout contrairement à l’utilisation des properties Margin, Canvas.
Second conseil : pour les Converter, il faut préparer les données en amont, et penser à la mise en cache !

Virtualisation d’UI

La virtualisation permet d’afficher des listes de millions d’éléments, en instanciant uniquement les éléments visibles. C’est un Must have ! Elle est activée par défaut mais attention car elle peut être désactivée en utilisant le regroupement de données, ou en désactivant l’un des deux flags isVirtualizing et CanContentScroll.

A retenir

  • Ne jamais désactiver la virtualisation
  • Activez le recyclage
  • les ItemsControl n’ont pas de virtualisation par défaut

Le cas DataGrid

La DataGrid est un peu la bête noire des entreprises. Elle regroupe tous les éléments vus précédemment (animations, layout, XAML, asynchronisme) et doit être performante. Le problème est que la DataGrid native pose quelques soucis lorsque l’on doit manipuler un grand nombre de cellules affichées à l’écran. Cyril a dû recoder une DataGrid simple pour pouvoir répondre aux critères du client. Il nous explique les points sur lesquels il a apporté des optimisations :
update du layout : temporiser (15ms) l’update du layout, et positionner les éléments uniquement avec du TranslateTransform permet de ne pas envoyer des updates de layout massivement.
virtualisation : on ne fait pas de add/remove des éléments, et la propriété visibility est flaguée à Collapsed

Tips & Tricks

Cyril conclut sur quelques petits trucs et astuces pour optimiser son application

  • Toujours tester sur le device ciblé
  • Impact de la résolution
  • Ralentissez vos traitements
  • Augmentez le volume de données
  • Impact de Debug et Trace dans les performances

Conclusion

Cette session fut riche en enseignements, Cyril a mis en lumière des optimisations essentielles et faciles à mettre en œuvre pour avoir un résultat optimum et par conséquent une expérience utilisateur accrue. Je vous vois déjà trépigner d’impatience pour mettre tout ceci en pratique, alors… A vos marques, prêts, Optimisez !!