Dot.Blog

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

Xamarin.Forms 4 : Le Shell Partie 3/4

Dans les articles précédents j’ai jeté les bases du nouveau Shell des Xamarin.Forms, il est temps d’aller un peu plus loin en nous intéressant à un aspect essentiel, le Routing…

Introduction

La Partie 1 nous a permis de découvrir le Shell et ses fonctions de base, La Partie 2 a permis de préciser certains concepts et d’en découvrir de nouveaux comme les onglets secondaires.

Vous êtes presque prêt à utiliser le Shell dans vos Apps. Mais la plupart du temps ces applications de production doivent s'appuyer sur une navigation plus complexe que les onglets et les menus déroulants. Dans cet article, je vais vous montrer comment vous pouvez utiliser le routage (Routing) pour naviguer dans n'importe quelle partie du Shell à l'aide de quelques lignes de code !

Des routes, pourquoi ?

Comme vous l’avez vu, jusqu’à maintenant la navigation est sous les ordres directes de l’utilisateur. Nous créons des structures de navigation, des menus, des tabulations, qui vont le guider, le diriger, mais c’est lui et lui seul qui décide sur quoi appuyer donc “où aller”.

Or dans une App la navigation – c’est ce qui en fait en partie la complexité – n’est pas sous les seuls ordres de l’utilisateur. L’application elle-même en fonction des requêtes auxquelles elle doit répondre, d’impératifs liés à son état interne ou à l’état externe d’autres éléments (devices, web…) doit être en mesure de prendre des décisions de navigation.

Le découplage fort MVVM s’étend à tout aujourd’hui et ne concerne plus que l’UI mais aussi le code C# et la structure, l’architecture même de toute l’App.

Or pour naviguer la façon usuelle consiste à créer des pages et à les empiler sur la pile de navigation.

Créer des pages ?

Oui. Donc instancier des classes précises pour créer des objets bien précis et les ajouter à un dictionnaire bien précis.

Cette relation entre l’App et ce bas niveau est intellectuellement consternant mais au-delà de nos avis et ressentis personnels cette relation est dangereuse !

Elle oblige à mélanger actions de hauts niveaux avec utilisation de classes connues difficilement modifiables par la suite sans créer d’erreur.

Le découplage fort qui s’est imposer avec le temps en XAML doit s’appliquer à la navigation. C’est pourquoi plutôt que de naviguer en instanciant des classes de Vues ou de ViewModels, nous devons nous séparer de cette réalité par une abstraction.

Cette abstraction ce sont des noms, des strings, pour chaque feuille, chaque embranchement de notre navigation. Des noms sans rapport avec l’implémentation mais en rapport avec leur rôle fonctionnel.

Cette abstraction permet ensuite d’entrevoir un moyen de navigation basé sur ces noms fonctionnels, formant ainsi des chemins, des routes dont la signification sera claire et constante dans le temps quelle que soit l’implémentation.

XAML, langage descriptif par essence, va ici nous permettre de préciser outre la structure de l’App les routes qui permettent d’y naviguer.

C’est le Routing, routage.

Pour fixer le décor nous partons d’un code de la partie 2 qui est le suivant ;


Pour l’instant il ne s’agit que de structuration des menus, des sections, des contenus. Les routes n’existent pas encore. Elles sont tracées mais le goudron n’a pas été déposé dessus en quelque sorte…

Ajoutons les routes :

image


La déclaration des routes consiste tout simplement à donner des noms aux nœuds et aux feuilles de notre structure de pages. Mais quelle avancée !

Chaque ShellItem, chaque ShellSection, chaque ShellContent à un nom de routage. Il est possible de répéter des valeurs (mêmes noms) tant que les chemins qu’on peut prendre en les utilisant restent uniques.

On comprend en lisant le XAML ci-dessus qu’il existe de nombreuses routes partant de la racine comme “Incontournables / Notes” ou “Bases / Main2” ou bien “Utilitaires / Suppléments / Note3”.

Naviguer sur les routes

Maintenant que nous avons défini les itinéraires la navigation vers un emplacement particulier dans l’ensemble de la structure de Shell est très simple. Pour l’exemple j’ai ajouté un bouton à la page principale en jouant sur sa méthode Click dans le code behind. Bien entendu dans la réalité (c’est à dire en MVVM) un tel raccourci paresseux n’est pas acceptable ! Il faudra créer un ViewModel, comme d’habitude, le connecter à la Vue comme d’habitude, créer une ICommand comme d’habitude etc, et dans cette commande utiliser le code que je vais vous montrer. Bon cela me paraît évident mais ça va mieux en le disant…

