Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Les deux règles pour comprendre XAML

Des règles et des bonnes pratiques pour développer des applications XAML il en existe bien plus que deux, faire croire le contraire ne serait pas honnête. Ne serait-ce que par la richesse des EDI utilisés (Visual Studio ou Blend). Il faut accumuler de l’expérience et mémoriser de nombreux patterns pour architecturer et designer correctement une application. Mais il y a deux règles à comprendre pour bien programmer en XAML.

XAML qui es-tu ?

XAML, le vrai, le dur, le tatoué, il n’y en a qu’un seul. Celui de WPF. Ces deux technologies sont nées ensemble et sont à jamais liées. Le XAML de WPF est la référence absolue. Il y a eu sa variante “everywhere” (WPF/E appelé plus tard Silverlight) qui n’a hélas pas survécu malgré ses grandes qualités, il y a eu Silverlight pour Windows Phone, passé à la trappe aussi, puis le XAML de WinRT version peu aimée du framework associée à Windows 8 mais qui n’est pas morte et qui a donné naissance à UWP, un XAML très honorable mais pas du niveau de celui de WPF, et enfin le XAML des Xamarin.Forms. Ce dernier ne peut rivaliser graphiquement avec WPF car le principe même est d’instancier des contrôles natifs ce qui supprime la possibilité de modifier leur aspect visuel via XAML et ses primitives graphiques, absentes des XF.

Donc aujourd’hui XAML c’est avant tout celui de WPF, et celui de UWP. Malgré mon support inconditionnel depuis des années à Xamarin et aux Xamarin.Forms, côté graphique et pour les raisons évoquées on ne peut pas comparer ce XAML là aux autres.

WPF fait de la résistance

Ca fait des années que je le dis, WPF est loin d’être devenu inutile. Je le disais quand Windows 8 et Metro sont sortis, je l’ai dit pour Windows 10 et UWP, et je continue à le dire car rien n’a changé dans la justification : WPF est toujours le seul et unique moyen de créer des applications PC hyper performantes et lookées dont la distribution reste sous le contrôle de son auteur ! UWP oblige à passer par le Store de MS, c’est restrictif.

Pour le Mac, pour les smartphones, Xamarin.Forms est la solution la plus aboutie, d’autant qu’elle couvre simultanément UWP ce qui n’oblige pas à cibler cette plateforme de façon spécifique. Mais comme je le disais, privée de sa facette graphique le XAML des Xamarin.Forms ne peut pas être comparé à celui de WPF et d’ailleurs il n’y a pour l’instant aucune vraie concurrence puisque WPF ne peut pas tourner en cross-plateforme et Xamarin.Forms ne peut pas tourner sur un PC sauf par le biais de UWP.

Le XAML de WPF et celui de UWP qui reste très complet malgré tout, sont ainsi les seules émanations de ce langage fantastique jamais égalé ni de près ni de loin par aucun éditeur de langage de programmation dans le monde.

La philosophie de XAML est totalement reprise dans UWP et dans les Xamarin.Forms ce qui est déjà extraordinaire, mais les deux règles que je vais aborder ici ne concernent que WPF en premier chef et UWP en second lieu.

WPF fait donc bien de la résistance, tellement en avance pour son époque qu’il reste la référence absolue pour XAML aujourd’hui encore.

Les éditeurs de logiciels qui ont fait le dos rond durant les époques troubles de Windows 8 jusqu’à 10 doivent bien mettre à jour leurs logiciels qui ont vieilli… Et quel éditeur de logiciel peut se permettre de perdre 20 à 30% de son CA juste pour le fun en créant des Apps UWP pour le Store ? Cela peut être une démarche complémentaire, mais je ne connais aucun actionnaire qui accepterais de perdre autant sur ses dividendes ! Donc pouf pouf … ben non, pas de pouf pouf car il n’y a qu’un seul choix possible pour rester maître de sa création et la distribuer comme on veut au prix qu’on veut : WPF.

Il existe aussi d’autres raisons, comme le fait qu’UWP nécessite un Windows 10 alors qu’il existe encore beaucoup de Windows anciens dans certains parcs informatiques.

