Partage via


NavigationView

Le contrôle NavigationView garantit une navigation de niveau supérieur à votre application. Il s’adapte à un large éventail de tailles d’écran et prend en charge les styles de navigation supérieure et gauche.

navigation par le hautnavigation par la gauche
NavigationView prend en charge le panneau ou menu de navigation en mode haut ou gauche

Est-ce le contrôle approprié ?

NavigationView est un contrôle de navigation adaptatif très efficace pour les tâches suivantes :

  • La fourniture d’une expérience de navigation cohérente dans toute votre application.
  • La conservation de l’espace de l’écran des fenêtres de plus petite taille.
  • La gestion de l’accès à de nombreuses catégories de navigation.

Pour visualiser d’autres modèles de navigation, voir Informations de base relatives à la conception de la navigation.

UWP et WinUI 2

Important

Les informations et les exemples de cet article sont optimisés pour les applications qui utilisent le SDK d'application Windows et WinUI 3, mais qui s’appliquent généralement aux applications UWP qui utilisent WinUI 2. Consultez la référence API de la plateforme Windows universelle pour obtenir des informations et des exemples spécifiques à la plateforme.

Cette section contient les informations dont vous avez besoin pour utiliser le contrôle dans une application de la plateforme Windows universelle ou de WinUI 2.

Le contrôle NavigationView pour les applications UWP est inclus dans WinUI 2. Pour plus d’informations, notamment des instructions d’installation, consultez WinUI 2. Les API de ce contrôle existent dans les espaces de noms Windows.UI.Xaml.Controls et Microsoft.UI.Xaml.Controls .

Nous vous recommandons d’utiliser la dernière version de WinUI 2 pour obtenir les styles, modèles et fonctionnalités les plus récents pour tous les contrôles. Certaines fonctionnalités de NavigationView, par exemple la navigation supérieure et hiérarchique, nécessitent Windows 10, version 1809 (SDK 17763) ou version ultérieure, ou WinUI 2.

Pour utiliser le code de cet article avec WinUI 2, utilisez un alias en XAML (nous utilisons muxc) pour représenter les API de bibliothèque d’interface utilisateur Windows incluses dans votre projet. Consultez Bien démarrer avec WinUI 2 pour plus d’informations.

xmlns:muxc="using:Microsoft.UI.Xaml.Controls"

<muxc:NavigationView />

Créer un affichage de navigation

L’application WinUI 3 Gallery comprend des exemples interactifs de la plupart des contrôles et des fonctionnalités WinUI 3. Procurez-vous l’application sur le Microsoft Store ou le code source sur GitHub.

Cet exemple montre comment créer un affichage de navigation simple en XAML.

<NavigationView>
    <NavigationView.MenuItems>
        <NavigationViewItem Content="Nav Item A"/>
        <NavigationViewItem Content="Nav Item B"/>
        <NavigationViewItem Content="Nav Item C"/>
    </NavigationView.MenuItems>

    <Frame x:Name="ContentFrame"/>
</NavigationView>

Modes d’affichage

Vous pouvez utiliser la propriété PaneDisplayMode pour configurer différents styles de navigation, ou modes d’affichage, pour NavigationView.

Haut

Le volet est positionné au-dessus du contenu.
PaneDisplayMode="Top"

Exemple de navigation supérieure

Nous vous recommandons la navigation supérieure dans les cas suivants :

  • Vous avez au moins 5 catégories de navigation de niveau supérieur d’égale importance, et toute autre catégorie de navigation de niveau supérieur qui se retrouve dans le menu déroulant de dépassement est considérée comme moins importante.
  • Vous devez afficher toutes les options de navigation à l’écran.
  • Vous souhaitez davantage d’espace pour le contenu de votre application.
  • Les icônes ne peuvent pas décrire clairement les catégories de navigation de votre application.

Gauche

Le volet est développé et positionné à gauche du contenu.
PaneDisplayMode="Left"

Exemple de volet de navigation à gauche développé

Nous vous recommandons la navigation à gauche dans les cas suivants :

  • Vous avez 5 à 10 catégories de navigation de niveau supérieur de même importance.
  • Vous voulez faire ressortir les catégories de navigation, en laissant moins d'espace aux autres contenus de l'application.

LeftCompact

Le volet affiche les icônes jusqu'à ce qu'il soit ouvert et positionné à gauche du contenu. Lorsqu’il est ouvert, le volet superpose le contenu.
PaneDisplayMode="LeftCompact"

Exemple de volet de navigation à gauche réduit

LeftMinimal

Seul le bouton de menu est affiché jusqu'à ce que le volet s’ouvre. Lorsqu’il est ouvert, le volet superpose le côté gauche du contenu.
PaneDisplayMode="LeftMinimal"

Exemple de volet de navigation à gauche minimal

Auto

Par défaut, la propriété PaneDisplayMode est définie sur Auto. En mode Auto, NavigationView passe du mode LeftMinimal quand la fenêtre est étroite, au mode LeftCompact, puis Left quand la fenêtre s’élargit. Pour en savoir plus, voir la section Comportement adaptatif.

Comportement adaptatif par défaut de la navigation à gauche
Comportement adaptatif par défaut de NavigationView

Anatomie

Ces images montrent la disposition du volet, de l’en-tête et des zones de contenu du contrôle avec une configuration de navigation supérieure ou à gauche.

Disposition supérieure de NavigationView
Disposition de la navigation supérieure

Disposition à gauche de NavigationView
Disposition de la navigation à gauche

Volet

Vous pouvez utiliser la propriété PaneDisplayMode pour positionner le volet au-dessus ou à gauche du contenu.

Le volet NavigationView peut contenir :

Le volet gauche contient également les éléments suivants :

  • Un bouton de menu pour activer/désactiver le volet ouvert et fermé. Sur les grandes fenêtres d’application lorsque le volet est ouvert, vous pouvez choisir de masquer ce bouton à l’aide de la propriété IsPaneToggleButtonVisible.

NavigationView affiche un bouton Précédent placé dans le coin supérieur gauche du volet. Mais elle ne gère pas automatiquement la navigation vers l’arrière et n'ajoute aucun contenu à la pile arrière. Pour activer la navigation vers l’arrière, consultez la section Navigation vers l’arrière.

Voici l’anatomie du volet détaillé pour les positions du volet de navigation supérieure et à gauche.

Volet de navigation supérieure

Anatomie du volet supérieur de NavigationView

  1. En-têtes
  2. Éléments de navigation
  3. Séparateurs
  4. AutoSuggestBox (facultatif)
  5. Bouton Paramètres (facultatif)

Volet de navigation à gauche

Anatomie du volet gauche de NavigationView

  1. Bouton Menu
  2. Éléments de navigation
  3. Séparateurs
  4. En-têtes
  5. AutoSuggestBox (facultatif)
  6. Bouton Paramètres (facultatif)

Vous pouvez utiliser FooterMenuItems pour placer des éléments de navigation à la fin du volet de navigation, à l’inverse de la propriété MenuItems qui place des éléments au début du volet.

Par défaut, FooterMenuItems s’affiche avant l’élément Settings. L’élément Settings peut toujours être activé/désactivé à l’aide de la propriété IsSettingsVisible.

Seuls les éléments de navigation doivent être placés dans FooterMenuItems : tout autre contenu qui doit être aligné sur le pied de page du volet doit être placé dans Footer menu items.

Pour obtenir un exemple d’ajout de FooterMenuItems à votre NavigationView, consultez la classe FooterMenuItems.

L’image ci-dessous montre un contrôle NavigationView avec les éléments de navigation Compte, Votre panier et Aide dans le menu de pied de page.

NavigationView avec FooterMenuItems

Vous pouvez placer un contenu de forme libre dans le pied de page du volet en l’ajoutant à la propriété PaneFooter.

Navigation supérieure du pied de page du volet
Pied de page du volet supérieur

Pied de page du volet de navigation à gauche
Pied de page du volet gauche