Par défaut la première page affichée est la page principale. Depuis le premier ShellItem disons que nous voulons atteindre à coup sûr la page secondaire du troisième élément (celui qui se trouve à l'intérieur de la section). Tout ce dont nous avons besoin est d'identifier de façon fonctionnelle l’itinéraire: Utilitaires / Suppléments / Note3.

Peu importe les noms des Vues ou des ViewModels, nous travaillons maintenant au niveau fonctionnel et cette navigation que vous nous venons d’exprimer de façon fonctionnelle se traduira dans le code par un appel tout aussi descriptif et fonctionne :

image

L'écran principal affiché par l’App est le suivant avec son bouton :

Screenshot_1565795461


lorsqu’on clique sur le bouton, voici ce qui est affiché :

Screenshot_1565795518

Nous voici en effet sur la page “Note3” faisant partie de la section Suppléments de la racine Utilitaires !

La syntaxe utilisée montre un double slash en début de chemin : c’est donc un chemin absolu que nous utilisons. Cela marcherait donc depuis n’importe quel endroit de l’App.

Comme j’ai dupliqué les mêmes deux pages dans tous les ShellItems on retrouve bien entendu le même bouton de navigation un peu partout sur les trois routes principales. Mais en cliquant dessus on atterrit toujours sur la même page !

En utilisant une syntaxe relative, comme pour le Web, on pourra naviguer relativement à l’emplacement en cours. C’est assez simple à comprendre je ne vais donc pas m’étendre.

De même il existe un second paramètre à GotoAsync qui indique si le Shell doit passer à la nouvelle page avec ou sans animation (avec étant le mode par défaut). Là encore c’est un classique pas besoin d’y rester des heures.

Naviguer hors des sentiers battus

GoToAsync est assez facile à utiliser cependant que se passe-t-il si vous avez une page qui ne fait pas partie de la structure du Shell ? Par exemple une page de connexion qui ne devrait figurer nulle part dans cette structure (l’utilisateur n’y accède pas à partir d'un onglet ou du menu déroulant), mais vers laquelle vous souhaitez quand même naviguer dans certains scénarios.

Dans ce cas, vous devez d'abord enregistrer la route, non pas à partir du fichier XAML du Shell, mais de son constructeur. Par exemple, si vous avez une page de connexion vers laquelle vous souhaitez naviguer en cliquant sur un bouton d’une page secondaire, vous devez suivre ces étapes:

Enregistrer la nouvelle route

C’est dans le constructeur du Shell et non dans le fichier XAML qu’on va initialiser ses chemins de traverse… S’ils étaient dans le Shell ils feraient partie des menus et l’utilisateur y aurait accès. Ici c’est l’App qui décide d’afficher ou non l’écran de login (c’est un exemple). La page existe mais sa route d’accès doit être définie hors Shell XAML :

image

Emprunter la route

Construire des routes n’a d’intérêt que si on les emprunte ! Pour utiliser la nouvelle route que nous avons construite et qui mène à l’écran Login on peut utiliser GotoAsync comme précédemment. Le fonctionnement est le même puisque le Shell connait la route. Mais le Shell visuel ne la connait pas. Nuance… Subtile mais très importante.

image

Le résultat visuel est légèrement différent de ce que nous avons vu jusqu’ici. Le Shell sait quel type de navigation il effectue et il utilise une animation différente en conséquence. De plus comme cet itinéraire n'existe pas dans la structure principale du Shell, la page affichée possède des attributs visuels différents comme le bouton Back:

Partons de la page secondaire (“Notes” comme on le voit dans la tabbar en bas) :

Screenshot_1565799776


Lorsqu’on clique sur le bouton l’animation de transition de page sera différente et nous montrera :

Screenshot_1565799784


Aller … Et Revenir !

Lorsque l’utilisateur cliquera sur le bouton d’identification l’exemple se contentera de naviguer en arrière par l’appel suivant :

image

Variantes

Bon, la page présentée n’est pas vraiment une page de Login. Sa position même dans la stack de navigation n’est pas tout à fait habituelle.

Mais cela peut correspondre à des cas réels malgré tout ! Par exemple une App qui n’a pas forcément de Login “forcé” mais une option pour se connecter à une source extérieure de données par exemple. Si l’utilisateur veut bénéficier de cette dernière il doit s’identifier, mais ce n’est qu’une option.

Toutefois dans l’idée qu’on se fait d’un “login” il y a quelque chose de plus radical.

A l’heure actuelle le scénario exact du Login n’est pas tout à fait pris en charge automatiquement par Shell. Ainsi vous pouvez utiliser la méthode usuelle qui consiste à faire pointer le App.MainPage d’abord sur la page de login puis en cas de succès de modifier à nouveau App.MainPage pour enfin la faire pointer sur votre Shell. Ainsi la mage de Login n’apparait ni dans le Shell, ni même dans les routes “secondaires” et encore moins dans l’historique de navigation ce qui évite qu’un Back ne fasse revenir à cette page.

La capture ci-dessous montre le lancement du Shell via MainPage dans App.Xaml. C’est ici qu’on peut débuter par un “new Login()” qui lui-même en cas de succès affectera “new MainShell()” à MainPage :

image

Mais on peut aussi utiliser le système de navigation classique qui se cache derrière Shell pour faire apparaître des pages hors Shell de façon modale par exemple.

On utilisera alors Shell.Current.Navigation.PushModalAsync(new Login());

Cela ne s’applique pas seulement aux pages de login bien entendu et chacun utilisera ces techniques en fonction du contexte de l’App qu’il développe.

La navigation arrière en mode modal est assez simple : Shell.Current.Navigation.PopModalAsync();

L’avantage du modal c’est que la page ne montrera pas de bouton  Back comme dans l’exemple précédent.

Conclusion de la partie 3

Voilà comment utiliser le routage dans vos applications Xamarin.Forms à l'aide du nouveau Shell. Il reste encore beaucoup de choses à couvrir sur ce nouveau paradigme de navigation comme savoir transmettre des données lors de la navigation à l'aide de cette technique de routage et comment procéder à certaines personnalisations pour améliorer l'apparence de notre application, mais à chaque jour suffit sa peine… Gardons-en pour la partie 4 !

Alors forcément…

Stay Tuned !

blog comments powered by Disqus