NavigationView

O controle NavigationView fornece navegação de nível superior para seu aplicativo. Ele se adapta a vários tamanhos de tela e é compatível com os estilos de navegação superior e esquerdo.

navegação superiorà esquerda
O NavigationView é compatível com o menu ou painel de navegação superior e esquerdo

Esse é o controle correto?

NavigationView é um controle de navegação adaptável que funciona bem para:

  • Fornecer uma experiência de navegação consistente em todos os aplicativos.
  • Preservar o estado real da tela de janelas menores.
  • Organizar o acesso a várias categorias de navegação.

Para outros padrões de navegação, confira Noções básicas de design de navegação.

UWP e WinUI 2

Importante

As informações e exemplos neste artigo são otimizados para aplicativos que usam o SDK do Aplicativo Windows e o WinUI 3, mas geralmente são aplicáveis a aplicativos UWP que usam o WinUI 2. Consulte a referência de API da UWP para obter informações e exemplos específicos da plataforma.

Esta seção contém informações necessárias para usar o controle em um aplicativo UWP ou WinUI 2.

O controle NavigationView para aplicativos UWP está incluído como parte do WinUI 2. Para obter mais informações, incluindo instruções de instalação, confira WinUI 2. As APIs para esse controle existem nos namespaces Windows.UI.Xaml.Controls e Microsoft.UI.Xaml.Controls.

É recomendável usar a WinUI 2 mais recente para obter os estilos, modelos e recursos mais atuais para todos os controles. Alguns recursos do NavigationView, como a navegação superior e hierárquica, exigem o Windows 10, versão 1809 (SDK 17763) ou superior ou a WinUI 2.

Para usar o código neste artigo com a WinUI 2, use um alias em XAML (usamos muxc) para representar as APIs da Biblioteca de Interface do Usuário do Windows incluídas em seu projeto. Confira Introdução à WinUI 2 para obter mais informações.

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

<muxc:NavigationView />

Criar uma exibição de navegação

O aplicativo Galeria da WinUI 3 inclui exemplos interativos da maioria dos controles, recursos e funcionalidades da WinUI 3. Obtenha o aplicativo na Microsoft Store ou o código-fonte no GitHub

Este exemplo mostra como criar uma exibição de navegação simples em 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>

Modos de exibição

Use a propriedade PaneDisplayMode para configurar os diferentes estilos de navegação ou modos de exibição para o NavigationView.

Parte superior

O painel está posicionado acima do conteúdo.
PaneDisplayMode="Top"

Exemplo de navegação superior

É recomendável a navegação superior quando:

  • Você tem cinco ou menos categorias de navegação de nível superior que são igualmente importantes, e qualquer categoria adicional de navegação de nível superior que termina no menu suspenso de estouro é considerada menos importante.
  • Você precisa mostrar todas as opções de navegação na tela.
  • Você deseja mais espaço para o conteúdo do aplicativo.
  • Os ícones não conseguem descrever claramente as categorias de navegação do seu aplicativo.

Esquerda

O painel é expandido e posicionado à esquerda do conteúdo.
PaneDisplayMode="Left"

Exemplo de painel de navegação esquerdo expandido

É recomendável a navegação à esquerda quando:

  • Você tem de cinco a dez categorias de navegação de nível superior igualmente importantes.
  • Você deseja que as categorias de navegação sejam proeminentes, com menos espaço para outros conteúdos do aplicativo.

LeftCompact

O painel mostra apenas os ícones até que seja aberto e está posicionado à esquerda do conteúdo. Quando aberto, o painel sobrepõe o conteúdo.
PaneDisplayMode="LeftCompact"

Exemplo de painel de navegação compacto à esquerda

LeftMinimal

Somente o botão de menu é exibido até abrir o painel. Quando aberto, o painel sobrepõe o lado esquerdo do conteúdo.
PaneDisplayMode="LeftMinimal"

Exemplo de painel de navegação mínimo à esquerda

Auto

Por padrão, o PaneDisplayMode é definido como Auto. No modo Auto, a NavigationView se adapta entre LeftMinimal quando a janela é estreita, para LeftCompact e, em seguida, Left conforme a janela fica mais ampla. Para saber mais, confira a seção comportamento adaptável.

Comportamento adaptável padrão da navegação à esquerda
Comportamento adaptável padrão do NavigationView

Anatomia

Essas imagens mostram o layout do painel, cabeçalho e áreas de conteúdo do controle quando configurado para navegação superior ou esquerda.

