NavigationView

Il controllo NavigationView fornisce uno spostamento di primo livello per la tua app. Si adatta a un'ampia gamma di dimensioni dello schermo e supporta entrambi gli stili di spostamento: superiore e a sinistra.

top navigationleft navigation
NavigationView supporta sia il riquadro di spostamento superiore che quello sinistro

È il controllo giusto?

NavigationView è un controllo di spostamento adattivo ideale per:

  • Fornire un'esperienza di spostamento coerente in tutta l'app.
  • Risparmiare spazio sullo schermo delle finestre più piccole.
  • Organizzare l'accesso a numerose categorie di spostamento.

Per altri modelli di spostamento, vedi Nozioni di base sulla progettazione della struttura di spostamento.

Piattaforma UWP e WinUI 2

Importante

Le informazioni e gli esempi in questo articolo sono ottimizzate per le app che usano i SDK per app di Windows e WinUI 3, ma sono generalmente applicabili alle app UWP che usano WinUI 2. Vedi le informazioni di riferimento sulle API UWP per informazioni ed esempi specifici della piattaforma.

Questa sezione contiene informazioni necessarie per usare il controllo in un'app UWP o WinUI 2.

Il controllo NavigationView per le app UWP è incluso come parte della libreria dell'interfaccia utente di Windows 2. Per altre informazioni, incluse le istruzioni per l'installazione, vedi Libreria dell'interfaccia utente di Windows. Le API per questo controllo esistono negli spazi dei nomi Windows.UI.Xaml.Controls e Microsoft.UI.Xaml.Controls .

È consigliabile usare la versione più recente di WinUI 2 per ottenere gli stili, i modelli e le funzionalità più recenti per tutti i controlli. Alcune funzioni di NavigationView, come lo spostamento superiore e gerarchico, richiedono Windows 10, versione 1809 (SDK 17763) o successiva oppure la libreria dell'interfaccia utente di Windows.

Per usare il codice in questo articolo con WinUI 2, usa un alias in XAML (usiamo muxc) per rappresentare le API della libreria dell'interfaccia utente di Windows incluse nel progetto. Per altre informazioni, vedi Introduzione a WinUI 2 .

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

<muxc:NavigationView />

Creare una visualizzazione di spostamento

L'app Raccolta WinUI 3 include esempi interattivi della maggior parte dei controlli, delle funzionalità e delle funzionalità winUI 3. Ottenere l'app da Microsoft Store o ottenere il codice sorgente in GitHub

Questo esempio mostra come creare una semplice visualizzazione di spostamento in 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>

Modalità di visualizzazione

Puoi usare la proprietà PaneDisplayMode per configurare differenti stili di spostamento o modalità di visualizzazione, per NavigationView.

In alto

Il riquadro è posizionato sopra il contenuto.
PaneDisplayMode="Top"

Example of top navigation

Ti consigliamo lo spostamento superiore quando:

  • Hai al massimo 5 categorie di spostamento di primo livello ugualmente importanti e ogni ulteriore categoria di spostamento di primo livello che viene inserita nel menu extra a discesa è considerata meno importante.
  • Devi visualizzare tutte le opzioni di spostamento sullo schermo.
  • Vuoi più spazio per il contenuto dell'app.
  • Le icone non possono descrivere in modo chiaro le categorie di spostamento dell'app.

Sinistra

Il riquadro viene espanso e posizionato a sinistra del contenuto.
PaneDisplayMode="Left"

Example of expanded left navigation pane

Ti consigliamo lo spostamento a sinistra quando:

  • Hai 5-10 categorie di spostamento di primo livello altrettanto importanti.
  • Vuoi che le categorie di spostamento siano molto importanti, riservando meno spazio all'altro contenuto dell'app.

LeftCompact

Il riquadro mostra solo le icone fino a quando non viene aperto e posizionato a sinistra del contenuto. Quando viene aperto, il riquadro sovrappone il contenuto.
PaneDisplayMode="LeftCompact"

Example of compact left navigation pane

LeftMinimal

Viene visualizzato solo il pulsante del menu finché il riquadro non viene aperto. Quando si apre, il riquadro si sovrappone al lato sinistro del contenuto.
PaneDisplayMode="LeftMinimal"

