Partager via


Navigation

Conseil

Ce contenu est un extrait du livre électronique Modèles d’application d’entreprise avec .NET MAUI, disponible dans la .documentation .NET ou en tant que PDF téléchargeable gratuitement qui peut être lu hors connexion.

Miniature de la couverture du livre électronique Enterprise Application Patterns Using .NET MAUI.

.NET MAUI inclut la prise en charge de la navigation basée sur des pages, qui résulte généralement de l’interaction de l’utilisateur avec l’IU, ou de l’application elle-même à la suite de changements d’état internes pilotés par la logique. Toutefois, la navigation peut être complexe à implémenter dans les applications qui utilisent le modèle MVVM (modèle-vue-vue modèle), car les difficultés suivantes doivent être aplanies :

  • Identifier la vue vers laquelle naviguer à l’aide d’une approche qui n’introduit pas de couplage étroit ni de dépendances entre les vues.
  • Coordonner le processus d’instanciation et d’initialisation de la vue vers laquelle naviguer. Quand vous utilisez MVVM, la vue et le modèle de vue doivent être instanciés et associés via le contexte de liaison de la vue. Quand une application utilise un conteneur d’injection de dépendances, l’instanciation des vues et des modèles de vue peut nécessiter un mécanisme de construction spécifique.
  • Choisir entre la navigation basée sur la vue en premier ou la navigation basée sur le modèle de vue en premier. Avec la navigation basée sur la vue en premier, la page cible de la navigation fait référence au nom du type de vue. Durant la navigation, la vue spécifiée est instanciée ainsi que le modèle de vue correspondant et les autres services dépendants. Une autre approche consiste à utiliser la navigation basée sur le modèle de vue en premier, où la page cible de la navigation fait référence au nom du type de modèle de vue.
  • Déterminer comment séparer clairement le comportement de navigation de l’application entre les vues et les modèles de vue. Le modèle MVVM sépare l’IU de l’application, sa présentation et sa logique métier, mais il ne fournit pas de mécanisme direct pour les lier. Toutefois, le comportement de navigation d’une application couvre souvent l’IU et les parties de présentation de l’application. L’utilisateur lance souvent la navigation à partir d’une vue, laquelle est remplacée à la suite de la navigation. Néanmoins, la navigation doit souvent également être lancée ou coordonnée à partir du modèle de vue.
  • Déterminer comment passer des paramètres durant la navigation à des fins d’initialisation. Par exemple, si l’utilisateur accède à une vue pour mettre à jour les détails d’une commande, les informations relatives à la commande doivent être passées à la vue pour qu’elle puisse afficher les données appropriées.
  • Coordonner la navigation pour garantir le respect de règles métier spécifiques. Par exemple, avant de quitter une vue, les utilisateurs peuvent être invités à corriger les données non valides, ou à envoyer ou abandonner les changements apportés aux données dans la vue.

Ce chapitre lève ces difficultés en présentant une classe de service de navigation nommée MauiNavigationService, qui permet d’effectuer une navigation parmi les pages à partir du modèle de vue en premier.

Notes

Le MauiNavigationService utilisé par l’application est simpliste et ne couvre pas tous les types de navigation possibles. Les types de navigation nécessaires à votre application peuvent nécessiter des fonctionnalités supplémentaires.

La logique de navigation peut résider dans le code-behind d’une vue ou dans un modèle de vue lié aux données. Bien que le placement de la logique de navigation dans une vue soit l’approche la plus simple, elle n’est pas facile à tester via des tests unitaires. Le fait de placer la logique de navigation dans des classes de modèle de vue signifie que la logique peut être testée via des tests unitaires. De plus, le modèle de vue peut ensuite implémenter une logique pour contrôler la navigation et garantir l’application de certaines règles métier. Par exemple, une application peut interdire à l’utilisateur de quitter une page tant que la validité des données entrées n’a pas été vérifiée.

Un service de navigation est généralement appelé à partir de modèles de vue pour promouvoir la testabilité. Toutefois, la navigation vers les vues à partir de modèles de vue oblige les modèles de vue à référencer les vues, en particulier celles auxquelles le modèle de vue actif n’est pas associé, ce qui n’est pas recommandé. Ainsi, le MauiNavigationService présenté ici spécifie le type de modèle de vue en tant que cible de navigation.