Titre et en-tête du volet

Vous pouvez placer le contenu textuel dans la zone d'en-tête du volet en définissant la propriété PaneTitle. Cette propriété prend une chaîne et affiche le texte en regard du bouton de menu.

Pour ajouter du contenu non textuel, comme une image ou un logo, vous pouvez placer n'importe quel élément dans l'en-tête du volet en l'ajoutant à la propriété PaneHeader.

Si les propriétés PaneTitle et PaneHeader sont définies, le contenu est empilé horizontalement à côté du bouton de menu, la propriété PaneTitle étant la plus proche du bouton de menu.

En-tête du volet de navigation supérieure
En-tête du volet supérieur

En-tête du volet de navigation à gauche
En-tête du volet gauche

Contenu du volet

Vous pouvez placer un contenu de forme libre dans le volet en l’ajoutant à la propriété PaneCustomContent.

Contenu personnalisé du volet de navigation supérieure
Contenu personnalisé du volet supérieur

Contenu personnalisé du volet de navigation à gauche
Contenu personnalisé du volet gauche

Vous pouvez ajouter un titre de page en définissant la propriété Header.

Exemple de zone d’en-tête de NavigationView
En-tête NavigationView

La zone d'en-tête est alignée verticalement avec le bouton de navigation dans la position du volet gauche et se trouve sous le volet dans la position du volet supérieur. Elle affiche une hauteur fixe de 52 px. Elle contient le titre de la page de la catégorie de navigation sélectionnée. L’en-tête est ancré sur le haut de la page et se comporte comme un point de découpage de défilement pour la zone de contenu.

L'en-tête est visible chaque fois que NavigationView est en mode Minimal. Vous pouvez choisir de masquer l’en-tête dans les autres modes, utilisés pour des fenêtres de largeur supérieure. Pour masquer l’en-tête, définissez la propriété AlwaysShowHeader sur false.

Contenu

Exemple de zone de contenu de NavigationView
Contenu de NavigationView

La zone de contenu est l’endroit où la plupart des informations relatives à la catégorie de navigation sélectionnée sont affichées.

Nous recommandons des marges de 12 px pour votre zone de contenu lorsque NavigationView est en mode Minimal, et des marges de 24 px dans les autres cas.

Comportement adaptatif

Par défaut, le mode d’affichage de NavigationView change automatiquement selon la quantité d’espace d’écran à sa disposition. Les propriétés CompactModeThresholdWidth et ExpandedModeThresholdWidth indiquent les points d’arrêt où le mode d'affichage change. Vous pouvez modifier ces valeurs pour personnaliser le comportement du mode d’affichage adaptatif.

Par défaut

Lorsque la propriété PaneDisplayMode est définie sur sa valeur par défaut Auto, le comportement adaptatif consiste à afficher :

  • Un volet gauche développé sur les fenêtres de grande largeur (1008 px ou supérieur).
  • Un volet de navigation gauche (LeftCompact) comportant uniquement des icônes sur les fenêtres de largeur moyenne (641 px à 1007 px).
  • Uniquement un bouton de menu (LeftMinimal) sur les fenêtres de petite largeur (640 px ou moins).

Pour plus d'informations sur les tailles de fenêtre pour un comportement adaptatif, consultez Tailles d’écran et points d’arrêt.

Comportement adaptatif par défaut de la navigation à gauche
Comportement adaptatif par défaut de NavigationView

Minimal

Un deuxième modèle adaptatif courant consiste à utiliser un volet gauche étendu sur les fenêtres de grande largeur, et uniquement un bouton de menu sur les fenêtres de moyenne et petite largeurs.

Ce modèle est recommandé dans les cas suivants :

  • Vous voulez plus d'espace pour le contenu de l'application sur les fenêtres de plus petite largeur.
  • Vos catégories de navigation ne peuvent pas être clairement représentées par des icônes.

Comportement adaptatif minimal de la navigation à gauche
Comportement adaptatif « minimal » de NavigationView

Pour configurer ce comportement, définissez CompactModeThresholdWidth sur la largeur à laquelle vous voulez que le volet se réduise. Ici, la taille passe de la valeur par défaut 640 à 1007. Vous devez également définir ExpandedModeThresholdWidth pour vous assurer que les valeurs n’entrent pas en conflit.

<NavigationView CompactModeThresholdWidth="1007" ExpandedModeThresholdWidth="1007"/>

Compact

Un troisième modèle adaptatif courant consiste à utiliser un volet gauche étendu sur les fenêtres de grande largeur, et un volet de navigation à icônes uniquement (LeftCompact) sur les fenêtres de moyenne et petite largeurs.

Ce modèle est recommandé dans les cas suivants :

  • Il est important de toujours afficher toutes les options de navigation à l’écran.
  • Vos catégories de navigation peuvent être clairement représentées par des icônes.

Comportement adaptatif compact de la navigation à gauche
Comportement adaptatif « compact » de NavigationView

Pour configurer ce comportement, définissez CompactModeThresholdWidth sur 0.

<NavigationView CompactModeThresholdWidth="0"/>

Aucun comportement adaptatif

Pour désactiver le comportement adaptatif automatique, définissez PaneDisplayMode sur une valeur autre que Auto. Ici, la valeur est définie sur LeftMinimal afin d’afficher uniquement le bouton de menu, quelle que soit la largeur de la fenêtre.

Comportement non adaptatif de la navigation à gauche
NavigationView avec PaneDisplayMode défini sur LeftMinimal

<NavigationView PaneDisplayMode="LeftMinimal" />

Comme décrit précédemment dans la section Modes d’affichage, vous pouvez définir le volet afin qu’il soit toujours visible, toujours développé, toujours compact ou toujours minimal. Vous pouvez également gérer les modes d’affichage vous-même dans le code de votre application. Vous trouverez un exemple dans la prochaine section.

Navigation du haut vers la gauche

Lorsque vous utilisez la navigation supérieure dans votre application, les éléments de navigation se réduisent en un menu de dépassement à mesure que la largeur de la fenêtre diminue. Lorsque la fenêtre de votre application est étroite, il est possible d'améliorer l'expérience de l'utilisateur en faisant passer le mode PaneDisplayMode de la navigation Top à LeftMinimal, plutôt que de laisser tous les éléments se réduire dans le menu de dépassement de capacité.

Nous recommandons d'utiliser la navigation supérieure pour les grandes fenêtres, et la navigation par la gauche pour les petites fenêtres dans les cas suivants :

  • Vous utilisez un groupe de catégories de navigation de niveau supérieur de même importance à afficher ensemble, de sorte que si une catégorie de ce groupe ne rentre pas dans l'écran, vous la réduisez avec la navigation à gauche pour lui donner la même importance.
  • Vous souhaitez conserver autant d'espace de contenu que possible dans les fenêtres de petite taille.

Cet exemple montre comment utiliser des propriétés VisualStateManager et AdaptiveTrigger.MinWindowWidth pour basculer entre la navigation Top et LeftMinimal.

Exemple 1 de comportement adaptatif supérieur ou à gauche

<Grid>
    <NavigationView x:Name="NavigationViewControl" >
        <NavigationView.MenuItems>
            <NavigationViewItem Content="A" x:Name="A" />
            <NavigationViewItem Content="B" x:Name="B" />
            <NavigationViewItem Content="C" x:Name="C" />
        </NavigationView.MenuItems>
    </NavigationView>

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState>
                <VisualState.StateTriggers>
                    <AdaptiveTrigger
                        MinWindowWidth="{x:Bind NavigationViewControl.CompactModeThresholdWidth}" />
                </VisualState.StateTriggers>

                <VisualState.Setters>
                    <Setter Target="NavigationViewControl.PaneDisplayMode" Value="Top"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

Conseil