Example of minimal left navigation pane

Automatica

Per impostazione predefinita, PaneDisplayMode è impostato su Auto. In Auto modalità NavigationView si adatta tra LeftMinimal quando la finestra è stretta, a LeftCompacte quindi Left quando la finestra diventa più ampia. Per altre informazioni, vedi la sezione sul comportamento adattivo.

Left navigation default adaptive behavior
Comportamento adattivo predefinito di NavigationView

Anatomia

Queste immagini mostrano il layout delle aree del riquadro, dell'intestazione e del contenuto del controllo quando la configurazione prevede lo spostamento superiore o a sinistra.

Top NavigationView layout
Layout dello spostamento superiore

Left NavigationView layout
Layout dello spostamento a sinistra

Riquadro

Puoi usare la proprietà PaneDisplayMode per posizionare il riquadro sopra o a sinistra del contenuto.

Il riquadro NavigationView può contenere:

Il riquadro a sinistra contiene anche:

  • Un pulsante di menu per alternare il riquadro aperto e chiuso. Nelle finestre più grandi dell'app quando il riquadro è aperto, puoi scegliere di nascondere questo pulsante usando la proprietà IsPaneToggleButtonVisible.

NavigationView ha un pulsante Indietro posizionato nell'angolo superiore sinistro del riquadro. Tuttavia, non gestisce automaticamente lo spostamento indietro e non aggiunge il contenuto allo stack Indietro. Per abilitare lo spostamento all'indietro, vedi la sezione Spostamento indietro.

Ecco l'anatomia del riquadro dettagliata per le posizioni del riquadro superiore e a sinistra.

Riquadro di spostamento superiore

NavigationView top pane anatomy

  1. Intestazioni
  2. Elementi di spostamento
  3. Separatori
  4. AutoSuggestBox (facoltativo)
  5. Pulsante delle impostazioni (facoltativo)

Riquadro di spostamento sinistro

NavigationView left pane anatomy

  1. Pulsante Menu
  2. Elementi di spostamento
  3. Separatori
  4. Intestazioni
  5. AutoSuggestBox (facoltativo)
  6. Pulsante delle impostazioni (facoltativo)

È possibile usare FooterMenuItems per posizionare gli elementi di navigazione alla fine del riquadro di spostamento, a differenza della proprietà MenuItems che inserisce gli elementi all'inizio del riquadro.

Piè di paginaMenuItems verrà visualizzato prima dell'elemento Settings per impostazione predefinita. L'elemento Settings può comunque essere attivato o disattivato usando la IsSettingsVisible proprietà .

Solo gli elementi di navigazione devono essere posizionati in FooterMenuItems. Tutti gli altri elementi che devono essere allineati al piè di pagina del riquadro possono essere posizionati in PaneFooter.

Per un esempio di come aggiungere FooterMenuItems a NavigationView, vedere la classe FooterMenuItems.

L'immagine seguente mostra un controllo NavigationView con gli elementi di navigazione Account, Carrello e Guida nel menu piè di pagina.

A NavigationView with FooterMenuItems

Puoi posizionare contenuto in formato libero nel piè di pagina del riquadro aggiungendolo alla proprietà PaneFooter.

Pane footer top nav
Piè di pagina riquadro superiore

Pane footer left nav
Piè di pagina del riquadro a sinistra

Intestazione e titolo del riquadro

Puoi posizionare il contenuto del testo nell'area di intestazione del riquadro impostando la proprietà PaneTitle. Accetta una stringa e mostra il testo accanto al pulsante di menu.

Per aggiungere contenuto non testuale, ad esempio un'immagine o un logo, puoi posizionare qualsiasi elemento nell'intestazione del riquadro aggiungendolo alla proprietà PaneHeader.

Se sono impostati sia PaneTitle che PaneHeader, il contenuto viene impilato orizzontalmente accanto al pulsante di menu, con PaneTitle più vicino al pulsante di menu.

Pane header top nav
Intestazione riquadro superiore

Pane header left nav
Intestazione del riquadro a sinistra

Contenuto del riquadro

Puoi posizionare contenuto in formato libero nel riquadro aggiungendolo alla proprietà PaneCustomContent.