Layout de NavigationView superior
Layout de navegação superior

Layout de NavigationView à esquerda
Layout de navegação à esquerda

Painel

É possível usar a propriedade PaneDisplayMode para posicionar o painel acima do conteúdo ou à esquerda do conteúdo.

O painel NavigationView pode conter:

O painel esquerdo também contém:

  • Um botão de menu para alternar o painel entre aberto e fechado. Em janelas maiores do aplicativo quando o painel está aberto, opte por ocultar este botão usando a propriedade IsPaneToggleButtonVisible.

O NavigationView tem um botão Voltar posicionado no canto superior esquerdo do painel. No entanto, ele não controla automaticamente a navegação regressiva e adiciona conteúdo à pilha Voltar. Para habilitar a Navegação regressiva confira a seção correspondente.

Esta é a anatomia detalhada do painel nas posições superior e à esquerda.

Painel de navegação superior

Anatomia do painel superior do NavigationView

  1. Cabeçalhos
  2. Itens de navegação
  3. Separadores
  4. AutoSuggestBox (opcional)
  5. Botão Configurações (opcional)

Painel de navegação à esquerda

Anatomia do painel à esquerda do NavigationView

  1. Botão Menu
  2. Itens de navegação
  3. Separadores
  4. Cabeçalhos
  5. AutoSuggestBox (opcional)
  6. Botão Configurações (opcional)

Você pode usar FooterMenuItems para colocar os itens de navegação no final do painel de navegação, em contraste com a propriedade MenuItems que coloca os itens no início do painel.

O FooterMenuItems será exibido antes do item Settings por padrão. O item Settings ainda pode ser alternado usando a propriedade IsSettingsVisible.

Somente itens de Navegação devem ser colocado em FooterMenuItems – qualquer outro conteúdo que precise ser alinhado ao rodapé do painel deve ser colocado em PaneFooter.

Para obter um exemplo de como adicionar FooterMenuItems ao seu NavigationView, confira a classe FooterMenuItems.

A imagem abaixo mostra um NavigationView com os itens de navegação Conta, Seu Carrinho e Ajuda no menu de rodapé.

Um NavigationView com FooterMenuItems

Adicione conteúdo livremente ao rodapé do painel com a propriedade PaneFooter.

Rodapé do painel na navegação superior
Rodapé do painel superior

Rodapé do painel na navegação à esquerda
Rodapé do painel à esquerda

Cabeçalho e título do painel

Adicione conteúdo de texto à área de cabeçalho do painel definindo a propriedade PaneTitle. Ela usa uma cadeia de caracteres e mostra o texto ao lado do botão de menu.

Para adicionar conteúdo não textual, como uma imagem ou logotipo, coloque qualquer elemento no cabeçalho do painel adicionando-o à propriedade PaneHeader.

Se PaneTitle e PaneHeader estão definidas, o conteúdo é empilhado horizontalmente ao lado do botão de menu, com PaneTitle mais próximo ao botão do menu.

Cabeçalho do painel de navegação superior
Cabeçalho do painel superior

Cabeçalho do painel de navegação à esquerda
Cabeçalho do painel à esquerda

Conteúdo do painel

Adicione conteúdo livremente ao painel com a propriedade PaneCustomContent.

Conteúdo personalizado do painel na navegação superior
Conteúdo personalizado do painel superior

Conteúdo personalizado do painel na navegação à esquerda
Conteúdo personalizado do painel à esquerda

Adicione um título de página definindo a propriedade Header.

Exemplo da área de cabeçalho do NavigationView
Cabeçalho do NavigationView

A área do cabeçalho é alinhada verticalmente com o botão de navegação na posição do painel à esquerda e se encontra abaixo do painel na posição do painel superior. Ele tem uma altura fixa de 52 px. Sua finalidade é conter o título da página da categoria de navegação selecionada. O cabeçalho é ancorado à parte superior da página e atua como um ponto de corte de rolagem para a área de conteúdo.

O cabeçalho fica visível sempre que o NavigationView está no modo de exibição Minimal. É possível escolher ocultar o cabeçalho em outros modos, que são usados em larguras de janela maiores. Para ocultar o cabeçalho, defina a propriedade AlwaysShowHeader como false.

Conteúdo

Exemplo da área de conteúdo do NavigationView
Conteúdo do NavigationView