L’application multiplateforme eShop utilise la classe MauiNavigationService pour fournir une navigation basée sur le modèle de vue en premier. Cette classe implémente l’interface INavigationService, comme le montre l’exemple de code suivant :

public interface INavigationService
{
    Task InitializeAsync();

    Task NavigateToAsync(string route, IDictionary<string, object> routeParameters = null);

    Task PopAsync();
}

Cette interface spécifie qu’une classe d’implémentation doit fournir les méthodes suivantes :

Méthode Objectif
InitializeAsync Effectue la navigation vers une page au choix parmi deux au lancement de l’application.
NavigateToAsync(string route, IDictionary<string, object> routeParameters = null) Effectue une navigation hiérarchique vers une page spécifique à l’aide d’une route de navigation inscrite. Peut éventuellement passer des paramètres de route nommés à utiliser pour le traitement dans la page de destination
PopAsync Supprime la page active de la pile de navigation.

Notes

Une interface INavigationService spécifie également une méthode GoBackAsync, qui permet de retourner par programmation à la page précédente dans la pile de navigation. Toutefois, cette méthode ne figure pas dans l’application multiplateforme eShop, car elle n’est pas obligatoire.

Création de l’instance de MauiNavigationService

La classe MauiNavigationService, qui implémente l’interface INavigationService, est inscrite en tant que singleton auprès du conteneur d’injection de dépendances dans la méthode MauiProgram.CreateMauiApp(), comme le montre l’exemple de code suivant :

mauiAppBuilder.Services.AddSingleton<INavigationService, MauiNavigationService>();;

Vous pouvez ensuite résoudre l’interface INavigationService en l’ajoutant au constructeur de nos vues et de nos modèles de vue, comme le montre l’exemple de code suivant :

public AppShell(INavigationService navigationService)

Cela retourne une référence à l’objet MauiNavigationService stocké dans le conteneur d’injection de dépendances.

La classe ViewModelBase stocke l’instance de MauiNavigationService dans une propriété NavigationService, de type INavigationService. Ainsi, toutes les classes de modèle de vue, qui dérivent de la classe ViewModelBase, peuvent utiliser la propriété NavigationService pour accéder aux méthodes spécifiées par l’interface INavigationService.

Gestion des requêtes de navigation

.NET MAUI offre plusieurs façons de naviguer dans une application. La méthode classique consiste à utiliser la classe NavigationPage, qui implémente une expérience de navigation hiérarchique dans laquelle l’utilisateur peut naviguer parmi les pages, en avant et en arrière, comme il le souhaite. L’application eShop utilise le composant Shell en tant que conteneur racine de l’application et en tant qu’hôte de navigation. Pour plus d’informations sur la navigation Shell, consultez Navigation Shell dans le Centre des développeurs Microsoft.

La navigation s’effectue dans les classes de modèle de vue via l’appel de l’une des méthodes NavigateToAsync, en spécifiant le chemin de routage de la page cible de la navigation, comme le montre l’exemple de code suivant :

await NavigationService.NavigateToAsync("//Main");

L’exemple de code suivant montre la méthode NavigateToAsync fournie par la classe MauiNavigationService :

public Task NavigateToAsync(string route, IDictionary<string, object> routeParameters = null)
{
    return
        routeParameters != null
            ? Shell.Current.GoToAsync(route, routeParameters)
            : Shell.Current.GoToAsync(route);
}

Le contrôle .NET MAUIShell connaît déjà la navigation basée sur le routage, la méthode NavigateToAsync permet donc de masquer cette fonctionnalité. La méthode NavigateToAsync permet de spécifier les données de navigation sous forme d’argument passé au modèle de vue cible de la navigation, où ces données sont généralement utilisées pour effectuer l’initialisation. Pour plus d’informations, consultez Passage de paramètres durant la navigation.

Important

Il existe plusieurs façons d’effectuer la navigation dans .NET MAUI. MauiNavigationService est spécifiquement conçu pour fonctionner avec Shell. Si vous utilisez le mécanisme de navigation NavigationPage ou TabbedPage, ou un autre mécanisme de navigation, ce service de routage doit être mis à jour pour fonctionner avec les composants.