Pane custom content top nav
Contenuto personalizzato riquadro superiore

Pane custom content left nav
Contenuto personalizzato riquadro sinistro

Puoi aggiungere un titolo di pagina impostando la proprietà Header.

Example of NavigationView header area
Intestazione NavigationView

L'area dell'intestazione è allineata verticalmente con il pulsante di spostamento nella posizione del riquadro sinistro e si trova sotto il riquadro nella posizione del riquadro superiore. Ha un'altezza fissa pari a 52 pixel. Lo scopo è contenere il titolo della pagina della categoria di spostamento selezionata. L'intestazione è ancorata alla parte superiore della pagina e funge da punto di ritaglio dello scorrimento per l'area del contenuto.

L'intestazione è visibile ogni volta che NavigationView è in Minimal modalità di visualizzazione. Puoi scegliere di nascondere l'intestazione nelle altre modalità utilizzate con larghezze di finestra più ampie. Per nascondere l'intestazione, impostare la proprietà AlwaysShowHeader su false.

Sommario

Example of NavigationView content area
Contenuto navigationView

L'area del contenuto è la posizione in cui viene visualizzata la maggior parte delle informazioni per la categoria di spostamento selezionata.

È consigliabile usare margini 12 px per l'area del contenuto quando NavigationView è in Minimal modalità e margini 24 px in caso contrario.

Comportamento adattivo

Per impostazione predefinita, NavigationView modifica automaticamente la modalità di visualizzazione in base alla quantità di spazio sullo schermo disponibile. Le proprietà CompactModeThresholdWidth ed ExpandedModeThresholdWidth specificano i punti di interruzione in corrispondenza di cui cambia la modalità di visualizzazione. Puoi modificare questi valori per personalizzare il comportamento adattivo della modalità di visualizzazione.

Default

Quando PaneDisplayMode è impostato sul valore predefinito di Auto, il comportamento adattivo consiste nello mostrare:

  • Un riquadro a sinistra espanso sulle larghezze di finestre grandi (1008 pixel o superiore).
  • Riquadro di spostamento a sinistra, solo icona (LeftCompact) su larghezza media della finestra (da 641 px a 1007 px).
  • Solo un pulsante di menu (LeftMinimal) su piccole larghezze di finestra (640 px o meno).

Per altre informazioni sulle dimensioni di finestra per il comportamento adattivo, vedi Dimensioni dello schermo e punti di interruzione.

Left navigation default adaptive behavior
Comportamento adattivo predefinito di NavigationView

Minimo

Un secondo modello adattivo comune consiste nell'utilizzare un riquadro a sinistra espanso su larghezze di finestre grandi e solo un pulsante di menu su larghezze di finestre piccole e medie.

Ti consigliamo questo approccio quando:

  • Vuoi più spazio per il contenuto dell'app su larghezze di finestre piccole.
  • Le categorie di spostamento non possono essere rappresentate in modo chiaro con icone.

Left navigation minimal adaptive behavior
Comportamento adattivo "minimo" di NavigationView

Per configurare questo comportamento, imposta CompactModeThresholdWidth sulla larghezza in corrispondenza della quale desideri che il riquadro venga compresso. In questo caso viene cambiato dal valore predefinito 640 a 1007. Devi anche impostare ExpandedModeThresholdWidth per assicurare che i valori non siano in conflitto.

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

Compact

Un terzo modello adattivo comune è quello di utilizzare un riquadro a sinistra espanso su larghezze di finestre grandi e un riquadro di spostamento LeftCompact, solo a icona, su larghezze di finestre piccole e medie.

Ti consigliamo questo approccio quando:

  • È importante visualizzare sempre tutte le opzioni di spostamento sullo schermo.
  • Le categorie di spostamento possono essere rappresentate in modo chiaro con icone.

Left navigation compact adaptive behavior
Comportamento adattivo "compact" di NavigationView

Per configurare questo comportamento, imposta CompactModeThresholdWidth su 0.

<NavigationView CompactModeThresholdWidth="0"/>

Nessun comportamento adattivo

Per disabilitare il comportamento adattivo automatico, impostare PaneDisplayMode su un valore diverso da Auto. Qui è impostato su LeftMinimal, quindi viene mostrato solo il pulsante di menu indipendentemente dalla larghezza della finestra.