Lorsque vous utilisez AdaptiveTrigger.MinWindowWidth, l'état visuel est déclenché lorsque la fenêtre est plus large que la largeur minimale spécifiée. Cela signifie que la valeur XAML par défaut définit la fenêtre étroite, et que la valeur VisualState définit les modifications appliquées lorsque la fenêtre s'élargit. La propriété PaneDisplayMode par défaut pour NavigationView est Auto. Par conséquent, quand la largeur de la fenêtre est inférieure ou égale à CompactModeThresholdWidth, la navigation LeftMinimal est utilisée. Lorsque la fenêtre s'élargit, VisualState prend le pas sur la valeur par défaut et la navigation Top est utilisée.

NavigationView n’effectue aucune tâche de navigation automatiquement. Quand l’utilisateur appuie sur un élément de navigation, NavigationView montre cet élément comme étant sélectionné et déclenche un événement ItemInvoked. Si l’appui entraîne la sélection d’un nouvel élément, l’événement SelectionChanged est également déclenché.

Vous pouvez gérer l'un ou l'autre événement pour effectuer des tâches liées à la navigation demandée. Celui que vous devez gérer dépend du comportement que vous voulez appliquer à votre application. En règle générale, vous naviguez jusqu’à la page demandée, puis mettez à jour l’en-tête NavigationView en réponse à ces événements.

  • ItemInvoked est déclenché chaque fois que l’utilisateur appuie sur un élément de navigation, même s’il est déjà sélectionné. (L’élément peut également être appelé avec une action équivalente à l’aide de la souris, du clavier ou d’une autre entrée. Pour plus d’informations, consultez Entrée et interactions.) Si vous naviguez dans le gestionnaire ItemInvoked, par défaut, la page est rechargée et une entrée en double est ajoutée à la pile de navigation. Si vous naviguez lorsqu'un élément est invoqué, vous devez empêcher le rechargement de la page ou vous assurer qu'une entrée en double n'est pas créée dans le backstack de navigation lorsque la page est rechargée. (Voir les exemples de code.)
  • SelectionChanged peut être déclenché par un utilisateur invoquant un élément qui n'est pas actuellement sélectionné, ou en modifiant par programmation l'élément sélectionné. Si le changement de sélection se produit parce qu'un utilisateur a invoqué un élément, l'événement ItemInvoked se produit en premier. Si la modification de la sélection s’effectue par programmation, ItemInvoked n’est pas déclenché.

Tous les éléments de navigation font partie du même modèle de sélection, qu’ils soient membres de MenuItems ou de FooterMenuItems. Un seul élément de navigation peut être sélectionné à la fois.

Navigation vers l’arrière

NavigationView intègre un bouton précédent ; mais, comme pour la navigation vers l'avant, il n'effectue pas automatiquement la navigation vers l'arrière. Lorsque l’utilisateur actionne le bouton précédent, l’événement BackRequested est déclenché. Vous gérez cet événement pour effectuer la navigation vers l’arrière. Pour obtenir plus d’informations et des exemples de code, consultez l’article Historique de navigation et navigation vers l’arrière.

En mode Minimal ou Compact, la NavigationView Pane est ouverte comme un menu volant. Dans ce cas, vous pouvez cliquer sur le bouton précédent pour fermer le Pane et afficher l'événement PaneClosing à la place.

Vous pouvez masquer ou désactiver le bouton précédent en définissant ces propriétés :

  • IsBackButtonVisible: pour afficher et masquer le bouton précédent. Cette propriété prend une valeur de l'énumération NavigationViewBackButtonVisible, qui est définie sur Auto par défaut. Lorsque le bouton est réduit, aucun espace n’est réservé pour celui-ci dans la disposition.
  • IsBackEnabled: activer ou désactiver le bouton précédent. Vous pouvez lier les données de cette propriété à la propriété CanGoBack de votre cadre de navigation. BackRequested n’est pas déclenché si IsBackEnabled est défini sur false.

Bouton précédent de NavigationView dans le volet de navigation gauche
Bouton précédent dans le volet de navigation gauche

Bouton précédent de NavigationView dans le volet de navigation supérieur
Bouton précédent dans le volet de navigation supérieur

Exemple de code

Cet exemple montre comment utiliser NavigationView avec un volet de navigation supérieur sur de grandes fenêtres et un volet de navigation à gauche sur les petites fenêtres. Il peut être adapté à la navigation à gauche uniquement en supprimant les paramètres de navigation supérieure dans le VisualStateManager.

L’exemple montre une façon courante de configurer les données de navigation qui fonctionnera dans de nombreux cas. Dans cet exemple, vous commencez par enregistrer (dans la balise de NavigationViewItem) le nom complet de la page vers laquelle vous souhaitez naviguer. Dans le gestionnaire d’événement, vous décompressez cette valeur, la transformez en objet Type(C#) ou Windows::UI::Xaml::Interop::TypeName(C++/WinRT), et l’utilisez pour naviguer jusqu’à la page de destination. Cela vous permet de créer des tests unitaires pour vérifier que les valeurs à l’intérieur de vos balises sont d’un type valide. (Voir aussi Boxing et unboxing de valeurs vers IInspectable avec C++/WinRT). Il montre également comment implémenter la navigation à rebours avec le bouton retour de NavigationView.

Ce code suppose que votre application contient des pages avec les noms suivants pour accéder à ces éléments : HomePage, AppsPage, GamesPage, MusicPage, MyContentPage et SettingsPage. Le code de ces pages n’est pas affiché.

<Page ... >
 <Grid>
     <NavigationView x:Name="NavView"
                     Loaded="NavView_Loaded"
                     ItemInvoked="NavView_ItemInvoked"
                     BackRequested="NavView_BackRequested">
         <NavigationView.MenuItems>
             <NavigationViewItem Tag="NavigationViewDemo.HomePage" Icon="Home" Content="Home"/>
             <NavigationViewItemSeparator/>
             <NavigationViewItemHeader x:Name="MainPagesHeader"
                                       Content="Main pages"/>
             <NavigationViewItem Tag="NavigationViewDemo.AppsPage" Content="Apps">
                 <NavigationViewItem.Icon>
                     <FontIcon Glyph="&#xEB3C;"/>
                 </NavigationViewItem.Icon>
             </NavigationViewItem>
             <NavigationViewItem Tag="NavigationViewDemo.GamesPage" Content="Games">
                 <NavigationViewItem.Icon>
                     <FontIcon Glyph="&#xE7FC;"/>
                 </NavigationViewItem.Icon>
             </NavigationViewItem>
             <NavigationViewItem Tag="NavigationViewDemo.MusicPage" Icon="Audio" Content="Music"/>
         </NavigationView.MenuItems>

         <NavigationView.AutoSuggestBox>
             <!-- See AutoSuggestBox documentation for
              more info about how to implement search. -->
             <AutoSuggestBox x:Name="NavViewSearchBox" QueryIcon="Find"/>
         </NavigationView.AutoSuggestBox>

         <ScrollViewer>
             <Frame x:Name="ContentFrame" IsTabStop="True"
                NavigationFailed="ContentFrame_NavigationFailed"/>
         </ScrollViewer>
     </NavigationView>

     <VisualStateManager.VisualStateGroups>
         <VisualStateGroup>
             <VisualState>
                 <VisualState.StateTriggers>
                     <AdaptiveTrigger
                     MinWindowWidth="{x:Bind NavViewCompactModeThresholdWidth}"/>
                 </VisualState.StateTriggers>
                 <VisualState.Setters>
                     <!-- Remove the next 3 lines for left-only navigation. -->
                     <Setter Target="NavView.PaneDisplayMode" Value="Top"/>
                     <Setter Target="NavViewSearchBox.Width" Value="200"/>
                     <Setter Target="MainPagesHeader.Visibility" Value="Collapsed"/>
                     <!-- Leave the next line for left-only navigation. -->
                     <Setter Target="ContentFrame.Padding" Value="24,0,24,24"/>
                 </VisualState.Setters>
             </VisualState>
         </VisualStateGroup>
     </VisualStateManager.VisualStateGroups>
 </Grid>
</Page>
private double NavViewCompactModeThresholdWidth { get { return NavView.CompactModeThresholdWidth; } }

private void ContentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
    throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}