Afin d’inscrire les routes pour MauiNavigationService, nous devons fournir les informations de route à partir du code XAML ou dans le fichier code-behind. L’exemple suivant montre l’inscription des routes via du code XAML.

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:views="clr-namespace:eShop.Views"
    x:Class="eShop.AppShell">

    <!-- Omitted for brevity -->

    <FlyoutItem >
        <ShellContent x:Name="login" ContentTemplate="{DataTemplate views:LoginView}" Route="Login" />
    </FlyoutItem>

    <TabBar x:Name="main" Route="Main">
        <ShellContent Title="CATALOG" Route="Catalog" Icon="{StaticResource CatalogIconImageSource}" ContentTemplate="{DataTemplate views:CatalogView}" />
        <ShellContent Title="PROFILE" Route="Profile" Icon="{StaticResource ProfileIconImageSource}" ContentTemplate="{DataTemplate views:ProfileView}" />
    </TabBar>
</Shell>

Dans cet exemple, les objets d’interface utilisateur ShellContent et TabBar définissent leur propriété Route. Il s’agit de la méthode recommandée pour inscrire les routes des objets d’interface utilisateur contrôlés par un Shell.

Si nous avons des objets à ajouter à la pile de navigation plus tard, nous devons les ajouter via le code-behind. L’exemple suivant montre l’inscription des routes dans le code-behind.

Routing.RegisterRoute("Filter", typeof(FiltersView));
Routing.RegisterRoute("Basket", typeof(BasketView));

Dans le code-behind, nous appelons la méthode Routing.RegisterRoute qui accepte un nom de route en tant que premier paramètre et un type de vue en tant que deuxième paramètre. Quand un modèle de vue utilise la propriété NavigationService pour naviguer, l’objet Shell de l’application recherche les routes inscrites et les envoie vers la pile de navigation.

Une fois que la vue a été créée et utilisée en tant que cible de navigation, les méthodes ApplyQueryAttributes et InitializeAsync du modèle de vue associé à la vue sont exécutées. Pour plus d’informations, consultez Passage de paramètres durant la navigation.

Au lancement de l’application, un objet Shell est défini en tant que vue racine de l’application. Une fois défini, Shell est utilisé pour contrôler l’inscription de la route et est désormais présent à la racine de notre application. Une fois le Shell créé, nous pouvons attendre qu’il soit attaché à l’application à l’aide de la méthode OnParentSet pour initialiser notre route de navigation. L’exemple de code suivant illustre cette méthode :

protected override async void OnParentSet()
{
    base.OnParentSet();

    if (Parent is not null)
    {
        await _navigationService.InitializeAsync();
    }
}

La méthode utilise une instance de INavigationService, à qui le constructeur fournit l’injection de dépendances, puis appelle sa méthode InitializeAsync.

L’exemple de code suivant montre l’implémentation de la méthode MauiNavigationService.InitializeAsync :

public Task InitializeAsync()
{
    return NavigateToAsync(string.IsNullOrEmpty(_settingsService.AuthAccessToken)
        ? "//Login"
        : "//Main/Catalog");
}

La route //Main/Catalog est la cible de navigation si l’application dispose d’un jeton d’accès en cache, qui est utilisé pour l’authentification. Sinon, la route //Login correspond à la cible de navigation.

Passage de paramètres durant la navigation

La méthode NavigateToAsync, désignée par l’interface INavigationService, permet de spécifier les données de navigation sous la forme d’un IDictionary<string, object> de données passées au modèle de vue cible de la navigation, où elles sont généralement utilisées pour effectuer l’initialisation.

Par exemple, la classe ProfileViewModel contient un OrderDetailCommand qui s’exécute quand l’utilisateur sélectionne une commande dans la page ProfileView. En retour, cela entraîne l’exécution de la méthode OrderDetailAsync, comme le montre l’exemple de code suivant :

private async Task OrderDetailAsync(Order order)
{
    if (order is null)
    {
        return;
    }

    await NavigationService.NavigateToAsync(
        "OrderDetail",
        new Dictionary<string, object>{ { "OrderNumber", order.OrderNumber } });
}

