Dot.Blog

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

Prism pour Xamarin.Forms – Partie 5

Poursuivons l’étude pratique de cette librairie MVVM très intéressante qu’est Prism…

Articles précédents

Avant d’aborder le sujet du jour, rappelons ce que nous avons vu jusqu'à maintenant :

  • Partie 1, une présentation générale de Prism et divers liens vers d’autres articles
  • Partie 2, Créer un projet, la connexion des Vues et des ViewModels…
  • Partie 3, le système de gestion des commandes
  • Partie 4, La navigation

Savoir créer un projet, comprendre comment MVVM s’applique, gérer les commandes et surtout la navigation, tout cela forme déjà un socle de base plutôt complet.

Mais Prism offre quelques autres services tout aussi bien conçus.

La messagerie

La messagerie est un service de la plupart des librairies MVVM. Pourquoi ? La gestion des évènements n’est-elle pas rigoureusement identiques ?

En fait oui, les Events permettent d’émettre des informations au moment voulu et ils autorisent d’autres parties de l’application à s’abonner à ces transmissions à leur guise pour réagir lorsqu’un évènement particulier se produit.

C’est la base de la mise à jour des UI en XAML par exemple grâce au support de INPC par les ViewModels. Lorsqu’on créé un binding entre un contrôle (une de ses propriétés) et une propriété du ViewModel l’UI s’abonne à l’évènement INPC du ViewModel. A chaque fois que la donnée sous jacente change elle émet un signal INPC qui est géré par l’UI (puisqu’y étant abonné) ce qui lui permet de se mettre à jour.

Les événements sont un peu partout dans la programmation sous C# et d’autres langages car Windows lui-même est un OS “Event driven”, piloté par les évènements, ceux du user notamment. N’importe quelle partie d’une application peut potentiellement être activée en réponse à un clic, un scroll, etc, sans que l’ordre de ces événements ne puissent être prévu. C’est ce qui a marqué une différence majeure avec la programmation classique qui se pratiquait alors en mode console par exemple (MS DOS si cela parle à certains lecteurs !).

Néanmoins on voit à ces explications qu’il y a quelque chose qui cloche dans le cadre d’un découplage fort tel que l’impose MVVM : Pour réagir à un événement on doit s’y abonner. En clair, si l’instance a de classe A veut s’abonner à l’événement e de classe E de l’instance b de la classe B, a doit connaître b, donc A doit connaître B.

Vous suivez ? Oui j’en suis sûr.

Et MVVM et les bonnes pratiques qui gravitent autour imposent un découplage fort. Elles imposent que A n’ait pas à connaître B. Forcément cette connaissance, ce couplage peut avoir un sens dans certains cas, mais en dehors de cas bien balisés A ne doit pas connaître B, et certainement pas pour juste s’échanger des messages.

D’où l’idée de “casser” ce lien fort qui existe en deux classes impliquées dans une gestion d’événement classique.

Pour casser ce lien le mécanisme de la messagerie s’est imposée : A et B peuvent connaître la messagerie, mais ils n’ont pas besoin de connaître mutuellement pour échanger des informations. C’est même mieux que la Poste ! Si quelqu’un veut vous envoyer une invitation à un évènement elle doit connaître votre nom et votre adresse. Il existe un couplage fort. Et si elle veut que vous puissiez vous rendre à l’évènement elle devra dans le courrier vous indiquer son nom aussi ainsi que l’adresse où vous rendre… Double couplage.

Les messageries MVVM découple réellement les intervenants. Les messages sont envoyés “à la volée” par celui qui les émet, et la messagerie les distribue uniquement à ceux qui le désirent.

On comprend ici que les messages contiennent donc en général quelques données ou indications qui permettent à la messagerie de filtrer les mouvements, c’est à dire d’effectuer un routage efficace. Si la messagerie envoie tous les messages de tout le monde à tout le monde cela risque de devenir assez vite trop lourd. Les messages MVVM ne sont pas décrits officiellement dans un livre ou par des universitaires, cela peut être uniquement un simple signal sans autre information. Mais généralement les librairies offrant une messagerie MVVM permettent de caractériser les messages par une clé, une catégorie, ou d’autres informations justement pour autoriser un routage efficace.

Les Xamarin.Forms qui sont une construction récente contiennent de base des éléments facilitant la mise en place de MVVM à la différence par exemple de WPF qui n’offre rien de base dans ce domaine. Ainsi on trouve out-of-the-box une messagerie MVVM plutôt simple et bien faite. Des librairies comme Mvvm Light offrent elles aussi leur propre gestion des messages.

Prism n’échappe donc pas à la règle. Mais pourquoi donc ne pas utiliser la messagerie des Xamarin.Forms ?

Il n’y a pas de raison “massue”. On peut évoquer la cohérence qui oblige d’une certaine façon à utiliser Prism en entier ou pas du tout par exemple. On peut dire que puiser un bout ici et un bout là risque d’être plus difficile à maintenir. Tout cela est vrai. Mais ce n’est pas décisif. Il m’est arrivé dans certaines Apps Xamarin.Forms d’utiliser Mvvm Light mais de me servir des commandes ou de la messagerie des Xamarin.Forms par exemple… Mais c’est là qu’on finit par se poser des questions… Dois-je continuer à utiliser Mvvm Light si ce n’est que pour le ViewModelLocator que je suis obligé d’écrire moi-même en plus ? La réponse est non, et ces Apps ont été terminées en supprimant totalement Mvvm Light pour éviter une dépendance à une librairie qui ne fournissaient presque plus aucun service à l’application… C’est un autre sujet mais c’est l’avenir de Mvvm Light qui se joue là. Être “light” est très sympa tant que la plateforme ne s’en mêle pas. Les Xamarins.Forms fournissant désormais des services MVVM typiques d’une librairie MVVM “'light”, Mvvm Light va devoir changer ou disparaître. Mais c’est vraiment un autre débat et je suis certain que Laurent Bugnon qui est un garçon intelligent y a déjà pensé !