private void NavView_Loaded(object sender, RoutedEventArgs e)
{
    // You can also add items in code.
    NavView.MenuItems.Add(new NavigationViewItemSeparator());
    NavView.MenuItems.Add(new NavigationViewItem
    {
        Content = "My content",
        Icon = new SymbolIcon((Symbol)0xF1AD),
        Tag = "NavigationViewDemo.MyContentPage"
    });

    // Add handler for ContentFrame navigation.
    ContentFrame.Navigated += On_Navigated;

    // NavView doesn't load any page by default, so load home page.
    NavView.SelectedItem = NavView.MenuItems[0];
    // If navigation occurs on SelectionChanged, this isn't needed.
    // Because we use ItemInvoked to navigate, we need to call Navigate
    // here to load the home page.
    NavView_Navigate(typeof(HomePage), new EntranceNavigationTransitionInfo());
}

private void NavView_ItemInvoked(NavigationView sender,
                                 NavigationViewItemInvokedEventArgs args)
{
    if (args.IsSettingsInvoked == true)
    {
        NavView_Navigate(typeof(SettingsPage), args.RecommendedNavigationTransitionInfo);
    }
    else if (args.InvokedItemContainer != null)
    {
        Type navPageType = Type.GetType(args.InvokedItemContainer.Tag.ToString());
        NavView_Navigate(navPageType, args.RecommendedNavigationTransitionInfo);
    }
}

// NavView_SelectionChanged is not used in this example, but is shown for completeness.
// You will typically handle either ItemInvoked or SelectionChanged to perform navigation,
// but not both.
private void NavView_SelectionChanged(NavigationView sender,
                                      NavigationViewSelectionChangedEventArgs args)
{
    if (args.IsSettingsSelected == true)
    {
        NavView_Navigate(typeof(SettingsPage), args.RecommendedNavigationTransitionInfo);
    }
    else if (args.SelectedItemContainer != null)
    {
        Type navPageType = Type.GetType(args.SelectedItemContainer.Tag.ToString());
        NavView_Navigate(navPageType, args.RecommendedNavigationTransitionInfo);
    }
}

private void NavView_Navigate(
    Type navPageType,
    NavigationTransitionInfo transitionInfo)
{
    // Get the page type before navigation so you can prevent duplicate
    // entries in the backstack.
    Type preNavPageType = ContentFrame.CurrentSourcePageType;

    // Only navigate if the selected page isn't currently loaded.
    if (navPageType is not null && !Type.Equals(preNavPageType, navPageType))
    {
        ContentFrame.Navigate(navPageType, null, transitionInfo);
    }
}

private void NavView_BackRequested(NavigationView sender,
                                   NavigationViewBackRequestedEventArgs args)
{
    TryGoBack();
}

private bool TryGoBack()
{
    if (!ContentFrame.CanGoBack)
        return false;

    // Don't go back if the nav pane is overlayed.
    if (NavView.IsPaneOpen &&
        (NavView.DisplayMode == NavigationViewDisplayMode.Compact ||
         NavView.DisplayMode == NavigationViewDisplayMode.Minimal))
        return false;

    ContentFrame.GoBack();
    return true;
}

private void On_Navigated(object sender, NavigationEventArgs e)
{
    NavView.IsBackEnabled = ContentFrame.CanGoBack;

    if (ContentFrame.SourcePageType == typeof(SettingsPage))
    {
        // SettingsItem is not part of NavView.MenuItems, and doesn't have a Tag.
        NavView.SelectedItem = (NavigationViewItem)NavView.SettingsItem;
        NavView.Header = "Settings";
    }
    else if (ContentFrame.SourcePageType != null)
    {
        // Select the nav view item that corresponds to the page being navigated to.
        NavView.SelectedItem = NavView.MenuItems
                    .OfType<NavigationViewItem>()
                    .First(i => i.Tag.Equals(ContentFrame.SourcePageType.FullName.ToString()));

        NavView.Header =
            ((NavigationViewItem)NavView.SelectedItem)?.Content?.ToString();

    }
}
// MainPage.idl
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
    ...
    Double NavViewCompactModeThresholdWidth{ get; };
}

// pch.h
...
#include <winrt/Windows.UI.Xaml.Interop.h>
#include <winrt/Microsoft.UI.Xaml.Media.Animation.h>


// MainPage.h
#pragma once

#include "MainPage.g.h"

namespace muxc
{
    using namespace winrt::Microsoft::UI::Xaml::Controls;
};

namespace winrt::NavigationViewDemo::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        double NavViewCompactModeThresholdWidth();
        void ContentFrame_NavigationFailed(
            Windows::Foundation::IInspectable const& /* sender */,
            Microsoft::UI::Xaml::Navigation::NavigationFailedEventArgs const& args);
        void NavView_Loaded(
            Windows::Foundation::IInspectable const& /* sender */,
            Microsoft::UI::Xaml::RoutedEventArgs const& /* args */);
        void NavView_ItemInvoked(
            Windows::Foundation::IInspectable const& /* sender */,
            muxc::NavigationViewItemInvokedEventArgs const& args);

        // NavView_SelectionChanged is not used in this example, but is shown for completeness.
        // You'll typically handle either ItemInvoked or SelectionChanged to perform navigation,
        // but not both.
        void NavView_SelectionChanged(
            muxc::NavigationView const& /* sender */,
            muxc::NavigationViewSelectionChangedEventArgs const& args);
        void NavView_Navigate(
            Windows::UI::Xaml::Interop::TypeName navPageType,
            Microsoft::UI::Xaml::Media::Animation::NavigationTransitionInfo const& transitionInfo);
        void NavView_BackRequested(
            muxc::NavigationView const& /* sender */,
            muxc::NavigationViewBackRequestedEventArgs const& /* args */);
        void On_Navigated(
            Windows::Foundation::IInspectable const& /* sender */,
            Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& args);
        bool TryGoBack();

    private:

    };
}

namespace winrt::NavigationViewDemo::factory_implementation
{
    struct MainPage : MainPageT<MainPage, implementation::MainPage>
    {
    };
}

// MainPage.cpp
#include "pch.h"
#include "MainPage.xaml.h"
#if __has_include("MainPage.g.cpp")
#include "MainPage.g.cpp"
#endif

using namespace winrt;
using namespace Microsoft::UI::Xaml;

namespace winrt::NavigationViewDemo::implementation
{
    MainPage::MainPage()
    {
        InitializeComponent();
    }

    double MainPage::NavViewCompactModeThresholdWidth()
    {
        return NavView().CompactModeThresholdWidth();
    }

    void MainPage::ContentFrame_NavigationFailed(
        Windows::Foundation::IInspectable const& /* sender */,
        Microsoft::UI::Xaml::Navigation::NavigationFailedEventArgs const& args)
    {
        throw winrt::hresult_error(
            E_FAIL, winrt::hstring(L"Failed to load Page ") + args.SourcePageType().Name);
    }

    void MainPage::NavView_Loaded(
        Windows::Foundation::IInspectable const& /* sender */,
        Microsoft::UI::Xaml::RoutedEventArgs const& /* args */)
    {
        // You can also add items in code.
        NavView().MenuItems().Append(muxc::NavigationViewItemSeparator());
        muxc::NavigationViewItem navigationViewItem;
        navigationViewItem.Content(winrt::box_value(L"My content"));
        navigationViewItem.Icon(muxc::SymbolIcon(static_cast<muxc::Symbol>(0xF1AD)));
        navigationViewItem.Tag(winrt::box_value(L"NavigationViewDemo.MyContentPage"));
        NavView().MenuItems().Append(navigationViewItem);

        // Add handler for ContentFrame navigation.
        ContentFrame().Navigated({ this, &MainPage::On_Navigated });

        // NavView doesn't load any page by default, so load home page.
        NavView().SelectedItem(NavView().MenuItems().GetAt(0));
        // If navigation occurs on SelectionChanged, then this isn't needed.
        // Because we use ItemInvoked to navigate, we need to call Navigate
        // here to load the home page.
        NavView_Navigate(winrt::xaml_typename<NavigationViewDemo::HomePage>(),
            Microsoft::UI::Xaml::Media::Animation::EntranceNavigationTransitionInfo());
    }