Bref, faire du XAML autonome et complet c’est choisir WPF. Si on ne se base que sur l’aspect graphique UWP peut faire l’affaire avec les restrictions techniques et financières déjà évoquées plus haut.

Programmation par Templates

Sous WPF/UWP lâchez les vieilles habitudes. L’une de celles que je rencontre souvent est celle qui consiste à se jeter sur son clavier pour créer un UserControl (ou un Control par héritage) dès qu’on a besoin d’un nouveau composant qui semble absent de la bibliothèque.

Erreur. Méthode du passé.

En effet, WPF et UWP impliquent des changements radicaux de mode de pensée et d’habitudes. Sous ces environnements, la majorité des besoins sont couverts par les composants existants, il “suffit” juste d’en modifier le template.

Nous sommes passés d’une programmation par héritage à une programmation par modèle (template).

Deux exemples pour bien cerner ce que j’entends par là.

Sticky Note

J’adore cet exemple car c’est certainement l’un des plus vieux qu’on puisse trouver ! Il prouve à la fois la fantastique avance de XAML dès sa sortie et sa spécificité technique. Sticky notes pour WPF est un cas d’école (sticky notes listbox). Ce “composant” se présente comme une liste verticale de petites notes de type “post-it” légèrement décalées les unes par rapport aux autres.

image

L’effet est sympathique et donne un peu de fantaisie et de vie à ce qui ne serait qu’une liste rectangulaire dans une grille en programmation classique. Certes le temps à passé et côté graphisme aujourd’hui la mode est au flat et le skeuomorphisme est un peu dépassé, mais ce n’est pas grave c’est un exemple qui à l’avantage d’être très visuel pour illustrrer mon propos.

Ce composant” n’utilise aucun code “'classique”. Inutile dans les sources de chercher la classe StickyNotes qui hériterait de Control ou même de chercher dans les fichiers de l’application le UserControl créé pour l’occasion.

Rien de tout cela.

Sticky Notes est créé uniquement en jouant sur le templating d’une simple… Listbox ! Une poignée de Xaml et des templates, c’est tout.

Le bouton de sélection de langue

Dans une application UWP je devais implémenter un bouton permettant de choisir depuis la page d’accueil la langue à utiliser (français ou anglais). Forcément on pense à un ToggleButton ou quelque chose d’équivalent (ce qui n’existe pas de base). On pourrait aussi associer deux RadioButton dans une grille.

Mais le plus intéressant consiste à se demander “quel control existant se rapproche le plus du comportement que je souhaite implémenter”. En y réfléchissant quelques secondes on s’aperçoit assez vite qu’une CheckBox possède deux états stables (oublions ici l’état indéterminé). Ce composant comporte toute la logique et les états visuels permettant de gérer deux états.

Par défaut une CheckBox c’est une case à cocher avec un bout de texte devant ou derrière.

Le plus dur consiste à se l’imaginer comme deux drapeaux (français et US) côte à côte, celui qui est sélectionné étant à 110% de sa taille et l’autre à 50%. Par convention arbitraire et chauvinisme inconscient certainement j’ai considéré que IsChecked = True était le Français, à False l’anglais (l’exemple est très réducteur quant au support international mais on s’en contentera ici). En partant d’une CheckBox que j’ai totalement vidée de son contenu, et en ajoutant les deux drapeaux (et quelques autres ingrédients et animations via le Visual State Manager) j’ai obtenu un merveilleux “ToggleButton” sans jamais “sous-classer” le moindre contrôle. Juste en écrivant un template.

Le ViewModel de la page d’accueil offre une propriété IsFrench de type booléen qui est simplement bindée à la propriété IsChecked du CheckBox (en mode TwoWay) et l’affaire est jouée !

Les règles

On en arrive aux fameuses deux règles illustrées par ces exemples.

Règle 1 : De l’héritage au templating

La programmation Xaml (WPF/UWP) est une programmation visuelle qui s’effectue par templating. Créer des UserControl et encore plus sous-classer des contrôles existants devient quelque chose de rarissime.