Left navigation no adaptive behavior
NavigationView con PaneDisplayMode impostato su LeftMinimal

<NavigationView PaneDisplayMode="LeftMinimal" />

Come descritto in precedenza nella sezione Modalità di visualizzazione, puoi impostare il riquadro in modo che sia sempre in alto, sempre espanso, sempre compatto o sempre minimo. Puoi anche gestire autonomamente le modalità di visualizzazione nel codice dell'app. Un esempio è illustrato nella sezione successiva.

Spostamento da superiore a sinistra

Quando si utilizza lo spostamento superiore nell'app, gli elementi di spostamento si comprimono in un menu extra al diminuire della larghezza della finestra. Quando la finestra dell'app è stretta, può offrire un'esperienza utente migliore per passare a PaneDisplayMode da Top a navigazione LeftMinimal , invece di consentire a tutti gli elementi di comprimere nel menu di overflow.

Ti consigliamo di utilizzare lo spostamento superiore nelle dimensioni di finestre grandi e lo spostamento a sinistra nelle dimensioni di finestre piccole:

  • Hai un gruppo di categorie di spostamento di primo livello altrettanto importanti da visualizzare insieme, in modo tale che se una categoria di questo gruppo non si adatta allo schermo, esegui la compressione passando allo spostamento a sinistra per attribuire la stessa importanza.
  • Vuoi mantenere quanto più spazio possibile per il contenuto nelle finestre piccole.

Questo esempio illustra come usare una proprietà VisualStateManager e AdaptiveTrigger.MinWindowWidth per passare da una navigazione all'altra TopLeftMinimal .

Example of top or left adaptive behavior 1

<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>

Suggerimento

Quando utilizzi AdaptiveTrigger.MinWindowWindowWidth, lo stato di visualizzazione si attiva quando la finestra è più ampia della larghezza minima specificata. In altri termini, il valore predefinito XAML definisce la finestra stretta e VisualState definisce le modifiche applicate quando la finestra diventa più ampia. Il valore predefinito PaneDisplayMode per NavigationView è Auto, quindi quando la larghezza della finestra è minore o uguale a CompactModeThresholdWidth, LeftMinimal viene usata la navigazione. Quando la finestra diventa più ampia, VisualState esegue l'override dell'impostazione predefinita e Top viene usata la navigazione.

NavigationView non esegue automaticamente alcuna attività di spostamento. Quando l'utente tocca un elemento di spostamento, NavigationView mostra l'elemento come selezionato e genera un evento ItemInvoked . Se il tocco genera la selezione di un nuovo elemento, viene generato anche un evento SelectionChanged.

Puoi gestire entrambi gli eventi per eseguire attività relative allo spostamento richiesto. La scelta di quale gestire dipende dal comportamento che desideri per la tua app. In genere, si passa alla pagina richiesta e si aggiorna l'intestazione NavigationView in risposta a questi eventi.

  • ItemInvoked viene generato ogni volta che l'utente tocca un elemento di spostamento, anche se è già selezionato. L'elemento può anche essere richiamato con un'azione equivalente usando mouse, tastiera o altro input. Per altre info, vedi Input e interazioni. Se si passa al gestore ItemInvoked, per impostazione predefinita, la pagina verrà ricaricata e viene aggiunta una voce duplicata allo stack di navigazione. Se navighi quando viene richiamato un elemento, devi impedire il ricaricamento della pagina o assicurarti che una voce duplicata non venga creata nel backstack di spostamento quando la pagina viene ricaricata. (Vedi gli esempi di codice).
  • SelectionChanged può essere attivato da un utente che richiama un elemento non selezionato attualmente o cambiando a livello di codice l'elemento selezionato. Se la modifica della selezione avviene perché un utente ha richiamato un elemento, l'evento ItemInvoked si verifica per primo. Se la modifica della selezione è a livello di codice, ItemInvoked non viene attivato.

Tutti gli elementi di navigazione fanno parte dello stesso modello di selezione, indipendentemente dal fatto che appartengano a MenuItems o a FooterMenuItems. È possibile selezionare un solo elemento di navigazione alla volta.