    void MainPage::NavView_ItemInvoked(
        Windows::Foundation::IInspectable const& /* sender */,
        muxc::NavigationViewItemInvokedEventArgs const& args)
    {
        if (args.IsSettingsInvoked())
        {
            NavView_Navigate(winrt::xaml_typename<NavigationViewDemo::SettingsPage>(),
                args.RecommendedNavigationTransitionInfo());
        }
        else if (args.InvokedItemContainer())
        {
            Windows::UI::Xaml::Interop::TypeName pageTypeName;
            pageTypeName.Name = unbox_value<hstring>(args.InvokedItemContainer().Tag());
            pageTypeName.Kind = Windows::UI::Xaml::Interop::TypeKind::Primitive;
            NavView_Navigate(pageTypeName, args.RecommendedNavigationTransitionInfo());
        }
    }

    // NavView_SelectionChanged is not used in this example, but is shown for completeness.
    // You will typically handle either ItemInvoked or SelectionChanged to perform navigation,
    // but not both.
    void MainPage::NavView_SelectionChanged(
        muxc::NavigationView const& /* sender */,
        muxc::NavigationViewSelectionChangedEventArgs const& args)
    {
        if (args.IsSettingsSelected())
        {
            NavView_Navigate(winrt::xaml_typename<NavigationViewDemo::SettingsPage>(),
                args.RecommendedNavigationTransitionInfo());
        }
        else if (args.SelectedItemContainer())
        {
            Windows::UI::Xaml::Interop::TypeName pageTypeName;
            pageTypeName.Name = unbox_value<hstring>(args.SelectedItemContainer().Tag());
            pageTypeName.Kind = Windows::UI::Xaml::Interop::TypeKind::Primitive;
            NavView_Navigate(pageTypeName, args.RecommendedNavigationTransitionInfo());
        }
    }

    void MainPage::NavView_Navigate(
        Windows::UI::Xaml::Interop::TypeName navPageType,
        Microsoft::UI::Xaml::Media::Animation::NavigationTransitionInfo const& transitionInfo)
    {
        // Get the page type before navigation so you can prevent duplicate
        // entries in the backstack.
        Windows::UI::Xaml::Interop::TypeName preNavPageType =
            ContentFrame().CurrentSourcePageType();

        // Navigate only if the selected page isn't currently loaded.
        if (navPageType.Name != L"" && preNavPageType.Name != navPageType.Name)
        {
            ContentFrame().Navigate(navPageType, nullptr, transitionInfo);
        }
    }

    void MainPage::NavView_BackRequested(
        muxc::NavigationView const& /* sender */,
        muxc::NavigationViewBackRequestedEventArgs const& /* args */)
    {
        TryGoBack();
    }

    bool MainPage::TryGoBack()
    {
        if (!ContentFrame().CanGoBack())
            return false;
        // Don't go back if the nav pane is overlayed.
        if (NavView().IsPaneOpen() &&
            (NavView().DisplayMode() == muxc::NavigationViewDisplayMode::Compact ||
                NavView().DisplayMode() == muxc::NavigationViewDisplayMode::Minimal))
            return false;
        ContentFrame().GoBack();
        return true;
    }

    void MainPage::On_Navigated(
        Windows::Foundation::IInspectable const& /* sender */,
        Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& args)
    {
        NavView().IsBackEnabled(ContentFrame().CanGoBack());

        if (ContentFrame().SourcePageType().Name ==
            winrt::xaml_typename<NavigationViewDemo::SettingsPage>().Name)
        {
            // SettingsItem is not part of NavView.MenuItems, and doesn't have a Tag.
            NavView().SelectedItem(NavView().SettingsItem().as<muxc::NavigationViewItem>());
            NavView().Header(winrt::box_value(L"Settings"));
        }
        else if (ContentFrame().SourcePageType().Name != L"")
        {
            for (auto&& eachMenuItem : NavView().MenuItems())
            {
                auto navigationViewItem =
                    eachMenuItem.try_as<muxc::NavigationViewItem>();
                {
                    if (navigationViewItem)
                    {
                        winrt::hstring hstringValue =
                            winrt::unbox_value_or<winrt::hstring>(
                                navigationViewItem.Tag(), L"");
                        if (hstringValue == ContentFrame().SourcePageType().Name)
                        {
                            NavView().SelectedItem(navigationViewItem);
                            NavView().Header(navigationViewItem.Content());
                        }
                    }
                }
            }
        }
    }
}

Navigation hiérarchique

Certaines applications peuvent avoir une structure hiérarchique plus complexe qui nécessite plus qu’une simple liste plate d’éléments de navigation. Vous souhaiterez peut-être utiliser des éléments de navigation de niveau supérieur pour afficher des catégories de pages, avec des éléments enfants affichant des pages spécifiques. Cette approche est également utile si vous avez des pages de style hub uniquement liées à d’autres pages. Dans ces types de cas, vous devez créer un NavigationView hiérarchique.

Pour montrer une liste hiérarchique d’éléments de navigation imbriqués dans le volet, utilisez la propriété MenuItems ou la propriété MenuItemsSource de NavigationViewItem. Chaque NavigationViewItem peut contenir d’autres NavigationViewItems et éléments d’organisation tels que des séparateurs et des en-têtes d’élément. Pour afficher une liste hiérarchique quand vous utilisez MenuItemsSource, définissez ItemTemplate en tant que NavigationViewItem et liez sa propriété MenuItemsSource au niveau suivant de la hiérarchie.

Bien que NavigationViewItem puisse contenir un nombre quelconque de niveaux imbriqués, nous vous recommandons de limiter la profondeur de la hiérarchie de navigation de votre application. Nous pensons que deux niveaux sont idéaux pour faciliter l’utilisation et la compréhension.

NavigationView affiche la hiérarchie dans les modes d’affichage du volet Top, Left et LeftCompact. Voici à quoi ressemble une sous-arborescence développée dans chacun des modes d’affichage du volet :

NavigationView avec hiérarchie

Ajout d’une hiérarchie d’éléments dans le balisage

Cet exemple montre comment déclarer la navigation d’application hiérarchique dans le balisage XAML.

<NavigationView>
    <NavigationView.MenuItems>
        <NavigationViewItem Content="Home" Icon="Home" ToolTipService.ToolTip="Home"/>
        <NavigationViewItem Content="Collections" Icon="Keyboard" ToolTipService.ToolTip="Collections">
            <NavigationViewItem.MenuItems>
                <NavigationViewItem Content="Notes" Icon="Page" ToolTipService.ToolTip="Notes"/>
                <NavigationViewItem Content="Mail" Icon="Mail" ToolTipService.ToolTip="Mail"/>
            </NavigationViewItem.MenuItems>
        </NavigationViewItem>
    </NavigationView.MenuItems>
</NavigationView>

Ajout d’une hiérarchie d’éléments à l’aide de la liaison de données

Ajoutez une hiérarchie d’éléments de menu à NavigationView en

  • liant la propriété MenuItemsSource aux données hiérarchiques ;
  • définissant le modèle d’élément en tant que NavigationViewMenuItem, avec son contenu (Content) défini sur l’étiquette de l’élément de menu et sa propriété MenuItemsSource liée au niveau suivant de la hiérarchie.

Cet exemple montre également les événements de développement (Expanding) et de réduction (Collapsed). Ces événements sont déclenchés pour un élément de menu avec enfants.