A área de conteúdo é onde a maioria das informações da categoria de navegação selecionada é exibida.

É recomendável usar margens de 12 px na área do conteúdo quando NavigationView está no modo Minimal, caso contrário, use margens de 24 px.

Comportamento adaptável

Por padrão, o NavigationView muda automaticamente a exibição com base na quantidade de espaço disponível na tela. As propriedades CompactModeThresholdWidth e ExpandedModeThresholdWidth especificam os pontos de interrupção nos quais o modo de exibição é alterado. É possível modificar esses valores para personalizar o comportamento do modo de exibição adaptável.

Padrão

Quando PaneDisplayMode é definido com o valor padrão Auto, o comportamento adaptável é exibir:

  • Um painel expandido à esquerda em larguras de janelas grandes (1008px ou superior).
  • À esquerda, somente ícones, painel de navegação (LeftCompact) em larguras de janelas médias (641 px a 1007 px).
  • Apenas um botão de menu (LeftMinimal) em larguras de janelas pequenas (640 px ou menos).

Para saber mais sobre os tamanhos de janelas para o comportamento adaptável, confira Tamanhos de tela e pontos de interrupção.

Comportamento adaptável padrão da navegação à esquerda
Comportamento adaptável padrão do NavigationView

Minimal

Um segundo padrão adaptável comum é usar um painel expandido à esquerda em larguras de janelas grandes e apenas um botão de menu em larguras de janelas médias e pequenas.

Recomendamos isso quando:

  • Você deseja mais espaço para o conteúdo do aplicativo em larguras de janela pequenas.
  • Suas categorias de navegação não podem ser representadas claramente com ícones.

Comportamento adaptável mínimo de navegação à esquerda
Comportamento adaptável "mínimo" do NavigationView

Para configurar esse comportamento, defina CompactModeThresholdWidth à largura na qual você deseja que o painel seja recolhido. Aqui, ele é alterado do padrão de 640 para 1007. Você também precisa definir ExpandedModeThresholdWidth para garantir que os valores não entrem em conflito.

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

Compacto

Um terceiro padrão adaptável comum é usar um painel expandido à esquerda em larguras de janela grandes e apenas um painel de navegação LeftCompact, somente com ícones, nas larguras de janela médias e pequenas.

Recomendamos isso quando:

  • É importante sempre mostrar todas as opções de navegação na tela.
  • Suas categorias de navegação podem ser representadas claramente com ícones.

Comportamento adaptável compacto de navegação à esquerda
Comportamento adaptável "compacto" do NavigationView

Para configurar esse comportamento, defina CompactModeThresholdWidth como 0.

<NavigationView CompactModeThresholdWidth="0"/>

Sem comportamento adaptável

Para desabilitar o comportamento adaptável automático, defina o PaneDisplayMode com um valor diferente de Auto. Aqui, ele está definido como LeftMinimal, portanto, somente o botão de menu é exibido, independentemente da largura da janela.

Navegação à esquerda sem comportamento adaptável
NavigationView com PaneDisplayMode definido como LeftMinimal

<NavigationView PaneDisplayMode="LeftMinimal" />

Como descrito anteriormente na seção Modos de exibição, é possível configurar o painel para estar sempre visível, sempre expandido, sempre compacto ou sempre mínimo. Também é possível gerenciar os modos de exibição no código do aplicativo. Um exemplo disso é exibido na próxima seção.

Navegação da parte superior para a esquerda

Ao usar o painel de navegação superior no seu aplicativo, os itens de navegação são recolhidos em um menu de estouro conforme a largura de janela diminui. Se a janela de aplicativo for estreita, a experiência do usuário pode melhorar quando se alterna o PaneDisplayMode da navegação de Top para LeftMinimal, ao invés de recolher todos os itens em um menu suspenso.

É recomendável usar a navegação superior em tamanhos de janela grandes e a navegação à esquerda em tamanhos de janela pequenos quando:

  • Você tem um conjunto de categorias de navegação de nível superior igualmente importantes para serem exibidas juntas de modo que, se uma categoria desse conjunto não couber na tela, você recolhe para navegação à esquerda para dar a todas a mesma importância.
  • Você deseja preservar o máximo de espaço de conteúdo possível em tamanhos de janela pequenos.

Este exemplo mostra como usar uma propriedade VisualStateManager e AdaptiveTrigger.MinWindowWidth para alternar entre a navegação Top e LeftMinimal.