Spostamento indietro

NavigationView include un pulsante Indietro, ma, come per lo spostamento avanti, non esegue automaticamente lo spostamento indietro. Quando l'utente tocca il pulsante Indietro, viene attivato l'evento BackRequested. Puoi gestire questo evento per eseguire lo spostamento indietro. Per altre info ed esempi di codice, vedi Cronologia di spostamento e spostamento indietro.

In Minimal modalità o Compact , NavigationView Pane è aperto come riquadro a comparsa. In questo caso, facendo clic sul pulsante Indietro verrà chiuso Pane e verrà generato l'evento PaneClosing.

Puoi nascondere o disabilitare il pulsante Indietro impostando queste proprietà:

  • IsBackButtonVisible: consente di visualizzare e nascondere il pulsante Indietro. Questa proprietà accetta il valore dell'enumerazione NavigationViewBackButtonVisible ed è impostata su per Auto impostazione predefinita. Quando il pulsante è compresso, non viene riservato alcuno spazio nel layout.
  • IsBackEnabled: consente di abilitare o disabilitare il pulsante Indietro. Puoi eseguire il data binding di questa proprietà alla proprietà CanGoBack del tuo frame di navigazione. BackRequested non viene generato se IsBackEnabled è false.

NavigationView back button in the left navigation pane
Pulsante Indietro nel riquadro di spostamento sinistro

NavigationView back button in the top navigation pane
Pulsante indietro nel riquadro di spostamento superiore

Esempio di codice

Questo esempio mostra come è possibile utilizzare NavigationView sia con un riquadro di spostamento superiore su finestre grandi che con un riquadro di spostamento a sinistra su finestre piccole. Può essere adattato allo spostamento solo a sinistra rimuovendo le impostazioni di spostamento superiore in VisualStateManager.

L'esempio illustra un modo comune per configurare i dati di navigazione che funzioneranno per molti scenari. In questo esempio, si archivia prima (nel tag di NavigationViewItem) il nome completo della pagina a cui si desidera spostarsi. Nel gestore eventi deselezionare tale valore, trasformarlo in un oggetto Type(C#) o Windows::UI::Xaml::Interop::TypeName(C++/WinRT) e usarlo per passare alla pagina di destinazione. In questo modo è possibile creare unit test per verificare che i valori all'interno dei tag siano di un tipo valido. (Vedere ancheBoxing e unboxing dei valori in IInspectable con C++/WinRT). Viene inoltre illustrato come implementare lo spostamento indietro con il pulsante Indietro di NavigationView.

Questo codice presuppone che l'app contenga pagine con i nomi seguenti per passare a: HomePage, AppsPage, GamesPage, Musica Page, MyContentPage e Impostazioni Page. Il codice per queste pagine non è mostrato.

<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());
                        }
                    }
                }
            }
        }
    }
}

Spostamento gerarchico

Alcune app possono avere una struttura gerarchica più complessa che richiede più di un semplice elenco di elementi di spostamento. Può essere opportuno usare elementi di spostamento di primo livello per visualizzare categorie di pagine ed elementi figlio per visualizzare pagine specifiche. Una struttura di questo tipo è utile anche se sono presenti pagine di tipo hub che si collegano solo ad altre pagine. Per questi casi, è necessario creare un controllo NavigationView di tipo gerarchico.

Per visualizzare un elenco gerarchico di elementi di spostamento annidati nel riquadro, usa la proprietà MenuItems o la proprietà MenuItemsSource di NavigationViewItem. Ogni NavigationViewItem può contenere altri NavigationViewItem ed elementi di carattere organizzativo come le intestazioni e i separatori di elementi. Per visualizzare un elenco gerarchico quando usi MenuItemsSource, imposta ItemTemplate come NavigationViewItem e associa la relativa proprietà MenuItemsSource al livello successivo della gerarchia.

Anche se NavigationViewItem può contenere un numero qualsiasi di livelli annidati, è consigliabile mantenere superficiale la gerarchia di navigazione dell'app. Una gerarchia a due livelli è la soluzione ideale per assicurare usabilità e comprensione.

