NavigationView
El control NavigationView proporciona navegación de nivel superior para la aplicación. Se adapta a distintos tamaños de pantalla y admite los estilos de navegación superior e izquierdo.
NavigationView admite el menú o panel de navegación superior e izquierdo
¿Es este el control adecuado?
NavigationView es un control de navegación adaptable que funciona bien para:
- Proporcionar una experiencia de navegación coherente entre aplicaciones.
- Conservar la superficie de pantalla en ventanas más pequeñas
- Organizar el acceso a muchas categorías de navegación
Para información sobre otros patrones de navegación, consulta Conceptos básicos del diseño de navegación.
UWP y WinUI 2
Importante
La información y los ejemplos de este artículo están optimizados para aplicaciones que usan el SDK de Aplicaciones para Windows y WinUI 3, pero generalmente son aplicables a las aplicaciones para UWP que usan WinUI 2. Consulte el material de referencia de las API de UWP para obtener información y ejemplos específicos de la plataforma.
Esta sección contiene información que necesita para usar el control en una aplicación para UWP o WinUI 2.
El control NavigationView para aplicaciones para UWP se incluye como parte de WinUI 2. Para obtener más información e instrucciones sobre la instalación, consulta el artículo WinUI 2. Hay API para este control en los espacios de nombres Windows.UI.Xaml.Controls y Microsoft.UI.Xaml.Controls.
- API de UWP: clase Windows.UI.Xaml.Controls.NavigationView
- Api de WinUI 2: clase Microsoft.UI.Xaml.Controls.NavigationView
- Abre la aplicación WinUI 2 Gallery para ver NavigationView en acción. La aplicación WinUI 2 Gallery incluye ejemplos interactivos de la mayoría de los controles, características y funcionalidades de WinUI 2. Obtenga la aplicación en Microsoft Store u obtenga el código fuente en GitHub.
Se recomienda usar la versión más reciente de WinUI 2 para obtener los estilos, las plantillas y las características más actuales de todos los controles. Algunas características de NavigationView, como la navegación superior y jerárquica, requieren Windows 10, versión 1809 (SDK 17763) o posterior, o WinUI 2.
Para usar el código de este artículo con WinUI 2, use un alias en XAML (usamos muxc
) para representar las API de la Biblioteca de interfaz de usuario de Windows que se incluyen en el proyecto. Consulte Introducción a la Biblioteca de interfaz de usuario de Windows 2 para obtener más información.
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
<muxc:NavigationView />
Creación de una vista de navegación
- API importantes: Clase NavigationView
La aplicación WinUI 3 Gallery incluye ejemplos interactivos de la mayoría de los controles, las características y la funcionalidad de WinUI 3. Obtenga la aplicación en Microsoft Store o el código fuente en GitHub.
Este ejemplo muestra cómo crear una vista de navegación sencilla en XAML.
<NavigationView>
<NavigationView.MenuItems>
<NavigationViewItem Content="Nav Item A"/>
<NavigationViewItem Content="Nav Item B"/>
<NavigationViewItem Content="Nav Item C"/>
</NavigationView.MenuItems>
<Frame x:Name="ContentFrame"/>
</NavigationView>
Modos de pantalla
Puedes usar la propiedad PaneDisplayMode para configurar diferentes estilos de navegación, o modos de pantalla, para NavigationView.
Superior
El panel se pone encima del contenido.PaneDisplayMode="Top"
La navegación superior se recomienda en los siguientes casos:
- Tienes cinco o menos categorías de navegación de nivel superior que son igual de importantes, y el resto de estas categorías que acaban en el menú desplegable de desbordamiento se consideran menos importantes.
- Debes mostrar en pantalla todas las opciones de navegación.
- Quieres tener más espacio para el contenido de la aplicación.
- Los iconos no pueden describir claramente las categorías de navegación de la aplicación.
Izquierda
El panel se expande y se pone a la izquierda del contenido.PaneDisplayMode="Left"
Se recomienda la navegación izquierda en los siguientes casos:
- Tienes entre 5 y 10 categorías de navegación de nivel superior igual de importantes.
- Quieres que destaquen, y destinar menos espacio a otro contenido de la aplicación.
LeftCompact
El panel muestra solo los iconos hasta que se abre y se coloca a la izquierda del contenido. Al abrirlo, el panel se superpone sobre el contenido.PaneDisplayMode="LeftCompact"
LeftMinimal
El botón de menú solo se muestra hasta que se abre el panel. Al abrirlo, el panel se superpone sobre el lado izquierdo del contenido.PaneDisplayMode="LeftMinimal"
Automático
De forma predeterminada, PaneDisplayMode está establecido en Auto
. En el modo Auto
, NavigationView se adapta a LeftMinimal
cuando la ventana es estrecha, LeftCompact
y después Left
conforme la ventana se hace más ancha. Para más información, consulte la sección Comportamiento adaptable.
Comportamiento adaptable predeterminado de NavigationView
Anatomía
Estas imágenes muestran el diseño del panel, el encabezado y las áreas de contenido del control cuando se configuran para los estilos de navegación superior o izquierdo.
Diseño de navegación superior
Diseño de navegación izquierda
Panel
Puedes usar la propiedad PaneDisplayMode para colocar el panel encima del contenido o a su izquierda.
El panel NavigationView puede contener:
- Objetos NavigationViewItem. Elementos de navegación para ir a páginas concretas.
- Objetos NavigationViewItemSeparator. Separadores para agrupar los elementos de navegación. Establece la propiedad Opacity en 0 para representar el separador como espacio.
- Objetos NavigationViewItemHeader. Encabezados para etiquetar grupos de elementos.
- Un control AutoSuggestBox opcional para permitir la búsqueda en el nivel de aplicación. Asigna al control la propiedad NavigationView.AutoSuggestBox.
- Un punto de entrada opcional para la configuración de la aplicación. Para ocultar el elemento de configuración, establece la propiedad IsSettingsVisible en
false
.
El panel izquierdo también contiene:
- Un botón de menú para alternar entre panel abierto y cerrado. En ventanas de aplicación más grandes, cuando el panel está abierto, puedes ocultar este botón mediante la propiedad IsPaneToggleButtonVisible.
NavigationView tiene un botón Atrás situado en la esquina superior izquierda del panel. Sin embargo, no controla automáticamente la navegación hacia atrás y agrega contenido a la pila de retroceso. Para habilitar la navegación hacia atrás, consulta la sección Navegación hacia atrás.
Esta es la anatomía detallada de las posiciones del panel superior e izquierdo.
Panel de navegación superior
- Encabezados
- Elementos de navegación
- Separadores
- AutoSuggestBox (opcional)
- Botón de configuración (opcional)
Panel de navegación izquierdo
- Botón de menú
- Elementos de navegación
- Separadores
- Encabezados
- AutoSuggestBox (opcional)
- Botón de configuración (opcional)
Elementos del menú de pie de página
Puede usar FooterMenuItems para colocar los elementos de navegación al final del panel de navegación (en comparación con la propiedad MenuItems, que coloca los elementos al principio del panel).
FooterMenuItems se mostrará antes que el elemento Settings
de manera predeterminada. El elemento Settings
todavía se puede alternar con la propiedad IsSettingsVisible
.
Solo los elementos de navegación deben colocarse en FooterMenuItems: cualquier otro contenido que deba alinearse con el pie de página del panel debe colocarse en PaneFooter.
Para obtener un ejemplo de cómo agregar FooterMenuItems a NavigationView, consulte la clase FooterMenuItems.
En la siguiente imagen se muestra un control NavigationView con los elementos de navegación Cuenta, Su carro y Ayuda en el menú de pie de página.
Pie de página del panel
Puedes colocar contenido de formato libre en el pie de página del panel con solo agregarlo a la propiedad PaneFooter.
Pie de página del panel superior
Pie de página del panel izquierdo
Encabezado y título del panel
Puedes colocar contenido de texto en el área de encabezado del panel mediante la propiedad PaneTitle. Esta propiedad toma una cadena y muestra el texto situado junto al botón de menú.
Para agregar contenido que no sea texto, como imágenes o logotipos, agrega a la propiedad PaneHeader los elementos que quieras colocar en el encabezado del panel.
Si ambas propiedades, PaneTitle y PaneHeader, están establecidas, el contenido se apila horizontalmente junto al botón de menú, con la propiedad PaneTitle más cercana al botón de menú.
Encabezado del panel superior
Encabezado del panel izquierdo
Contenido del panel
Puedes colocar contenido de formato libre en el panel si lo agregas a la propiedad PaneCustomContent.
Contenido personalizado del panel superior
Contenido personalizado del panel izquierdo
Header
Puedes agregar un título de página mediante la propiedad Header.
Encabezado de NavigationView
El área de encabezado se alinea verticalmente con el botón de navegación en la posición del panel izquierdo y yace debajo del panel en la posición del panel superior. Tiene una altura fija de 52 px. Su finalidad es contener el título de la página de la categoría de navegación seleccionada. El encabezado se acopla a la parte superior de la página y actúa como punto de recorte de desplazamiento para el área de contenido.
El encabezado está visible cada vez que el control NavigationView está en el modo de presentación Minimal
. Puedes elegir ocultar el encabezado en otros modos, que se usan en anchos de ventana mayores. Para ocultar el encabezado, establece la propiedad AlwaysShowHeader en false
.
Contenido
Contenido de NavigationView
El área de contenido es donde se muestra la mayor parte de la información para la categoría de navegación seleccionada.
Te recomendamos márgenes de 12 píxeles en el área de contenido cuando NavigationView se encuentre en el modo Minimal
y márgenes de 24 píxeles en caso contrario.
Comportamiento adaptable
De manera predeterminada, NavigationView cambia automáticamente su modo de pantalla en función de la cantidad de espacio en pantalla que tiene a su disposición. Las propiedades CompactModeThresholdWidth y ExpandedModeThresholdWidth especifican los puntos de interrupción en los que el modo de pantalla cambia. Puedes modificar estos valores para personalizar el comportamiento del modo de pantalla adaptable.
Valor predeterminado
Cuando PaneDisplayMode está establecido en su valor predeterminado de Auto
, el comportamiento adaptable es mostrar:
- Un panel izquierdo expandido en anchos de ventana grandes (1008 px o mayor).
- Un panel de navegación izquierdo solo con iconos (
LeftCompact
) con un ancho de ventana medio (de 641 px a 1007 px). - Solo un botón de menú (
LeftMinimal
) con un ancho de ventana pequeño (640 px o menos).
Para más información sobre los tamaños de ventana para el comportamiento adaptable, consulta Tamaños de pantalla y puntos de interrupción.
Comportamiento adaptable predeterminado de NavigationView
Mínimo
Un segundo patrón adaptable común es usar un panel izquierdo expandido en anchos de ventana grandes y solo un botón de menú en anchos de ventana pequeños y medianos.
Este patrón se recomienda en los siguientes casos:
- Quieres más espacio para el contenido de la aplicación en anchos de ventana más pequeños.
- Las categorías de navegación no se pueden representar claramente con iconos.
Comportamiento adaptable "mínimo" de NavigationView
Para configurar este comportamiento, establece CompactModeThresholdWidth en el ancho en el que quieres que se contraiga el panel. En este caso, se cambia el valor predeterminado de 640 a 1007. También debes establecer ExpandedModeThresholdWidth para asegurarte de que los valores no entran en conflicto.
<NavigationView CompactModeThresholdWidth="1007" ExpandedModeThresholdWidth="1007"/>
Compacto
Un tercer patrón adaptable común es usar un panel izquierdo expandido en anchos de ventana grandes y un panel de navegación LeftCompact solo de iconos en anchos de ventana pequeños y medianos.
Este patrón se recomienda en los siguientes casos:
- Es importante mostrar siempre todas las opciones de navegación en la pantalla.
- Las categorías de navegación se pueden representar claramente con iconos.
Comportamiento adaptable "compacto" de NavigationView
Para configurar este comportamiento, establece CompactModeThresholdWidth en 0.
<NavigationView CompactModeThresholdWidth="0"/>
Sin comportamiento adaptable
Para deshabilitar el comportamiento adaptable automático, establezca PaneDisplayMode en un valor distinto de Auto
. En este caso, se establece en LeftMinimal, así que solo se muestra el botón de menú, con independencia del ancho de ventana.
NavigationView con PaneDisplayMode establecido en LeftMinimal
<NavigationView PaneDisplayMode="LeftMinimal" />
Como se describió anteriormente en la sección Modos de pantalla, puedes configurar el panel para que siempre esté arriba, siempre expandido, siempre compacto o siempre mínimo. También puedes administrar los modos de pantalla por tu cuenta en el código de la aplicación. En la sección siguiente se muestra un ejemplo de esto.
Navegación de arriba hacia la izquierda
Cuando usas la navegación superior en la aplicación, los elementos de navegación se contraen en un menú de desbordamiento a medida que el ancho de ventana disminuye. Cuando la ventana de la aplicación es estrecha, se puede proporcionar una mejor experiencia de usuario si se cambia PaneDisplayMode de la navegación Top
a LeftMinimal
, en lugar de permitir que todos los elementos se contraigan en el menú de desbordamiento.
Se recomienda usar la navegación superior en tamaños de ventana grandes y la navegación izquierda en tamaños de ventana pequeños en los siguientes casos:
- Tienes un conjunto de categorías de navegación de nivel superior igual de importantes para mostrarse juntas, de forma que si una categoría de este conjunto no cabe en la pantalla, la contraes al panel de navegación izquierdo para darle la misma importancia.
- Deseas conservar tanto espacio de contenido como sea posible en los tamaños de ventana pequeños.
En este ejemplo se muestra cómo usar las propiedades VisualStateManager y AdaptiveTrigger.MinWindowWidth para cambiar entre la navegación Top
y la navegación LeftMinimal
.
<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>
Sugerencia
Cuando usas AdaptiveTrigger.MinWindowWidth, el estado visual se desencadena cuando la ventana es más ancha que el ancho mínimo especificado. Esto significa que el código XAML predeterminado define la ventana estrecha y VisualState define las modificaciones que se aplican cuando la ventana se ensancha. La propiedad PaneDisplayMode predeterminada de NavigationView es Auto, de modo que, cuando el ancho de la ventana es menor o igual que CompactModeThresholdWidth
, se usa la navegación LeftMinimal
. Cuando la ventana se ensancha, VisualState invalida el valor predeterminado y se usa la navegación Top
.
Navegación
NavigationView no realiza automáticamente ninguna tarea de navegación. Cuando el usuario pulsa en un elemento de navegación, NavigationView muestra ese elemento como seleccionado y genera un evento ItemInvoked. Si la pulsación da lugar a la selección de un nuevo elemento, también se genera un evento SelectionChanged.
Puedes controlar cualquier evento para realizar tareas relacionadas con la navegación solicitada. Que debas controlar uno u otro depende del comportamiento que quieras para la aplicación. Normalmente, va a la página solicitada y actualiza el encabezado de NavigationView en respuesta a estos eventos.
- ItemInvoked se produce siempre que el usuario pulsa en un elemento de navegación, incluso si ya está seleccionado. El elemento también se puede invocar con una acción equivalente usando el mouse, el teclado u otro tipo de entrada. Para obtener más información, consulte Entrada e interacciones. Si navega por el controlador ItemInvoked, de forma predeterminada, se volverá a cargar la página y se agregará una entrada duplicada a la pila de navegación. Si navegas cuando se invoca un elemento, debes impedir que se vuelva a cargar la página, o asegúrate de que no se crea una entrada duplicada en la pila de retroceso de navegación cuando se vuelve a cargar la página. (Mira los ejemplos de código).
- SelectionChanged puede generarse cuando un usuario invoca un elemento que no está seleccionado actualmente o cambia el elemento seleccionado mediante programación. Si el cambio de selección se produce porque un usuario invocó un elemento, el evento ItemInvoked se produce primero. Si el cambio de selección se realiza mediante programación, no se genera ItemInvoked.
Todos los elementos de navegación forman parte del mismo modelo de selección, independientemente de que formen parte de MenuItems o FooterMenuItems. Solo se puede seleccionar un elemento de navegación cada vez.
Navegación hacia atrás
NavigationView presenta un botón Atrás integrado; pero, al igual que con la navegación hacia adelante, no realiza la navegación hacia atrás automáticamente. Cuando el usuario pulsa el botón Atrás, se genera el evento BackRequested. Es necesario controlar este evento para realizar la navegación hacia atrás. Para más información y obtener ejemplos de código, consulta Historial de navegación y navegación hacia atrás.
En el modo Minimal
o Compact
, se abre el Pane
de NavigationView como control flotante. En este caso, al hacer clic en el botón Atrás, se cierra el Pane
y se genera el evento PaneClosing.
Puedes ocultar o deshabilitar el botón Atrás mediante el establecimiento de estas propiedades:
- IsBackButtonVisible: se usa para mostrar y ocultar el botón Atrás. Esta propiedad toma un valor de la enumeración NavigationViewBackButtonVisible y se establece en
Auto
de forma predeterminada. Cuando se contrae el botón, no se reserva espacio para él en el diseño. - IsBackEnabled: se usa para habilitar o deshabilitar el botón Atrás. Puedes enlazar los datos de esta propiedad a la propiedad CanGoBack de tu marco de navegación. BackRequested no se genera si
IsBackEnabled
esfalse
.
Botón atrás en el panel de navegación izquierdo
Botón atrás en el panel de navegación superior
Ejemplo de código
En este ejemplo se muestra cómo puedes usar NavigationView con un panel de navegación superior en tamaños de ventana grandes y un panel de navegación izquierdo en tamaños de ventana pequeños. Este control se puede adaptar a solo la navegación izquierda si se quita el valor de navegación top en VisualStateManager.
En el ejemplo se muestra una manera común de configurar los datos de navegación que funciona en muchos escenarios. En este ejemplo, primero almacena (en la etiqueta de NavigationViewItem) el nombre de tipo completo de la página a la que quiere ir. En el controlador de eventos, aplica la conversión unboxing a ese valor, lo convierte en un objeto Type (C#) o Windows::UI::Xaml::Interop::TypeName (C++/WinRT) y lo usa para ir a la página de destino. Esto le permite crear pruebas unitarias para confirmar que los valores de las etiquetas tienen un tipo válido. Consulte también Conversión boxing y unboxing de valores a IInspectable con C++/WinRT. También se muestra cómo implementar la navegación hacia atrás con el botón Atrás de NavigationView.
Este código supone que la aplicación contiene páginas con los nombres siguientes para ir a: HomePage, AppsPage, GamesPage, MusicPage, MyContentPage y SettingsPage. No se muestra el código de estas páginas.
<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=""/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Tag="NavigationViewDemo.GamesPage" Content="Games">
<NavigationViewItem.Icon>
<FontIcon Glyph=""/>
</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());
}
}
}
}
}
}
}
Navegación jerárquica
Algunas aplicaciones pueden tener una estructura jerárquica más compleja que requiere más que una lista plana de elementos de navegación. Puede que desees usar elementos de navegación de nivel superior para mostrar categorías de páginas, con elementos secundarios que muestren páginas específicas. También resulta útil si tienes páginas de estilo de concentrador que solo se vinculan a otras páginas. Para estos tipos de casos, debes crear una clase NavigationView jerárquica.
Para mostrar una lista jerárquica de elementos de navegación anidados en el panel, usa la propiedad MenuItems o la propiedad MenuItemsSource de NavigationViewItem. Cada elemento NavigationViewItem puede contener otros elementos NavigationViewItems, y organizarlos como encabezados y separadores de elementos. Para mostrar una lista jerárquica al usar MenuItemsSource
, establece ItemTemplate
como un elemento NavigationViewItem y enlaza su propiedad MenuItemsSource
al siguiente nivel de la jerarquía.
Aunque un elemento NavigationViewItem puede contener cualquier número de niveles anidados, se recomienda mantener una jerarquía de navegación de la aplicación superficial. Creemos que dos niveles son ideales para facilitar el uso y la comprensión.
NavigationView muestra la jerarquía en los modos de presentación de panel Top
, Left
y LeftCompact
. Este es el aspecto que tiene un subárbol expandido en cada uno de los modos de visualización del panel:
Adición de una jerarquía de elementos en el marcado
En este ejemplo se muestra cómo declarar la navegación jerárquica de la aplicación en el marcado 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>
Adición de una jerarquía de elementos mediante el enlace de datos
Para agregar una jerarquía de elementos de menú a NavigationView, realiza las siguientes acciones:
- Enlazar la propiedad MenuItemsSource a los datos jerárquicos.
- Definir la plantilla de elemento como un elemento NavigationViewMenuItem, con el contenido establecido en la etiqueta del elemento de menú y la propiedad MenuItemsSource enlazada al siguiente nivel de la jerarquía.
En este ejemplo también se muestran los eventos Expanding y Collapsed. Estos eventos se generan para un elemento de menú con elementos secundarios.
<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);
}
}
Selección
De forma predeterminada, cualquier elemento puede contener elementos secundarios, invocarse o seleccionarse.
Al proporcionar a los usuarios un árbol jerárquico de opciones de navegación, puedes optar por hacer que los elementos primarios no se puedan seleccionar, por ejemplo, si la aplicación no tiene una página de destino asociada a ese elemento primario. Si los elementos primarios son seleccionables, se recomienda usar los modos de visualización del panel Left-Expanded o Top. El modo LeftCompact hará que el usuario navegue hasta el elemento primario para abrir el subárbol secundario cada vez que se invoque.
Los elementos seleccionados dibujarán sus indicadores de selección a lo largo de su borde izquierdo en el modo Left o en el borde inferior en el modo Top. A continuación se muestran los elementos NavigationView en los modos Left i Top donde está seleccionado un elemento primario.
Es posible que el elemento seleccionado no siempre permanezca visible. Si se selecciona un elemento secundario en un subárbol contraído o no expandido, su primer antecesor visible se mostrará como seleccionado. El indicador de selección se devolverá al elemento seleccionado si el subárbol está expandido.
Por ejemplo, en la imagen anterior, el usuario puede seleccionar el elemento Calendario y, a continuación, contraer su subárbol. En este caso, el indicador de selección se mostraría debajo del elemento Cuenta, ya que este es el primer antecesor visible de Calendario. El indicador de selección se devolverá al elemento Calendario cuando el usuario vuelva a expandir el subárbol.
El elemento NavigationView completo no mostrará más de un indicador de selección.
En los modos Top y Left, al hacer clic en las flechas de los elementos NavigationViewItem, se expandirá o contraerá el subárbol. Al hacer clic o pulsar en otro lugar en el elemento NavigationViewItem se desencadenará el evento ItemInvoked
y también se contraerá o expandirá el subárbol.
Para evitar que un elemento muestre el indicador de selección cuando se invoca, establece su propiedad SelectsOnInvoked en False, como se muestra a continuación:
<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);
}
...
Uso del teclado con el elemento NavigationView jerárquico
Los usuarios pueden cambiar el foco en NavigationView mediante el teclado. Las teclas de dirección exponen la "navegación interna" dentro del panel y siguen las interacciones que se proporcionan en la vista de árbol. Las acciones clave cambian al desplazarse por el elemento NavigationView o su menú flotante, que se muestra en los modos Top y Left-Compact de HierarchicalNavigationView. A continuación se muestran las acciones específicas que puede realizar cada clave en un elemento NavigationView jerárquico:
Clave | En el modo Left | En el modo Top | En el modo de control flotante |
---|---|---|---|
Subir | Mueve el foco al elemento directamente encima del elemento que está en el foco actualmente. | No hace nada. | Mueve el foco al elemento directamente encima del elemento que está en el foco actualmente. |
Bajar | Mueve el foco directamente debajo del elemento que está en el foco actualmente.* | No hace nada. | Mueve el foco directamente debajo del elemento que está en el foco actualmente.* |
Derecha | No hace nada. | Mueve el foco al elemento directamente a la derecha del elemento que está en el foco actualmente. | No hace nada. |
Izquierda | No hace nada. | Mueve el foco al elemento directamente a la izquierda del elemento que está en el foco actualmente. | No hace nada. |
Espacio/Entrar | Si el elemento tiene elementos secundarios, expande o contrae el elemento y no cambia el foco. | Si el elemento tiene elementos secundarios, expande los elementos secundarios en un control flotante y coloca el foco en el primer elemento del control flotante. | Invoca o selecciona el elemento y cierra el control flotante. |
Esc | No hace nada. | No hace nada. | Cierra el control flotante. |
La barra espaciadora o la tecla Entrar siempre invocan o seleccionan un elemento.
*Ten en cuenta que no es necesario que los elementos sean adyacentes visualmente. El foco se desplazará del último elemento de la lista del panel al elemento de configuración.
Personalización de NavigationView
Fondos del panel
De forma predeterminada, el panel NavigationView usa un fondo diferente según el modo de pantalla:
- el panel es de color gris sólido cuando se expande a la izquierda, en paralelo con el contenido (en modo izquierdo).
- el panel usa acrílico en la aplicación cuando se abre como una superposición sobre el contenido (en modo superior, mínimo o compacto).
Para modificar el fondo del panel, puedes reemplazar los recursos de tema XAML usados para representar el fondo en cada modo. (Esta técnica se usa en lugar de una sola propiedad PaneBackground con el fin de admitir distintos fondos para distintos modos de pantalla).
En esta tabla se muestra qué recurso de tema se usa en cada modo de pantalla.
Modo de pantalla | Recursos de tema |
---|---|
Izquierda | NavigationViewExpandedPaneBackground |
LeftCompact LeftMinimal |
NavigationViewDefaultPaneBackground |
Superior | NavigationViewTopPaneBackground |
En este ejemplo se muestra cómo invalidar los recursos de tema en App.xaml. Cuando invalides los recursos de tema, debes siempre proporcionar como mínimo los diccionarios de recursos "Default" y "HighContrast" y los diccionarios de recursos "Light" o "Dark" según sea necesario. Para más información, consulta ResourceDictionary.ThemeDictionaries.
Importante
Este código muestra cómo usar la versión de AcrylicBrush de WinUI 2 Si usas en cambio la versión de AcrylicBrush de la plataforma, la versión mínima del proyecto de aplicación debe ser SDK 16299 o superior. Para usar la versión de la plataforma, quita todas las referencias 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>
Espacio en blanco superior
La
IsTitleBarAutoPaddingEnabled
propiedad requiere WinUI 2.2 o posterior.
Algunas aplicaciones permiten personalizar la barra de título de sus ventanas. Esto permite extender el contenido de la aplicación al área de la barra de título. Cuando NavigationView es el elemento raíz de las aplicaciones que se pueden extender a la barra de título mediante ExtendViewIntoTitleBar API, el control ajusta automáticamente la posición de los elementos interactivos para evitar la superposición con la región arrastrable.
Si la aplicación especifica la región arrastrable mediante una llamada al método Window.SetTitleBar y prefiere que los botones Atrás y Menú se acerquen a la parte superior de la ventana de la aplicación, establezca IsTitleBarAutoPaddingEnabled en false
.
<muxc:NavigationView x:Name="NavView" IsTitleBarAutoPaddingEnabled="False">
Observaciones
Para ajustar aún más la posición del área de encabezado de NavigationView, invalida, por ejemplo, el recurso de tema XAML de NavigationViewHeaderMargin en los recursos de la página.
<Page.Resources>
<Thickness x:Key="NavigationViewHeaderMargin">12,0</Thickness>
</Page.Resources>
Este recurso de tema modifica el margen alrededor de NavigationView.Header.