Nous sommes passés de l’ère de la programmation objet par héritage à celle de la programmation visuelle par templating. Ce changement n’est pas récent, il remonte à la création de WPF mais c’est le changement de paradigme le moins bien compris aujourd’hui encore. Bien comprendre toute la signification de ce changement est un point primordial et un préliminaire indispensable pour comprendre cette technologie et donc la programmer intelligemment.

Programmation par Properties

Il s’agit du même genre de glissement, une pente douce mais dont la longueur finit par conférer une vitesse tellement grande à celui qui s’y laisse glisser que le décor n’a plus rien à voir avec celui qu’on a tout le temps d’admirer en balade à dos d’âne…

Dans l’exemple précédent on touchait du doigt cette nouvelle approche mais sans la mettre en exergue.

En effet, dans le pattern M-V-VM plutôt que de créer un code incompatible avec le visuel d’un côté pour ensuite créer de l’autre des tripotés de convertisseurs (programmation classique sous WPF historiquement) il semble bien plus simple d’exposer dans les ViewModels des propriétés directement exploitables par l’UI. Si adaptation des données il doit y avoir c’est le ViewModel qui s’en charge (directement si cela est ponctuel, ou via une classe de service si la chose doit être réutilisées ailleurs).

Dans l’exemple précédent du Checkbox transformé en ToggleButton de sélection de langue, aucun événement n’est programmé, aucun gestionnaire n’est écrit pour réagir au clic. Tout se joue dans le ballet automatique de IsChecked de la CheckBox et de IsFrench du ViewModel sous l’égide discrète mais indispensable d’un binding two way…

Quant l’utilisateur clique sur la CheckBox (enfin sur le ToggleButton avec les deux drapeaux) le composant sous-jacent bascule sa propriété IsChecked à vrai ou faux selon le cas. Comme cette dernière est liée à IsFrench du ViewModel, une propriété de type booléen aussi pour assurer la compatibilité des comportements, le ViewModel ne reçoit pas un événement (ou une ICommand) mais voit l’une de ces propriétés (IsFrench) modifiée. Ce qui déclenche le Setter de cette dernière. Ce dernier s’occupant de modifier le fichier de ressource utilisé pour puiser les chaines de caractères. De là et par une série de notification de changement de propriétés (INPC), il avertit en retour la Vue que toutes les propriétés de type texte ont été modifiées. La vue (et ses bindings) y réagit en rafraichissant les affichages… sans programmation ou presque.

Toute cette mécanique s’est déroulée sans aucun gestionnaire d’événement, sans aucune programmation de Commande, sans aucune programmation “classique” (en dehors du ViewModel et de ces propriétés gérant INotifyPropertyChanged, ce qui peut être automatisé ou simplifié en utilisant une toolbox MVVM).

Règle 2 :  de l’événementiel au binding

La seconde règle d’or à bien comprendre pour tirer totalement partie de XAML et de ses enfants (WPF et UWP mais aussi les Xamarin.Forms ici) est ainsi d’opter pour un modèle de développement de type Model-View-ViewModel se basant presque exclusivement sur des couples de propriétés mis en relation via binding.

On est passé de l’ère du développement dit “événementiel” des premières versions de Windows à ce qu’on pourrait appeler la “programmation par Binding” ou par “properties”.

Conclusion

Pour résumer :

Règle 1 on cherche à templater des contrôles existants sans créer des UserControl ni dériver des contrôles existants.

Règle 2 : on base la dynamique de l’application sur le binding entre propriétés et non plus sur les gestionnaires des événements des contrôles.

Si vous avez déjà fait vôtre ses règles alors vous allez devenir, si ce n’est pas déjà le cas, de très bons développeurs XAML !

Si vous n’aviez pas encore vu les choses sous cet angle là, je serai très heureux si par chance j’ai réussi à lever le voile qui vous empêchait de les voir ainsi. Vous ne ferez qu’entrer plus vite dans la catégorie précédente !

Stay Tuned !

Faites des heureux, PARTAGEZ l'article !