En serait-il de même de Prism ?

On sait que ce n’est pas le cas rien que pour le service de Navigation par exemple. Difficile de s’en passer. On le verra plus tard pour le service de dialogue ou même les Logs. Dès lors puisque Prism se justifie pour ces fonctions importantes il est naturel d’en utiliser toutes les facettes.

La raison d’utiliser la messagerie Prism se trouve donc là : elle s’ajoutent à des services réellement utiles de Prism et puisqu’on va utiliser ces derniers autant utiliser par cohérence l’ensemble fourni par cette librairie.

EventAggregator

Certainement l’héritage des premières versions de Prism, le nom de la messagerie n’est pas très friendly et peut même effrayer un débutant. Un agrégateur d’évènements… Brrrr. Ca fiche les jetons !

En fait non, c’est juste un autre nom possible pour une simple messagerie MVVM, un nom plus juste d’ailleurs certainement mais fort peu utilisé il faut l’avouer.

Donc pour commencer considérez que ce nom étrange n’est autre que celui de la messagerie, comme celle fournie par les Xamarin.Forms ou celle de Mvvm Light.

Ses avantages sont approximativement les mêmes :

  • Fort découplage, communication basée sur des évènements
  • Multiple publicateurs et multiples souscripteurs
  • Possibilité de passer des paramètres ou des données de toute nature
  • Présence d’un filtre des événements
  • Et bien entendu ce sont des weak events utilisant des weak references.

Le filtrage est un élément qui varie beaucoup d’une messagerie à l’autre et c’est là qu’on verra la différence principale. L’autre élément d’appréciation à considérer est l’utilisation de weak events, c’est à dire l’utilisation de références faibles qui évitent les pertes de mémoire que la gestion traditionnelle des événements peu entraîner.

C’est un sujet important et lorsqu’on choisi une messagerie MVVM on doit vérifier ce point essentiel. Ne souhaitant allonger cet article par trop de redites, je renverrai le lecteur intéressé à ces trois articles plus anciens :

Code souvent dans le monde du découplé tout passe par une interface, IEventAggregator. Comme sous Mvvm Light les messages sont eux mêmes des instances d’une classe particulière. Rien de nouveau donc.

Voici un exemple schématique d’utilisation :

// Déclaration de la classe de l'événement ( = message)
public class SavedEvent : PubSubEvent<Person> { }

// Publicateur du message
IEventAggregator.GetEvent<SavedEvent>().Publish(somePersonInstance);

//Côté souscripteur du message
IEventAggregator.GetEvent<SavedEvent>().Subscribe(SomethingSaved);

// Un delegate activé par la réception du message
void SomethingSaved(Person p)
{
    // faire quelque chose ici...
}

Bien entendu dans la réalité on n’appelle pas l’interface de cette façon mais une instance d’un service qui implémente la dite interface.

Généralement on obtiendra le service de messagerie par le biais de l’injection de dépendances dans le constructeur du ViewModel de façon assez classique :

        private readonly INavigationService _navigationService;
        private IEventAggregator _eventAggregator;

        public MainPageViewModel (INavigationService navigationService, IEventAggregator eventAggregator)
        {
            _navigationService = navigationService;
            _eventAggregator = eventAggregator;
        }

Les références sont conservées dans des variables locales pour être réutilisées par les différentes méthodes de la classe ViewModel.

Les messages étant typés si on souhaite passer des données on dispose d’un mécanisme complet permettant la transmission de données ou de contextes complexes qui peuvent être utilisés par le ou les récepteurs pour traiter l’événement.

En réalité le mélange entre “événement” et “message” est volontaire ici, pour vous faire comprendre qu’en réalité une messagerie MVVM n’est rien d’autre qu’une question d’Event comme C# le propose de base mais en version fortement découplée… Si vous comprenez les Events et les delegates alors vous comprenez l’EventAggregator de Prism !

Bien que la messagerie Prism utilise des Weak Events il n’est interdit de penser à se désabonner notamment avant de sortir d’une page (voir les événements de navigation de INavigationAware) cela est toujours plus propre et peut aussi éviter qu’un message soit interprété par une page qui ne devrait plus le faire (en effet la page peut être détruite par le garbage collector au bout d’un temps inconnu laissant la possibilité à des messages de passer, ce qui créée des plantages particulièrement sournois ! Avec Prism comme avec toutes les gestions d’événements et toutes les messageries MVVM).

Conclusion

La gestion de la messagerie MVVM de Prism est assez classique, complète, bien programmée (en utilisant des Weak Events). L’utilisation de nombreux messages dans une application est toutefois à éviter car le code spaghetti est déjà un enfer mais l’event spaghetti est peut-être encore pire !

L’étude du code de Prism montre qu’il existe d’autres petites choses à savoir sur la messagerie mais rien ne sert d’alourdir le présent article, si vous vous décidez à utiliser Prism vous trouverez par vous-mêmes ces petits bonus…

Il nous reste encore des choses à voir sur Prism, alors je vous donne rendez-vous pour un prochain article…

Stay Tuned !

blog comments powered by Disqus