Exemplo de comportamento adaptável superior ou à esquerda 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>

Dica

Ao usar AdaptiveTrigger.MinWindowWidth, o estado visual é acionado quando a janela é maior do que a largura mínima especificada. Isso significa que o XAML padrão define a janela estreita e o VisualState define as modificações aplicadas quando a janela é ampliada. O PaneDisplayMode padrão para o NavigationView é Automático, portanto, quando a largura da janela é menor ou igual a CompactModeThresholdWidth, usa-se a navegação LeftMinimal. Quando a janela é ampliada, o VisualState substitui o padrão, e usa-se o painel de navegação Top.

O NavigationView não realiza nenhuma tarefa de navegação automaticamente. Quando o usuário toca em um item de navegação, o NavigationView mostra esse item como selecionado e gera um evento ItemInvoked. Se o toque resultar em um novo item sendo selecionado, também é gerado um evento SelectionChanged.

É possível manipular o evento para executar tarefas relacionadas à navegação solicitada. O comportamento desejado para seu aplicativo vai definir com qual deles você lidará. Normalmente, é possível navegar até a página solicitada e atualizar o cabeçalho do NavigationView em resposta a esses eventos.

  • O ItemInvoked é gerado sempre que o usuário toca em um item de navegação, mesmo se ele já estiver selecionado. (O item também pode ser invocado com uma ação equivalente usando mouse, teclado ou outra entrada. Para obter mais informações, consulte Entrada e interações.) Caso navegue no manipulador ItemInvoked, por padrão, a página será recarregada e uma entrada duplicada será adicionada à pilha de navegação. Se você navegar quando um item for chamado, precisará proibir o recarregamento da página ou garantir que uma entrada duplicada não seja criada no backstack de navegação ao recarregar a página. (Veja os exemplos de código.)
  • SelectionChanged pode ser gerado por um usuário chamando um item que não está selecionado ou alterando o item selecionado via programação. Se a alteração da seleção ocorreu porque um usuário chamou um item, o evento ItemInvoked ocorre primeiro. Se a alteração da seleção ocorreu via programação, ItemInvoked não será gerado.

Todos os itens de navegação fazem parte do mesmo modelo de seleção, sejam eles parte de MenuItems ou FooterMenuItems. Somente um item de navegação pode ser selecionado de cada vez.

Navegação regressiva

O NavigationView tem um botão Voltar interno, mas, assim como acontece com a navegação progressiva, ele não realiza a navegação regressiva automaticamente. Quando o usuário toca no botão Voltar, o evento BackRequested é gerado. Manipule esse evento para executar a navegação regressiva. Para saber mais e obter exemplos de código, confira Histórico de navegação e navegação regressiva.

No modo Minimal ou Compact, o NavigationView Pane é aberto como um submenu. Nesse caso, selecionar o botão Voltar fecha o Pane e gera o evento PaneClosing.

É possível ocultar ou desabilitar o botão Voltar configurando essas propriedades:

  • IsBackButtonVisible: use para mostrar e ocultar o botão Voltar. Essa propriedade usa um valor da enumeração NavigationViewBackButtonVisible e é configurada como Auto por padrão. Quando o botão é recolhido, nenhum espaço fica reservado para ele no layout.
  • IsBackEnabled: use para habilitar ou desabilitar o botão Voltar. É possível associar os dados dessa propriedade à propriedade CanGoBack de seu quadro de navegação. BackRequested não é gerado se IsBackEnabled é false.

Botão Voltar do NavigationView no painel de navegação à esquerda
O botão voltar no painel de navegação à esquerda

Botão Voltar do NavigationView no painel de navegação superior
O botão voltar no painel de navegação superior

Exemplo de código

Este exemplo mostra como usar o NavigationView com um painel de navegação superior em tamanhos de janela grandes e um painel de navegação à esquerda em tamanhos de janela pequenos. Ele pode ser adaptado para navegação somente à esquerda ao remover as configurações de navegação top no VisualStateManager.