NavigationView mostra la gerarchia nelle Topmodalità di visualizzazione del riquadro , Lefte LeftCompact . Di seguito è illustrato l'aspetto di un sottoalbero espanso in ognuna delle modalità di visualizzazione del riquadro:

NavigationView with Hierarchy

Aggiunta di una gerarchia di elementi nel markup

Questo esempio mostra come dichiarare lo spostamento gerarchico delle app nel markup 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>

Aggiunta di una gerarchia di elementi tramite data binding

Puoi aggiungere una gerarchia di voci di menu a NavigationView nei modi seguenti:

  • Associando la proprietà MenuItemsSource ai dati gerarchici
  • Definendo il modello di elemento come NavigationViewMenuItem, con il relativo contenuto impostato come etichetta della voce di menu e la relativa proprietà MenuItemsSource associata al livello successivo della gerarchia

Questo esempio illustra anche gli eventi di espansione e compressione. Questi eventi vengono generati per una voce di menu con elementi figlio.

<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);
    }
}

Selezione

Per impostazione predefinita, qualsiasi elemento può contenere elementi figlio, essere richiamato o selezionato.

Quando si fornisce agli utenti una struttura gerarchica di opzioni di spostamento, è possibile scegliere di rendere non selezionabili gli elementi padre, ad esempio quando nell'app non è associata una pagina di destinazione a tali elementi. Se gli elementi padre sono selezionabili, è consigliabile usare la modalità di visualizzazione del riquadro Top o Left espansa. In modalità LeftCompact l'utente deve passare all'elemento padre per aprire il sottoalbero figlio ogni volta che viene richiamato.

Gli indicatori di selezione degli elementi vengono visualizzati lungo il bordo sinistro quando il riquadro è in modalità Left o lungo il bordo inferiore quando invece è in modalità Top. Di seguito sono riportati esempi di NavigationView in modalità Left e Top con un elemento padre selezionato.

NavigationView in left-mode with parent selected

NavigationView in top-mode with parent selected

È possibile che non sempre l'elemento selezionato rimanga visibile. Se è selezionato un elemento figlio in un sottoalbero compresso o non espanso, verrà visualizzato come selezionato il primo predecessore visibile. L'indicatore di selezione verrà spostato di nuovo sull'elemento selezionato se/quando il sottoalbero verrà espanso.

Nell'immagine precedente, ad esempio, l'utente potrebbe selezionare l'elemento del calendario e quindi comprimere il relativo sottoalbero. In questo caso, l'indicatore di selezione verrebbe visualizzato sotto l'elemento Account poiché Account è il primo predecessore visibile del calendario. L'indicatore di selezione passerà di nuovo all'elemento del calendario quando l'utente espanderà il sottoalbero.

L'intero controllo NavigationView visualizzerà un solo indicatore di selezione.

In entrambe le modalità Top e Left, quando fai clic sulle frecce di NavigationViewItem, il sottoalbero viene espanso o compresso. Quando fai clic o tocchi un punto diverso da NavigationViewItem, viene attivato l'evento ItemInvoked e anche in questo caso il sottoalbero viene compresso o espanso.

Per impedire a un elemento di mostrare l'indicatore di selezione quando viene richiamato, imposta su False la relativa proprietà SelectsOnInvoked, come illustrato di seguito:

<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);
}
...

Utilizzo dei tasti nel controllo NavigationView di tipo gerarchico

Gli utenti possono spostare lo stato attivo intorno a NavigationView usando la tastiera. I tasti di direzione espongono lo "spostamento interno" all'interno del riquadro e seguono le interazioni fornite nella visualizzazione ad albero. Le azioni dei tasti cambiano quando ti sposti nella struttura di NavigationView o nel relativo menu a comparsa, che viene visualizzato nelle modalità Top e LeftCompact di HierarchicalNavigationView. Di seguito sono riportate le azioni specifiche che ogni tasto può eseguire in un controllo NavigationView di tipo gerarchico:

Chiave In modalità Left In modalità Top Nel riquadro a comparsa
Freccia SU Sposta lo stato attivo sull'elemento immediatamente superiore a quello con stato attivo. Non esegue operazioni. Sposta lo stato attivo sull'elemento immediatamente superiore a quello con stato attivo.
Giù Sposta lo stato attivo sull'elemento immediatamente inferiore a quello con stato attivo.* Non esegue operazioni. Sposta lo stato attivo sull'elemento immediatamente inferiore a quello con stato attivo.*
Right Non esegue operazioni. Sposta lo stato attivo sull'elemento immediatamente a destra di quello con stato attivo. Non esegue operazioni.
Sinistra Non esegue operazioni. Sposta lo stato attivo sull'elemento immediatamente a sinistra di quello con stato attivo. Non esegue operazioni.
BARRA SPAZIATRICE/INVIO Se sono presenti elementi figlio, espande o comprime l'elemento e non cambia lo stato attivo. Se sono presenti elementi figlio, espande gli elementi figlio in un riquadro a comparsa e posiziona lo stato attivo sul primo elemento nel riquadro. Richiama o seleziona l'elemento e chiude il riquadro a comparsa.
ESC Non esegue operazioni. Non esegue operazioni. Chiude il riquadro a comparsa.

La BARRA SPAZIATRICE o il tasto INVIO richiama sempre o seleziona un elemento.

*Non è necessario che gli elementi siano visivamente adiacenti. Lo stato attivo passa dall'ultimo elemento nell'elenco del riquadro all'elemento delle impostazioni.

Sfondi del riquadro

Per impostazione predefinita, il riquadro NavigationView usa uno sfondo diverso a seconda della modalità di visualizzazione:

  • il riquadro è di colore grigio uniforme quando viene espanso a sinistra, fianco a fianco con il contenuto (in modalità Left).
  • il riquadro utilizza l'acrilico in-app quando è aperto come sovrimpressione sul contenuto (in modalità superiore, minima o compatta).

Per modificare lo sfondo del riquadro, puoi sovrascrivere le risorse del tema XAML usate per eseguire il rendering dello sfondo in ogni modalità. Questa tecnica viene usata al posto di una singola proprietà PaneBackground per supportare sfondi diversi per modalità di visualizzazione differenti.

Questa tabella mostra quale risorsa del tema viene utilizzata in ogni modalità di visualizzazione.

Display mode Risorsa del tema
Sinistra NavigationViewExpandedPaneBackground
LeftCompact
LeftMinimal
NavigationViewDefaultPaneBackground
In alto NavigationViewTopPaneBackground

Questo esempio mostra come sovrascrivere le risorse del tema in App.xaml. Quando sostituisci le risorse del tema, dovresti sempre fornire almeno i dizionari delle risorse "Default" e "HighContrast" e i dizionari per le risorse "Light" o "Dark" secondo le necessità. Per ulteriori informazioni, vedi ResourceDictionary.ThemeDictionaries.

Importante

Questo codice mostra come utilizzare la versione della Libreria dell'interfaccia utente di Windows di AcrylicBrush. Se invece usi la versione della piattaforma di AcrylicBrush, la versione minima per il tuo progetto app deve essere SDK 16299 o successiva. Per usare la versione della piattaforma, rimuovi tutti i riferimenti a 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>

Spazi vuoti superiori

Per la proprietà IsTitleBarAutoPaddingEnabled è richiesta la libreria dell'interfaccia utente di Windows 2.2 o versioni successive.

In alcuni casi puoi scegliere di personalizzare la barra del titolo della finestra, estendendo potenzialmente il contenuto dell'app nell'area della barra del titolo. Quando NavigationView è l'elemento radice nelle app che si estendono nella barra del titolo usando l'API ExtendViewIntoTitleBar, il controllo regola automaticamente la posizione degli elementi interattivi per impedire la sovrapposizione con l'area trascinabile.

An app extending into the title bar

Se l'app specifica l'area trascinabile chiamando il metodo Window.SetTitleBar e si preferisce che i pulsanti indietro e menu si avvicinino alla parte superiore della finestra dell'app, impostare IsTitleBarAutoPaddingEnabled su false.

App extending into the title bar without extra padding

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

Osservazioni:

Per regolare ulteriormente la posizione dell'area di intestazione di NavigationView, esegui l'override della risorsa del tema XAML NavigationViewHeaderMargin, ad esempio nelle risorse della pagina.

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

Questa risorsa del tema modifica il margine intorno a NavigationView.Header.