Cette méthode appelle la navigation jusqu’à la route OrderDetail, en passant les informations du numéro de commande correspondant à la commande sélectionnée par l’utilisateur. Quand le framework d’injection de dépendances crée OrderDetailView pour la route OrderDetail avec la classe OrderDetailViewModel, qui est affectée au BindingContext de la vue. Un attribut est ajouté à OrderDetailViewModel, ce qui lui permet de recevoir des données du service de navigation, comme le montre l’exemple de code ci-dessous.

[QueryProperty(nameof(OrderNumber), "OrderNumber")]
public class OrderDetailViewModel : ViewModelBase
{
    public int OrderNumber { get; set; }
}

L’attribut QueryProperty nous permet de fournir un paramètre de propriété auquel mapper les valeurs ainsi qu’une clé pour rechercher les valeurs dans le dictionnaire des paramètres de requête. Dans cet exemple, la clé « OrderNumber » et la valeur du numéro de commande ont été fournies durant l’appel de NavigateToAsync. Le modèle de vue a trouvé la clé « OrderNumber » et a mappé la valeur à la propriété OrderNumber. La propriété OrderNumber peut ensuite être utilisée plus tard pour récupérer les détails complets de la commande à partir de l’instance de OrderService.

Appel de la navigation à l’aide de comportements

La navigation est généralement déclenchée à partir d’une vue par une interaction utilisateur. Par exemple, LoginView effectue la navigation après une authentification réussie. L’exemple de code suivant montre comment la navigation est appelée par un comportement :

<WebView>
    <WebView.Behaviors>
        <behaviors:EventToCommandBehavior
            EventName="Navigating"
            EventArgsConverter="{StaticResource WebNavigatingEventArgsConverter}"
            Command="{Binding NavigateCommand}" />
    </WebView.Behaviors>
</WebView>

Au moment de l’exécution, le EventToCommandBehavior répond à l’interaction avec le WebView. Quand WebView accède à une page web, l’événement Navigating se déclenche, ce qui entraîne l’exécution de NavigateCommand dans le LoginViewModel. Par défaut, les arguments d’événement de l’événement sont passés à la commande. Ces données sont converties au fur et à mesure qu’elles sont passées entre la source et la cible par le convertisseur spécifié dans la propriété EventArgsConverter, qui retourne Url à partir de WebNavigatingEventArgs. Ainsi, quand NavigationCommand est exécuté, le Url de la page web est passé en tant que paramètre à l’action inscrite.

En retour, NavigationCommand exécute la méthode NavigateAsync, comme le montre l’exemple de code suivant :

private async Task NavigateAsync(string url)
{
    // Omitted for brevity.
    if (!string.IsNullOrWhiteSpace(accessToken))
    {
        _settingsService.AuthAccessToken = accessToken;
        _settingsService.AuthIdToken = authResponse.IdentityToken;
        await NavigationService.NavigateToAsync("//Main/Catalog");
    }
}

Cette méthode appelle NavigationService pour router l’application vers la route //Main/Catalog.

Confirmation ou annulation de la navigation

Une application peut être amenée à interagir avec l’utilisateur durant une opération de navigation pour permettre à l’utilisateur de confirmer ou d’annuler la navigation. Cela peut s’avérer nécessaire, par exemple, quand l’utilisateur tente de naviguer avant d’avoir complètement rempli une page d’entrée de données. Dans ce cas, l’application doit fournir une notification qui permet à l’utilisateur de quitter la page, ou d’annuler l’opération de navigation avant qu’elle n’ait lieu. Pour ce faire, utilisez la réponse d’une notification dans une classe de modèle de vue afin de contrôler si la navigation est appelée ou non.

Résumé

.NET MAUI inclut la prise en charge de la navigation basée sur des pages, qui résulte généralement de l’interaction de l’utilisateur avec l’IU, ou de l’application elle-même, à la suite de changements d’état internes pilotés par la logique. Toutefois, la navigation peut être complexe à implémenter dans les applications qui utilisent le modèle MVVM.

Ce chapitre a présenté la classe NavigationService, qui permet d’effectuer une navigation basée sur le modèle de vue en premier à partir de modèles de vue. Le fait de placer la logique de navigation dans des classes de modèle de vue signifie que la logique peut être testée via des tests automatisés. De plus, le modèle de vue peut ensuite implémenter une logique pour contrôler la navigation et garantir l’application de certaines règles métier.