<Page ... >
    <Page.Resources>
        <DataTemplate x:Key="NavigationViewMenuItem" x:DataType="local:Category">
            <NavigationViewItem Content="{x:Bind Name}" MenuItemsSource="{x:Bind Children}"/>
        </DataTemplate>
    </Page.Resources>

    <Grid>
        <NavigationView x:Name="navview"
    MenuItemsSource="{x:Bind Categories, Mode=OneWay}"
    MenuItemTemplate="{StaticResource NavigationViewMenuItem}"
    ItemInvoked="{x:Bind OnItemInvoked}"
    Expanding="OnItemExpanding"
    Collapsed="OnItemCollapsed"
    PaneDisplayMode="Left">
            <StackPanel Margin="10,10,0,0">
                <TextBlock Margin="0,10,0,0" x:Name="ExpandingItemLabel" Text="Last Expanding: N/A"/>
                <TextBlock x:Name="CollapsedItemLabel" Text="Last Collapsed: N/A"/>
            </StackPanel>
        </NavigationView>
    </Grid>
</Page>
public class Category
{
    public String Name { get; set; }
    public String CategoryIcon { get; set; }
    public ObservableCollection<Category> Children { get; set; }
}

public sealed partial class HierarchicalNavigationViewDataBinding : Page
{
    public HierarchicalNavigationViewDataBinding()
    {
        this.InitializeComponent();
    }

    public ObservableCollection<Category> Categories = new ObservableCollection<Category>()
    {
        new Category(){
            Name = "Menu item 1",
            CategoryIcon = "Icon",
            Children = new ObservableCollection<Category>() {
                new Category(){
                    Name = "Menu item 2",
                    CategoryIcon = "Icon",
                    Children = new ObservableCollection<Category>() {
                        new Category() {
                            Name  = "Menu item 3",
                            CategoryIcon = "Icon",
                            Children = new ObservableCollection<Category>() {
                                new Category() { Name  = "Menu item 4", CategoryIcon = "Icon" },
                                new Category() { Name  = "Menu item 5", CategoryIcon = "Icon" }
                            }
                        }
                    }
                }
            }
        },
        new Category(){
            Name = "Menu item 6",
            CategoryIcon = "Icon",
            Children = new ObservableCollection<Category>() {
                new Category(){
                    Name = "Menu item 7",
                    CategoryIcon = "Icon",
                    Children = new ObservableCollection<Category>() {
                        new Category() { Name  = "Menu item 8", CategoryIcon = "Icon" },
                        new Category() { Name  = "Menu item 9", CategoryIcon = "Icon" }
                    }
                }
            }
        },
        new Category(){ Name = "Menu item 10", CategoryIcon = "Icon" }
    };

    private void OnItemInvoked(object sender, NavigationViewItemInvokedEventArgs e)
    {
        var clickedItem = e.InvokedItem;
        var clickedItemContainer = e.InvokedItemContainer;
    }
    private void OnItemExpanding(object sender, NavigationViewItemExpandingEventArgs e)
    {
        var nvib = e.ExpandingItemContainer;
        var name = "Last expanding: " + nvib.Content.ToString();
        ExpandingItemLabel.Text = name;
    }
    private void OnItemCollapsed(object sender, NavigationViewItemCollapsedEventArgs e)
    {
        var nvib = e.CollapsedItemContainer;
        var name = "Last collapsed: " + nvib.Content;
        CollapsedItemLabel.Text = name;
    }
}
// Category.idl
namespace HierarchicalNavigationViewDataBinding
{
    runtimeclass Category
    {
        String Name;
        String CategoryIcon;
        Windows.Foundation.Collections.IObservableVector<Category> Children;
    }
}

// Category.h
#pragma once
#include "Category.g.h"

namespace winrt::HierarchicalNavigationViewDataBinding::implementation
{
    struct Category : CategoryT<Category>
    {
        Category();
        Category(winrt::hstring name,
            winrt::hstring categoryIcon,
            Windows::Foundation::Collections::
                IObservableVector<HierarchicalNavigationViewDataBinding::Category> children);

        winrt::hstring Name();
        void Name(winrt::hstring const& value);
        winrt::hstring CategoryIcon();
        void CategoryIcon(winrt::hstring const& value);
        Windows::Foundation::Collections::
            IObservableVector<HierarchicalNavigationViewDataBinding::Category> Children();
        void Children(Windows::Foundation::Collections:
            IObservableVector<HierarchicalNavigationViewDataBinding::Category> const& value);

    private:
        winrt::hstring m_name;
        winrt::hstring m_categoryIcon;
        Windows::Foundation::Collections::
            IObservableVector<HierarchicalNavigationViewDataBinding::Category> m_children;
    };
}

// Category.cpp
#include "pch.h"
#include "Category.h"
#include "Category.g.cpp"

namespace winrt::HierarchicalNavigationViewDataBinding::implementation
{
    Category::Category()
    {
        m_children = winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
    }

    Category::Category(
        winrt::hstring name,
        winrt::hstring categoryIcon,
        Windows::Foundation::Collections::
            IObservableVector<HierarchicalNavigationViewDataBinding::Category> children)
    {
        m_name = name;
        m_categoryIcon = categoryIcon;
        m_children = children;
    }

    hstring Category::Name()
    {
        return m_name;
    }

    void Category::Name(hstring const& value)
    {
        m_name = value;
    }

    hstring Category::CategoryIcon()
    {
        return m_categoryIcon;
    }

    void Category::CategoryIcon(hstring const& value)
    {
        m_categoryIcon = value;
    }

    Windows::Foundation::Collections::IObservableVector<HierarchicalNavigationViewDataBinding::Category>
        Category::Children()
    {
        return m_children;
    }

    void Category::Children(
        Windows::Foundation::Collections::IObservableVector<HierarchicalNavigationViewDataBinding::Category>
            const& value)
    {
        m_children = value;
    }
}

// MainPage.idl
import "Category.idl";

namespace HierarchicalNavigationViewDataBinding
{
    [default_interface]
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        Windows.Foundation.Collections.IObservableVector<Category> Categories{ get; };
    }
}

// MainPage.h
#pragma once

#include "MainPage.g.h"

namespace muxc
{
    using namespace winrt::Microsoft::UI::Xaml::Controls;
};

namespace winrt::HierarchicalNavigationViewDataBinding::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        Windows::Foundation::Collections::IObservableVector<HierarchicalNavigationViewDataBinding::Category>
            Categories();

        void OnItemInvoked(muxc::NavigationView const& sender, muxc::NavigationViewItemInvokedEventArgs const& args);
        void OnItemExpanding(
            muxc::NavigationView const& sender,
            muxc::NavigationViewItemExpandingEventArgs const& args);
        void OnItemCollapsed(
            muxc::NavigationView const& sender,
            muxc::NavigationViewItemCollapsedEventArgs const& args);

    private:
        Windows::Foundation::Collections::
            IObservableVector<HierarchicalNavigationViewDataBinding::Category> m_categories;
    };
}

namespace winrt::HierarchicalNavigationViewDataBinding::factory_implementation
{
    struct MainPage : MainPageT<MainPage, implementation::MainPage>
    {
    };
}

// MainPage.cpp
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"

#include "Category.h"

namespace winrt::HierarchicalNavigationViewDataBinding::implementation
{
    MainPage::MainPage()
    {
        InitializeComponent();

        m_categories =
            winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();

        auto menuItem10 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 10", L"Icon", nullptr);

        auto menuItem9 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 9", L"Icon", nullptr);
        auto menuItem8 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 8", L"Icon", nullptr);
        auto menuItem7Children =
            winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
        menuItem7Children.Append(*menuItem9);
        menuItem7Children.Append(*menuItem8);

        auto menuItem7 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 7", L"Icon", menuItem7Children);
        auto menuItem6Children =
            winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
        menuItem6Children.Append(*menuItem7);

        auto menuItem6 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 6", L"Icon", menuItem6Children);

        auto menuItem5 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 5", L"Icon", nullptr);
        auto menuItem4 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 4", L"Icon", nullptr);
        auto menuItem3Children =
            winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
        menuItem3Children.Append(*menuItem5);
        menuItem3Children.Append(*menuItem4);

        auto menuItem3 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 3", L"Icon", menuItem3Children);
        auto menuItem2Children =
            winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
        menuItem2Children.Append(*menuItem3);

        auto menuItem2 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 2", L"Icon", menuItem2Children);
        auto menuItem1Children =
            winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
        menuItem1Children.Append(*menuItem2);

        auto menuItem1 = winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
            (L"Menu item 1", L"Icon", menuItem1Children);

        m_categories.Append(*menuItem1);
        m_categories.Append(*menuItem6);
        m_categories.Append(*menuItem10);
    }