O exemplo demonstra a maneira comum de configurar dados de navegação que funcionarão para diversos cenários. Neste exemplo, você primeiro armazena (na marca do NavigationViewItem) o nome completo do tipo da página em que quer navegar. No manipulador de eventos, é possível converter esse valor, transformá-lo em um objeto Tipo(C#) ou Windows::UI::Xaml::Interop::TypeName (C++/WinRT) e usá-lo para navegar até a página de destino. Isso permite criar testes de unidade para confirmar se os valores dentro de suas marcas são de um tipo válido. (Confira também Fazer conversões boxing e unboxing de valores para IInspectable com C++/WinRT). Ele também demonstra como implementar a navegação regressiva com o botão Voltar do NavigationView.

Esse código pressupõe que seu aplicativo contém páginas com os seguintes nomes: HomePage, AppsPage, GamesPage, MusicPage, MyContentPage e SettingsPage. O código dessas páginas não é exibido.

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

Navegação hierárquica

Alguns aplicativos podem ter uma estrutura hierárquica mais complexa que exija mais do que apenas uma lista simples de itens de navegação. Talvez seja interessante usar itens de navegação de nível superior para exibir categorias de páginas, com itens filhos exibindo páginas específicas. Também será útil se você tiver páginas de estilo de hub que só se vinculem a outras páginas. Para esses tipos de casos, você deve criar um NavigationView hierárquico.

Para mostrar uma lista hierárquica de itens de navegação aninhados no painel, use a propriedade MenuItems ou a propriedade MenuItemsSource de NavigationViewItem. Cada NavigationViewItem pode conter outros NavigationViewItems e elementos de organização, como cabeçalhos e separadores de itens. Para mostrar uma lista hierárquica ao usar MenuItemsSource, defina o ItemTemplate como um NavigationViewItem e associe a propriedade MenuItemsSource dele ao próximo nível da hierarquia.

Embora o NavigationViewItem possa conter vários níveis aninhados, recomendamos manter uma hierarquia de navegação do aplicativo superficial. Acreditamos que dois níveis são ideais para usabilidade e compreensão.

O NavigationView mostra a hierarquia nos modos de exibição de painel Top, Left e LeftCompact. Veja como é a aparência de uma subárvore expandida em cada um dos modos de exibição de painel:

NavigationView com hierarquia

Adicionar uma hierarquia de itens na marcação

Este exemplo mostra como declarar a navegação hierárquica do aplicativo na marcação 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>

Adicionar uma hierarquia de itens usando a associação de dados

Adicione uma hierarquia de itens de menu ao NavigationView

  • associando a propriedade MenuItemsSource aos dados hierárquicos
  • que definem o modelo de item a ser um NavigationViewMenuItem, com o conjunto de conteúdo definido como o rótulo do item de menu e a propriedade MenuItemsSource associada ao próximo nível da hierarquia

Este exemplo também demonstra os eventos de Expansão e Recolhimento. Esses eventos são gerados para um item de menu com filhos.

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

Seleção

Por padrão, qualquer item pode conter filhos, ser invocado ou ser selecionado.

Ao fornecer aos usuários uma árvore hierárquica de opções de navegação, você pode optar por tornar itens pai não selecionáveis, por exemplo, quando seu aplicativo não tem uma página de destino associada a esse item pai. Se os itens pai forem selecionáveis, é recomendável usar os modos de exibição de painel Left-Expanded ou Superior. O modo LeftCompact fará o usuário navegar até o item pai a fim de abrir a subárvore filha sempre que ela for invocada.

Os itens selecionados desenharão indicadores de seleção ao longo da borda esquerda quando estiverem no modo esquerdo ou na borda inferior quando estiverem no modo superior. Abaixo estão NavigationViews nos modos esquerdo e superior em que um item pai está selecionado.

NavigationView no modo esquerdo com pai selecionado

NavigationView no modo superior com pai selecionado

O item selecionado pode nem sempre permanecer visível. Se um filho em uma subárvore recolhida/não expandida for selecionado, o primeiro ancestral visível será exibido como selecionado. O indicador de seleção voltará para o item selecionado se/quando a subárvore for expandida.

Por exemplo, na imagem acima, o item Calendário pode ser selecionado pelo usuário e o usuário pode recolher a subárvore dele. Nesse caso, o indicador de seleção apareceria abaixo do item Conta, pois a Conta é o primeiro ancestral visível do Calendário. O indicador de seleção será movido de volta para o item Calendário à medida que o usuário expandir a subárvore novamente.

O NavigationView inteiro mostrará, no máximo, um indicador de seleção.

Nos modos Superior e Esquerdo, clicar nas setas em NavigationViewItems expandirá ou recolherá a subárvore. Clicar ou tocar em em outro lugar no NavigationViewItem vai disparar o evento ItemInvoked e também vai recolher ou expandir a subárvore.

Para impedir que um item mostre o indicador de seleção quando invocado, defina a propriedade SelectsOnInvoked dele como False, conforme mostrado abaixo:

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

Teclado no NavigationView hierárquico

Os usuários podem mover o foco ao redor do NavigationView usando o teclado. As teclas de seta expõem a “navegação interna” com o painel e seguem as interações fornecidas no modo de exibição de árvore. As principais ações mudam ao navegar pelo NavigationView ou pelo submenu dele, exibido nos modos Superior e Left-compact do HierarchicalNavigationView. Abaixo estão as ações específicas de cada tecla em um NavigationView hierárquico:

Chave No modo Left No modo Superior No submenu
Up Move o foco para o item diretamente acima do item em foco no momento. Não faz nada. Move o foco para o item diretamente acima do item em foco no momento.
Down Move o foco diretamente abaixo do item em foco no momento.* Não faz nada. Move o foco diretamente abaixo do item em foco no momento.*
Direita Não faz nada. Move o foco para o item diretamente à direita do item em foco no momento. Não faz nada.
Esquerda Não faz nada. Move o foco para o item diretamente à esquerda do item em foco no momento. Não faz nada.
Espaço/Enter Se o item tem filhos, expande/recolhe o item e não altera o foco. Se o item tem filhos, expande os filhos para um submenu e coloca o foco no primeiro item do submenu. Invoca/seleciona o item e fecha o submenu.
Esc Não faz nada. Não faz nada. Fecha o submenu.

A tecla de espaço ou enter sempre invoca/seleciona um item.

*Observe que os itens não precisam ser visualmente adjacentes, o foco será movido do último item na lista do painel para o item de configurações.

Telas de fundo do painel

Por padrão, o painel do NavigationView usa uma tela de fundo diferente que depende do modo de exibição:

  • O painel tem uma cor cinza sólida quando expandido à esquerda, lado a lado com o conteúdo (no modo à esquerda).
  • O painel usa acrílico do aplicativo quando abre como uma sobreposição sobre o conteúdo (no modo compacto, mínimo ou superior).

Para modificar a tela de fundo do painel, substitua os recursos de tema do XAML usados para renderizar a tela de fundo em cada modo. (Essa técnica é usada em vez da propriedade PaneBackground individual para dar suporte a telas de fundo diferentes para vários modos de exibição.)

Essa tabela mostra quais recursos de temas são usados em cada modo de exibição.

Modo de exibição Recursos de tema
Esquerda NavigationViewExpandedPaneBackground
LeftCompact
LeftMinimal
NavigationViewDefaultPaneBackground
Parte superior NavigationViewTopPaneBackground

Este exemplo mostra como substituir os recursos de tema em App.xaml. Ao substituir os recursos de tema, forneça sempre no mínimo os dicionários de recursos "Default" e "HighContrast" e os dicionários para os recursos "Light" ou "Dark", conforme necessário. Para saber mais, confira ResourceDictionary.ThemeDictionaries.

Importante

Este código mostra como usar a versão da WinUI 2 do AcrylicBrush. Se, em vez disso, você usar a versão da plataforma do AcrylicBrush, a versão mínima para seu projeto de aplicativo deverá ser a SDK 16299 ou posterior. Para usar a versão da plataforma, remova todas as referências 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>

Espaço em branco na parte superior

A propriedade IsTitleBarAutoPaddingEnabled requer WinUI 2.2 ou posterior.

Alguns aplicativos optam por personalizar a barra de título da janela, potencialmente estendendo o conteúdo do aplicativo para a área da barra de título. Quando NavigationView é o elemento raiz em aplicativos que se estendem para a barra de título usando a API ExtendViewIntoTitleBar , o controle ajusta automaticamente a posição dos próprios elementos interativos para evitar sobreposição com a região arrastável.

Um aplicativo que se estende para a barra de título

Se o aplicativo especifica a região arrastável chamando o método Window.SetTitleBar e você prefere fazer com que os botões voltar e menu fiquem mais perto da parte superior da janela do aplicativo, defina IsTitleBarAutoPaddingEnabled como false.

Aplicativo estendendo-se para a barra de título sem preenchimento extra

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

Comentários

Para ajustar ainda mais a posição da área de cabeçalho de NavigationView, substitua o recurso de tema XAML NavigationViewHeaderMargin, por exemplo, em seus Recursos de página.

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

Esse recurso de tema modifica a margem em volta de NavigationView.Header.