    Windows::Foundation::Collections::IObservableVector<HierarchicalNavigationViewDataBinding::Category>
        MainPage::Categories()
    {
        return m_categories;
    }

    void MainPage::OnItemInvoked(
        muxc::NavigationView const& /* sender */,
        muxc::NavigationViewItemInvokedEventArgs const& args)
    {
        auto clickedItem = args.InvokedItem();
        auto clickedItemContainer = args.InvokedItemContainer();
    }

    void MainPage::OnItemExpanding(
        muxc::NavigationView const& /* sender */,
        muxc::NavigationViewItemExpandingEventArgs const& args)
    {
        auto nvib = args.ExpandingItemContainer();
        auto name = L"Last expanding: " + winrt::unbox_value<winrt::hstring>(nvib.Content());
        ExpandingItemLabel().Text(name);
    }

    void MainPage::OnItemCollapsed(
        muxc::NavigationView const& /* sender */,
        muxc::NavigationViewItemCollapsedEventArgs const& args)
    {
        auto nvib = args.CollapsedItemContainer();
        auto name = L"Last collapsed: " + winrt::unbox_value<winrt::hstring>(nvib.Content());
        CollapsedItemLabel().Text(name);
    }
}

d’un certificat SSTP

Par défaut, tous les éléments peuvent contenir des enfants, être appelés ou être sélectionnés.

Quand vous proposez aux utilisateurs une arborescence d’options de navigation, vous pouvez choisir de rendre les éléments parents non sélectionnables, par exemple quand votre application n’a pas de page de destination associée à l’élément parent concerné. Si vos éléments parents sont sélectionnables, nous vous recommandons d’utiliser les modes d’affichage Left-Expanded ou Top du volet. Avec le mode LeftCompact, l’utilisateur accède à l’élément parent pour ouvrir la sous-arborescence enfant chaque fois qu’il est appelé.

Les éléments sélectionnés affichent leurs indicateurs de sélection le long de leur bord gauche quand ils sont disposés en mode Left ou de leur bord inférieur quand ils sont disposés en mode Top. Vous trouverez ci-dessous des NavigationViews en mode Left et Top dans lesquels un élément parent est sélectionné.

NavigationView en mode Left avec parent sélectionné

NavigationView en mode Top avec parent sélectionné

Il est possible que l’élément sélectionné ne soit pas toujours visible. Si un enfant d’une sous-arborescence réduite/non développée est sélectionné, son premier ancêtre visible s’affiche comme étant sélectionné. L’indicateur de sélection revient à l’élément sélectionné si/quand la sous-arborescence est développée.

Par exemple, dans l’image ci-dessus, l’élément Calendar peut être sélectionné par l’utilisateur, qui peut ensuite réduire la sous-arborescence. Dans ce cas, l’indicateur de sélection s’affiche sous l’élément Account, car ce dernier est le premier ancêtre visible de l’élément Calendar. L’indicateur de sélection revient à l’élément Calendar quand l’utilisateur redéveloppe la sous-arborescence.

Le NavigationView entier n’affiche pas plus d’un indicateur de sélection.

Dans les deux modes Top et Left, un clic sur les flèches sur les NavigationViewItems permet de développer ou de réduire la sous-arborescence. En cliquant ou en appuyant ailleurs sur le NavigationViewItem, vous déclenchez l’événement ItemInvoked, qui entraîne également la réduction ou le développement de la sous-arborescence.

Pour empêcher un élément d’afficher l’indicateur de sélection quand il est appelé, affectez la valeur False à sa propriété SelectsOnInvoked, comme indiqué ci-dessous :

<Page ...>
    <Page.Resources>
        <DataTemplate x:Key="NavigationViewMenuItem" x:DataType="local:Category">
            <NavigationViewItem Content="{x:Bind Name}"
            MenuItemsSource="{x:Bind Children}"
            SelectsOnInvoked="{x:Bind IsLeaf}"/>
        </DataTemplate>
    </Page.Resources>

    <Grid>
        <NavigationView x:Name="navview"
    MenuItemsSource="{x:Bind Categories, Mode=OneWay}"
    MenuItemTemplate="{StaticResource NavigationViewMenuItem}">
        </NavigationView>
    </Grid>
</Page>
public class Category
{
    public String Name { get; set; }
    public String CategoryIcon { get; set; }
    public ObservableCollection<Category> Children { get; set; }
    public bool IsLeaf { get; set; }
}

public sealed partial class HierarchicalNavigationViewDataBinding : Page
{
    public HierarchicalNavigationViewDataBinding()
    {
        this.InitializeComponent();
    }

    public ObservableCollection<Category> Categories = new ObservableCollection<Category>()
    {
        new Category(){
            Name = "Menu item 1",
            CategoryIcon = "Icon",
            Children = new ObservableCollection<Category>() {
                new Category(){
                    Name = "Menu item 2",
                    CategoryIcon = "Icon",
                    Children = new ObservableCollection<Category>() {
                        new Category() {
                            Name  = "Menu item 3",
                            CategoryIcon = "Icon",
                            Children = new ObservableCollection<Category>() {
                                new Category() { Name  = "Menu item 4", CategoryIcon = "Icon", IsLeaf = true },
                                new Category() { Name  = "Menu item 5", CategoryIcon = "Icon", IsLeaf = true }
                            }
                        }
                    }
                }
            }
        },
        new Category(){
            Name = "Menu item 6",
            CategoryIcon = "Icon",
            Children = new ObservableCollection<Category>() {
                new Category(){
                    Name = "Menu item 7",
                    CategoryIcon = "Icon",
                    Children = new ObservableCollection<Category>() {
                        new Category() { Name  = "Menu item 8", CategoryIcon = "Icon", IsLeaf = true },
                        new Category() { Name  = "Menu item 9", CategoryIcon = "Icon", IsLeaf = true }
                    }
                }
            }
        },
        new Category(){ Name = "Menu item 10", CategoryIcon = "Icon", IsLeaf = true }
    };
}
// Category.idl
namespace HierarchicalNavigationViewDataBinding
{
    runtimeclass Category
    {
        ...
        Boolean IsLeaf;
    }
}

// Category.h
...
struct Category : CategoryT<Category>
{
    ...
    Category(winrt::hstring name,
        winrt::hstring categoryIcon,
        Windows::Foundation::Collections::IObservableVector<HierarchicalNavigationViewDataBinding::Category> children,
        bool isleaf = false);
    ...
    bool IsLeaf();
    void IsLeaf(bool value);

private:
    ...
    bool m_isleaf;
};

// Category.cpp
...
Category::Category(winrt::hstring name,
    winrt::hstring categoryIcon,
    Windows::Foundation::Collections::IObservableVector<HierarchicalNavigationViewDataBinding::Category> children,
    bool isleaf) : m_name(name), m_categoryIcon(categoryIcon), m_children(children), m_isleaf(isleaf) {}
...
bool Category::IsLeaf()
{
    return m_isleaf;
}

void Category::IsLeaf(bool value)
{
    m_isleaf = value;
}

// MainPage.h and MainPage.cpp
// Delete OnItemInvoked, OnItemExpanding, and OnItemCollapsed.

// MainPage.cpp
...
MainPage::MainPage()
{
    InitializeComponent();

    m_categories = winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();

    auto menuItem10 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 10", L"Icon", nullptr, true);

    auto menuItem9 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 9", L"Icon", nullptr, true);
    auto menuItem8 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 8", L"Icon", nullptr, true);
    auto menuItem7Children =
        winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
    menuItem7Children.Append(*menuItem9);
    menuItem7Children.Append(*menuItem8);

    auto menuItem7 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 7", L"Icon", menuItem7Children);
    auto menuItem6Children =
        winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
    menuItem6Children.Append(*menuItem7);

    auto menuItem6 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 6", L"Icon", menuItem6Children);

    auto menuItem5 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 5", L"Icon", nullptr, true);
    auto menuItem4 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 4", L"Icon", nullptr, true);
    auto menuItem3Children =
        winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
    menuItem3Children.Append(*menuItem5);
    menuItem3Children.Append(*menuItem4);

    auto menuItem3 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 3", L"Icon", menuItem3Children);
    auto menuItem2Children =
        winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
    menuItem2Children.Append(*menuItem3);

    auto menuItem2 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 2", L"Icon", menuItem2Children);
    auto menuItem1Children =
        winrt::single_threaded_observable_vector<HierarchicalNavigationViewDataBinding::Category>();
    menuItem1Children.Append(*menuItem2);

    auto menuItem1 =
        winrt::make_self<HierarchicalNavigationViewDataBinding::implementation::Category>
        (L"Menu item 1", L"Icon", menuItem1Children);

    m_categories.Append(*menuItem1);
    m_categories.Append(*menuItem6);
    m_categories.Append(*menuItem10);
}
...

Utilisation du clavier avec un NavigationView hiérarchique

Les utilisateurs peuvent déplacer le focus dans NavigationView à l’aide du clavier. Les touches de direction exposent la « navigation interne » dans le volet et suivent les interactions fournies dans l’arborescence. Les actions des touches changent quand vous naviguez dans le NavigationView ou dans son menu volant, qui s’affiche dans les modes Top and LeftCompact de HierarchicalNavigationView. Voici les actions spécifiques que chaque touche peut effectuer dans un NavigationView hiérarchique :

Clé En mode Left En mode Top Dans le menu volant
Haut Déplace le focus vers l’élément situé juste au-dessus de l’élément actif. Ne fait rien. Déplace le focus vers l’élément situé juste au-dessus de l’élément actif.
Bas Déplace le focus juste au-dessous de l’élément actif.* Ne fait rien. Déplace le focus juste au-dessous de l’élément actif.*
Droit Ne fait rien. Déplace le focus vers l’élément situé juste à droite de l’élément actif. Ne fait rien.
Gauche Ne fait rien. Déplace le focus vers l’élément situé juste à gauche de l’élément actif. Ne fait rien.
Espace/Entrée Si l’élément a des enfants, développe/réduit l’élément et ne change pas le focus. Si l’élément a des enfants, développe les enfants dans un menu volant et place le focus sur le premier élément du menu. Appelle/sélectionne un élément et ferme le menu volant.
Échap Ne fait rien. Ne fait rien. Ferme le menu volant.

La touche Espace ou Entrée appelle/sélectionne toujours un élément.

*Notez que les éléments n’ont pas besoin d’être visuellement adjacents, car le focus se déplace du dernier élément de la liste du volet vers l’élément relatif aux paramètres.

Arrière-plans de volet de navigation

Par défaut, le volet NavigationView utilise un arrière-plan différent selon le mode d’affichage :

  • le volet est d'une couleur grise unie lorsqu'il est agrandi à gauche, côte à côte avec le contenu (en mode Left) ;
  • le volet utilise l'acrylique dans l’application lorsqu'il est ouvert sous forme de superposition par rapport au contenu (en mode Top, Minimal ou Compact).

Pour modifier l'arrière-plan du volet, vous pouvez remplacer les ressources du thème XAML utilisées l’affichage de l'arrière-plan dans chaque mode. (Cette technique est privilégiée par rapport à une propriété PaneBackground unique car elle prend en charge différents arrière-plans pour différents modes d'affichage.)

Ce tableau indique quelle ressource de thème est utilisée dans chaque mode d'affichage.

Mode d’affichage Ressource de thème
Gauche NavigationViewExpandedPaneBackground
LeftCompact
LeftMinimal
NavigationViewDefaultPaneBackground
Haut NavigationViewTopPaneBackground

Cet exemple montre comment remplacer les ressources de thème dans App.xaml. Lorsque vous remplacez des ressources de thème, vous devez toujours fournir au minimum les dictionnaires de ressources « Default » et « HighContrast» , et les dictionnaires pour les ressources « Light » ou « Dark » si nécessaire. Pour plus d’informations, consultez ResourceDictionary.ThemeDictionaries.

Important

Ce code montre comment utiliser la version WinUI 2 d’AcrylicBrush. Si vous utilisez la version plateforme d’AcrylicBrush à la place, la version minimale pour votre projet d'application doit être SDK 16299 ou supérieure. Pour utiliser la version plateforme, supprimez toutes les références à muxm:.

<Application ... xmlns:muxm="using:Microsoft.UI.Xaml.Media" ...>
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls"/>
                <ResourceDictionary>
                    <ResourceDictionary.ThemeDictionaries>
                        <ResourceDictionary x:Key="Default">
                            <!-- The "Default" theme dictionary is used unless a specific
                                 light, dark, or high contrast dictionary is provided. These
                                 resources should be tested with both the light and dark themes,
                                 and specific light or dark resources provided as needed. -->
                            <muxm:AcrylicBrush x:Key="NavigationViewDefaultPaneBackground"
                                   BackgroundSource="Backdrop"
                                   TintColor="LightSlateGray"
                                   TintOpacity=".6"/>
                            <muxm:AcrylicBrush x:Key="NavigationViewTopPaneBackground"
                                   BackgroundSource="Backdrop"
                                   TintColor="{ThemeResource SystemAccentColor}"
                                   TintOpacity=".6"/>
                            <LinearGradientBrush x:Key="NavigationViewExpandedPaneBackground"
                                     StartPoint="0.5,0" EndPoint="0.5,1">
                                <GradientStop Color="LightSlateGray" Offset="0.0" />
                                <GradientStop Color="White" Offset="1.0" />
                            </LinearGradientBrush>
                        </ResourceDictionary>
                        <ResourceDictionary x:Key="HighContrast">
                            <!-- Always include a "HighContrast" dictionary when you override
                                 theme resources. This empty dictionary ensures that the
                                 default high contrast resources are used when the user
                                 turns on high contrast mode. -->
                        </ResourceDictionary>
                    </ResourceDictionary.ThemeDictionaries>
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Espace supérieur

La propriété IsTitleBarAutoPaddingEnabled nécessite WinUI 2.2 ou version ultérieure.

Certaines applications choisissent de personnaliser la barre de titre de leur fenêtre, en étendant éventuellement leur contenu dans la zone de barre de titre. Quand NavigationView est l’élément racine dans les applications qui étendent dans la barre de titre en utilisant l’API ExtendViewIntoTitleBar ,le contrôle ajuste automatiquement la position de ses éléments interactifs pour éviter le chevauchement avec la zone pouvant être glissée.

Application qui s’étend dans la barre de titre

Si votre application spécifie la région qui peut être déplacée par glisser en appelant la méthode Window.SetTitleBar et que vous préférez que les boutons précédent et de menu soient plus près du haut de la fenêtre de votre application, définissez IsTitleBarAutoPaddingEnabled sur false.

Application qui s’étend dans la barre de titre sans remplissage supplémentaire

<muxc:NavigationView x:Name="NavView" IsTitleBarAutoPaddingEnabled="False">

Remarks

Pour ajuster davantage la position de la zone d’en-tête de NavigationView, remplacez la ressource de thème XAML NavigationViewHeaderMargin, par exemple dans vos ressources de page.

<Page.Resources>
    <Thickness x:Key="NavigationViewHeaderMargin">12,0</Thickness>
</Page.Resources>

Cette ressource de thème modifie la marge autour de NavigationView.Header.