NavigationView

Элемент управления NavigationView обеспечивает навигацию верхнего уровня для вашего приложения. Он адаптируется к различным размерам экрана и поддерживает оба типа панели навигации: верхнюю и левую.

Верхняя область навигацииНавигация слева
NavigationView поддерживает как верхнюю, так и левую панель или меню навигации

Выбор правильного элемента управления

NavigationView — это адаптивный элемент управления навигацией, который обеспечивает следующее:

  • согласованность навигации в приложении;
  • сохранение свободного экранного пространства в окнах меньших размеров;
  • организацию доступа ко многим категориям навигации.

Сведения о других шаблонах навигации см. в статье Основы проектирования навигации для приложений UWP.

UWP и WinUI 2

Внимание

Сведения и примеры в этой статье оптимизированы для приложений, использующих пакет SDK для приложений Windows и WinUI 3, но обычно применимы к приложениям UWP, использующим WinUI 2. См. справочник по API UWP для конкретных сведений и примеров платформы.

В этом разделе содержатся сведения, необходимые для использования элемента управления в приложении UWP или WinUI 2.

Элемент управления NavigationView для приложений UWP входит в состав WinUI 2. Дополнительные сведения, включая инструкции по установке, см. в статье WinUI 2. API для этого элемента управления существуют как в пространствах имен Windows.UI.Xaml.Controls, так и в пространствах имен Microsoft.UI.Xaml.Controls.

Мы рекомендуем использовать последнюю версию WinUI 2 , чтобы получить самые актуальные стили, шаблоны и функции для всех элементов управления. Для некоторых функций NavigationView, таких как верхняя и иерархическая навигация, требуется Windows 10 версии 1809 (пакет SDK 17763) или более поздней версии или WinUI 2.

Чтобы использовать код в этой статье с WinUI 2, используйте псевдоним в XAML (мы используем muxc), чтобы представить API библиотеки пользовательского интерфейса Windows, включенные в проект. Дополнительные сведения см. в статье "Начало работы с WinUI 2 ".

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

<muxc:NavigationView />

Создание представления навигации

Приложение коллекции WinUI 3 включает интерактивные примеры большинства элементов управления, функций и функций WinUI 3. Получение приложения из Microsoft Store или получение исходного кода на GitHub

В этом примере показано, как создать простое представление навигации в 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>

Режимы отображения

Вы можете использовать свойство PaneDisplayMode для настройки различных видов панели навигации или режимов отображения для элемента NavigationView.

Верх

Область находится над содержимым.
PaneDisplayMode="Top"

Пример верхней панели навигации

Рекомендуем использовать верхнюю панель навигации в следующих случаях:

  • у вас есть 5 или меньше категорий навигации верхнего уровня одинаковой степени важности, а дополнительные категории навигации верхнего уровня, попадающие в раскрывающееся меню переполнения, менее важны;
  • вы хотите отобразить все параметры навигации на экране;
  • для содержимого вашего приложения требуется больше пространства;
  • значки не четко описывают категории навигации приложения.

Left

Область разворачивается и размещается слева от содержимого.
PaneDisplayMode="Left"

Пример развернутой левой панели навигации

Рекомендуем использовать левую панель навигации в следующих случаях:

  • у вас есть 5–10 одинаково важных категорий навигации верхнего уровня;
  • вам необходимо, чтобы категории навигации были очень заметными, а для другого содержимого приложения достаточно небольшого пространства.

LeftCompact

На панели отображаются лишь неоткрытые значки, расположенные слева от содержимого. При открытии панель накладывает содержимое.
PaneDisplayMode="LeftCompact"

Пример левой панели навигации в компактном режиме отображения

LeftMinimal

Пока панель закрыта, отображается лишь кнопка меню. При открытии панель накладывает левую сторону содержимого.
PaneDisplayMode="LeftMinimal"

Пример левой панели навигации в минимальном режиме отображения

Авто

По умолчанию для ПанелиDisplayMode задано Autoзначение . В Auto режиме navigationView адаптируется между LeftMinimal узким окном, LeftCompactа затем Left , когда окно становится шире. Дополнительные сведения см. в разделе об адаптивном поведении.

Адаптивное поведение левой панели навигации в режиме отображения по умолчанию
Адаптивное поведение NavigationView по умолчанию

Структура

На приведенных ниже изображениях представлена структура панели, верхнего колонтитула и области содержимого элемента управления при настройке верхней или левой панели навигации.

Макет Top элемента NavigationView
Структура верхней панели навигации

Макет Left элемента NavigationView
Структура левой панели навигации

навигации

Вы можете использовать свойство PaneDisplayMode для размещения панели над содержимым или слева от содержимого.

Панель NavigationView может содержать следующие объекты:

  • Объект NavigationViewItem. Элементы навигации для перехода на определенные страницы.
  • Объекты NavigationViewItemSeparator. Разделители для группировки элементов навигации. Установите для свойства Opacity значение 0, чтобы разделитель отображался как пробел.
  • Объекты NavigationViewItemHeader. Заголовки для маркировки групп элементов.
  • Необязательный элемент управления AutoSuggestBox для поиска на уровне приложения. Назначьте элемент управления свойству NavigationView.AutoSuggestBox.
  • Необязательная точка входа для параметров приложения. Чтобы скрыть элемент параметров, задайте для свойства IsSettingsVisible значение false.

Левая панель также содержит следующие объекты:

  • Кнопка меню для переключения открытой и закрытой панели. Когда панель открыта в более крупных окнах приложения, вы можете скрыть эту кнопку с помощью свойства IsPaneToggleButtonVisible.

В NavigationView есть кнопка возврата, расположенная в верхнем левом углу области. Но она автоматически не обрабатывает переход в обратном направлении и не добавляет содержимое в обратный стек. Сведения о включении навигации в обратном направлении см. в этом разделе.

Ниже приведена подробная структура верхней и левой панелей.

Верхняя панель навигации

Структура области NavigationView со стилем Top

  1. Заголовки
  2. Элементы навигации
  3. Разделители
  4. AutoSuggestBox (необязательно)
  5. Кнопка "Параметры" (необязательно)

Левая панель навигации

Структура области NavigationView со стилем Left

  1. Кнопка меню
  2. Элементы навигации
  3. Разделители
  4. Заголовки
  5. AutoSuggestBox (необязательно)
  6. Кнопка "Параметры" (необязательно)

С помощью FooterMenuItems вы можете поместить элементы навигации в конец панели навигации, в отличие от свойства MenuItems, которое размещает эти элементы в начале панели.

FooterMenuItems будет отображаться перед элементом Settings по умолчанию. Элемент Settings по-прежнему IsSettingsVisible можно переключать с помощью свойства.

Внутри FooterMenuItems следует размещать только элементы Navigation, а любое другое содержимое для нижней части панели переносите в элемент PaneFooter.

Пример добавления FooterMenuItems в NavigationView можно изучить в документации по классу FooterMenuItems.

На рисунке ниже показан элемент NavigationView с учетной записью, корзиной и элементом навигации справки в меню нижнего колонтитула.

Элемент NavigationView с FooterMenuItems

В нижнем колонтитуле панели можно разместить содержимое в произвольном формате, добавив его в свойство PaneFooter.

Нижний колонтитул верхней панели навигации
Нижний колонтитул верхней панели

Нижний колонтитул левой панели навигации
Нижний колонтитул левой панели

Заголовок и верхний колонтитул панели

В области верхнего колонтитула панели можно разместить текстовое содержимое, задав свойство PaneTitle. Это свойство принимает строковое значение и отображает текст рядом с кнопкой меню.

Чтобы добавить нетекстовое содержимое, например изображение или логотип, вы можете поместить любой элемент в верхний колонтитул панели, добавив его в свойство PaneHeader.

Если заданы оба свойства (PaneTitle и PaneHeader), содержимое будет расположено горизонтально рядом с кнопкой меню. При этом PaneTitle будет располагаться ближе к кнопке меню.

Верхний колонтитул, верхняя панель навигации
Верхний колонтитул верхней панели навигации

Верхний колонтитул, левая панель навигации
Верхний колонтитул левой панели навигации

Содержимое панели

На панели можно разместить содержимое в произвольном формате, добавив его в свойство PaneCustomContent.

Настраиваемое содержимое, верхняя панель навигации
Настраиваемое содержимое верхней панели навигации

Настраиваемое содержимое, левая панель навигации
Настраиваемое содержимое левой панели навигации

Вы можете добавить заголовок страницы, задав свойство Header.

Пример области заголовка NavigationView
Заголовок NavigationView

Область заголовка выровнена по вертикали относительно кнопки навигации в левой панели и находится под верхней панелью. Она имеет фиксированную высоту в 52 пикселя. Его назначение — удержание заголовка страницы выбранной категории навигации. Заголовок закреплен в верхней части страницы и выступает в качестве точки отсечения прокрутки для области содержимого.

Заголовок отображается в любой момент, когда NavigationView находится в Minimal режиме отображения. Вы можете скрыть заголовок в других режимах, используемых для окон большей ширины. Чтобы скрыть заголовок, задайте для свойства AlwaysShowHeader значение false.

Содержимое

Пример области содержимого NavigationView
Содержимое NavigationView

Область содержимого содержит большую часть сведений для выбранной категории навигации.

Мы рекомендуем использовать поля 12px для области содержимого, если NavigationView находится в Minimal режиме и 24px поля в противном случае.

Адаптивное поведение

По умолчанию NavigationView автоматически изменяет режим отображения в зависимости от доступного экранного пространства. Свойства CompactModeThresholdWidth и ExpandedModeThresholdWidth определяют точки останова, в которых изменяется режим отображения. Вы можете изменить эти значения, чтобы настроить поведение адаптивного режима отображения.

По умолчанию.

Если Параметр PaneDisplayMode имеет значение Autoпо умолчанию, адаптивное поведение — показать следующее:

  • Развернутая левая панель для окон большой ширины (1008 пикселей или больше).
  • Левая панель навигации (только для значков) на средней ширине окна (LeftCompact641 пикселей до 1007 пикселей).
  • Только кнопка меню (LeftMinimal) на небольшой ширине окна (640 пикселей или меньше).

Дополнительные сведения о размерах окон для адаптивного поведения см. в статье Размеры экрана и точки останова.

Адаптивное поведение левой панели навигации в режиме отображения по умолчанию
Адаптивное поведение NavigationView по умолчанию

Минимальные

Вторым распространенным адаптивным шаблоном является использование развернутой левой панели для окон большой ширины и кнопок меню — для окон средней и небольшой ширины.

Рекомендуем использовать его в следующих случаях:

  • вам требуется больше пространства для содержимого приложения в окне небольшой ширины;
  • ваши категории навигации невозможно представить значками.

Адаптивное поведение левой панели навигации в минимальном режиме отображения
Адаптивное поведение NavigationView в минимальном режиме отображения

Чтобы настроить это поведение, задайте для свойства CompactModeThresholdWidth ширину, при которой панель необходимо свернуть. В этом примере значение по умолчанию (640) изменено на 1007. Кроме того, задайте соответствующее значение для ExpandedModeThresholdWidth, чтобы избежать конфликта значений.

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

Compact

Третьим распространенным адаптивным шаблоном является использование развернутой левой панели для окон большой ширины и панели навигации LeftCompact, содержащей лишь значки, — для окон средней и небольшой ширины.

Рекомендуем использовать его в следующих случаях:

  • вам необходимо, чтобы на экране всегда отображались все возможности навигации;
  • ваши категории навигации можно представить значками.

Адаптивное поведение левой панели навигации в компактном режиме отображения
Адаптивное поведение NavigationView в компактном режиме отображения

Чтобы настроить это поведение, задайте для свойства CompactModeThresholdWidth значение 0.

<NavigationView CompactModeThresholdWidth="0"/>

Без адаптивного поведения

Чтобы отключить автоматическое адаптивное поведение, задайте для ПанелиDisplayMode значение, отличное от Autoзначения. В этом случае установлено значение LeftMinimal, поэтому отображается только кнопка меню независимо от ширины окна.

Левая панель навигации без адаптивного поведения
NavigationView с параметром PaneDisplayMode со значением LeftMinimal

<NavigationView PaneDisplayMode="LeftMinimal" />

Как указано выше в разделе Режимы отображения, вы можете настроить панель таким образом, чтобы она всегда отображалась сверху или же в развернутом, компактном или минимальном режимах. Вы также можете самостоятельно управлять режимами отображения в коде своего приложения. Соответствующий фрагмент кода приведен в следующем разделе.

Переключение верхней панели навигации на левую

При использовании верхней панели навигации в приложении элементы навигации свертываются в меню переполнения по причине уменьшения ширины окна. Если окно приложения узкое, оно может обеспечить более удобный пользовательский интерфейс для переключения панелиDisplayMode на Top LeftMinimal навигацию, а не позволить всем элементам сворачиваться в меню переполнения.

Рекомендуем использовать верхнюю панель навигации для окон большого размера, а левую панель навигации для окон небольших размеров в следующих случаях:

  • у вас есть набор одинаково важных категорий навигации верхнего уровня, которые должны отображаться вместе, поэтому если одна категория в этом наборе не помещается на экране, вы переключаетесь на левую панель навигации, чтобы придать им одинаковую степень важности;
  • вам необходимо сохранить как можно больше содержимого в окнах небольшого размера.

В этом примере показано, как использовать свойство VisualStateManager и AdaptiveTrigger.MinWindowWidth для переключения между Top и LeftMinimal навигацией.

Пример 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>

Совет

При использовании AdaptiveTrigger.MinWindowWidth визуальное состояние активируется, если ширина окна превышает указанное минимальное значение. Это означает, что XAML по умолчанию определяет узкое окно, а VisualState определяет модификации, которые применяются при увеличении ширины окна. Значение по умолчанию PaneDisplayMode для NavigationView — auto, поэтому если ширина окна меньше или равна CompactModeThresholdWidth, LeftMinimal используется навигация. Когда окно становится шире, VisualState переопределяет значение по умолчанию и Top используется навигация.

NavigationView не выполняет никаких задач навигации автоматически. При касании элемента навигации NavigationView выделяет этот элемент как выбранный и вызывает событие ItemInvoked. Если касание приводит к выбору нового элемента, представление также вызывает событие SelectionChanged.

Вы можете обрабатывать любое событие для выполнения задач, связанных с запрошенной навигацией. Какое из событий необходимо обработать зависит от поведения вашего приложения. Обычно в ответ на эти события вы переходите на запрошенную страницу, а заголовок NavigationView изменяется.

  • Событие ItemInvoked вызывается каждый раз, когда пользователь касается элемента навигации, даже если он уже выбран. (Элемент также можно вызвать с эквивалентным действием с помощью мыши, клавиатуры или других входных данных. Дополнительные сведения см. в разделе "Входные данные и взаимодействие".) При переходе по обработчику ItemInvoked по умолчанию страница будет перезагружена, а в стек навигации добавляется повторяющаяся запись. Если вы выполняете переход при вызове элемента, запретите перезагрузку страницы или убедитесь, что при повторной загрузке страницы в обратном стеке навигации не создается повторяющаяся запись. (См. примеры кода.)
  • Событие SelectionChanged может быть инициировано пользователем, который вызывает не выбранный в настоящее время элемент или изменяет выбранный элемент программным способом. Если изменение выбора происходит из-за вызова элемента, сначала возникает событие ItemInvoked. Если изменение выбора выполняется программным способом, событие ItemInvoked не возникает.

Все элементы навигации, размещенные в MenuItems и FooterMenuItems, размещаются в одной модели выбора. В каждый момент времени может быть выбран только один элемент навигации.

Обратная навигация

NavigationView содержит встроенную кнопку возврата. Но, как и переход вперед, навигация в обратном направлении не выполняется автоматически. При нажатии кнопки возврата возникает событие BackRequested. Вы обрабатываете это событие для выполнения перехода в обратном направлении. Дополнительные сведения и примеры кода см. в статье Журнал навигации и навигация в обратном направлении для приложений UWP.

В Minimal или Compact в режиме навигационный объект Pane открывается как всплывающий элемент. В этом случае нажатие кнопки "Назад" закроет Pane и вызовет событие PaneClosing.

Вы можете скрыть или отключить кнопку возврата, задав следующие свойства:

  • IsBackButtonVisible — используйте, чтобы отобразить и скрыть кнопку возврата. Это свойство принимает значение перечисления NavigationViewBackButtonVisible и имеет значение Auto по умолчанию. Если кнопка свернута, в макете для нее не зарезервировано пространство.
  • IsBackEnabled — используйте, чтобы включить или отключить кнопку возврата. Вы можете привязать данные этого свойства к свойству CanGoBack вашего фрейма навигации. BackRequested не вызывается, если IsBackEnabled есть false.

Кнопка
Кнопка "Назад" в левой области навигации

Кнопка
Кнопка "Назад" в верхней области навигации

Пример кода

В этом примере показано, как можно использовать NavigationView с верхней областью навигации для окон больших размеров и левой областью навигации для окон небольших размеров. Его можно адаптировать только для левой панели навигации, удалив параметры верхней панели навигации в VisualStateManager.

В этом примере показан общий способ настройки данных навигации, которые будут работать для многих сценариев. В этом примере вы сначала сохраните (в теге NavigationViewItem) полное имя страницы, на которую вы хотите перейти. В обработчике событий вы распаковываете это значение, преобразуете его в объект Type(C#) или Windows::UI::Xaml:Interop::TypeName(C++/WinRT) и используете его для перехода на целевую страницу. Это позволяет создавать модульные тесты, чтобы убедиться, что значения внутри тегов имеют допустимый тип. (См. также Бокс и распаковка значений в IInspectable с помощью C++/WinRT). В нем также показано, как реализовать обратную навигацию с помощью кнопки "Назад" NavigationView.

Этот код предполагает, что приложение содержит страницы со следующими именами, чтобы перейти к: HomePage, AppsPage, GamesPage, MusicPage, MyContentPage и SettingsPage. Код для этих страниц не отображается.

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

Иерархическая навигация

Некоторые приложения могут иметь более сложную иерархическую структуру, которая требует больше, чем просто неструктурированный список элементов навигации. Для отображения категорий страниц можно использовать элементы навигации верхнего уровня, при этом дочерние элементы отображают определенные страницы. Это также полезно при наличии сводных страниц, которые связаны только с другими страницами. В подобных случаях следует создать иерархическое представление NavigationView.

Чтобы отобразить иерархический список вложенных элементов навигации на панели, используйте свойство MenuItems или свойство MenuItemsSource объекта NavigationViewItem. Каждый объект NavigationViewItem может содержать другие объекты NavigationViewItem и организационные элементы, такие как заголовки элементов и разделители. Чтобы отобразить иерархический список при использовании MenuItemsSource, назначьте ItemTemplate объектом NavigationViewItem и привяжите его свойство MenuItemsSource к следующему уровню иерархии.

Хотя объект NavigationViewItem может содержать любое количество вложенных уровней, рекомендуется не делать иерархию навигации вашего приложения слишком глубокой. Мы считаем, что двухуровневая навигация идеально сочетает удобство использования и понятность.

NavigationView отображает иерархию в TopLeftрежимах отображения и LeftCompact области. Вот как выглядит развернутое поддерево в каждом из режимов отображения панели:

Представление NavigationView с иерархией

Добавление иерархии элементов в разметку

В этом примере показано, как объявить иерархическую навигацию приложения в разметке 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>

Добавление иерархии элементов с помощью привязки данных

Добавление иерархии пунктов меню в представления NavigationView с помощью

  • привязки свойства MenuItemsSource к иерархическим данным
  • определения шаблона элемента как объекта NavigationViewMenuItem, когда его содержимое должно быть меткой элемента меню, а свойство MenuItemsSource привязано к следующему уровню иерархии

В этом примере также демонстрируются события развертывание и свертывание. Эти события вызываются для пункта меню с дочерними элементами.

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

Выбор

По умолчанию любой элемент может содержать дочерние элементы, быть вызванным или выбранным.

Предоставляя пользователям иерархическое дерево вариантов навигации можно сделать родительские элементы невыбираемыми, например, если у приложения нет конечной страницы, связанной с этим родительским элементом. Если родительские элементы доступны для выбора, рекомендуется использовать режимы представления Left-Expanded или Top. Использование режима LeftCompact приведет к тому, что пользователь будет переходить к родительскому элементу, чтобы открывать дочернее дерево при каждом вызове элемента.

Индикаторы выбора будут отрисовываться на выбранных элементах вдоль левого края в режиме Left или на нижней границе в режиме Top. Ниже показаны объекты NavigationView в режиме Left и Top, если выбран родительский элемент.

Представление NavigationView в режиме Left с выбранным родительским элементом

Представление NavigationView в режиме Top с выбранным родительским элементом

Выбранный элемент может не всегда оставаться видимым. Если выбран дочерний элемент в свернутом или развернутом поддереве, то их первый видимый предок будет показан как выбранный. Индикатор выделения вернется к выбранному элементу при развертывании поддерева.

Например, на рисунке выше пользователь может выбрать элемент Календаря, а затем может свернуть его поддерево. В этом случае индикатор выбора будет отображаться под элементом учетной записи, так как учетная запись является первым видимым предком в Календаре. Индикатор выделения вернется к элементу Календаря, когда пользователь снова развернет поддерево.

Представление NavigationView будет отображать не более одного индикатора выбора.

В режимах Top и Left при щелчке по стрелкам в объектах NavigationViewItem поддерево разворачивается или сворачивается. Если щелкнуть или коснуться в другом месте помимо NavigationViewItem, будет активировано событие ItemInvoked, а также будет свернуто или развернуто поддерево.

Чтобы элемент не отображал индикатор выбора при вызове, установите для свойства SelectsOnInvoked значение false, как показано ниже:

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

Навигация с помощью клавиатуры в иерархическом представлении NavigationView

Пользователи могут перемещать фокус по NavigationView с помощью клавиатуры. Клавиши со стрелками позволяют реализовать "внутреннюю навигацию" по панели и взаимодействуют с объектами в представлении дерева. Действия клавиш изменяются при навигации по представлению NavigationView или его всплывающем меню, которое отображается в режимах Top и Left представления HierarchicalNavigationView. Ниже приведены действия, которые каждая клавиша может выполнить в иерархическом представлении NavigationView:

Ключ В режиме Left В режиме Top Во всплывающем меню
Up Перемещает фокус на элемент непосредственно над элементом, на котором фокус находится сейчас. Не выполняет никаких действий. Перемещает фокус на элемент непосредственно над элементом, на котором фокус находится сейчас.
Down Перемещает фокус на элемент непосредственно под элементом, на котором фокус находится сейчас.* Не выполняет никаких действий. Перемещает фокус на элемент непосредственно под элементом, на котором фокус находится сейчас.*
Right Не выполняет никаких действий. Перемещает фокус на элемент непосредственно справа от элемента, на котором фокус находится сейчас. Не выполняет никаких действий.
Left Не выполняет никаких действий. Перемещает фокус на элемент непосредственно слева от элемента, на котором фокус находится сейчас. Не выполняет никаких действий.
ПРОБЕЛ/ВВОД Если элемент содержит дочерние элементы, разворачивает или сворачивает элемент и не меняет фокус. Если элемент содержит дочерние элементы, разворачивает дочерние элементы во всплывающий элемент и помещает фокус на первый элемент во всплывающем элементе. Вызывает или выбирает элемент и закрывает всплывающий элемент.
ESC Не выполняет никаких действий. Не выполняет никаких действий. Закрывает всплывающий элемент.

Пробел или клавиша ВВОД всегда вызывает или выбирает элемент.

*Обратите внимание, что элементы не должны быть визуально смежными, фокус будет перемещен от последнего элемента в списке панели к элементу параметров.

Фоновый цвет панелей

По умолчанию панель NavigationView использует фоновый цвет в зависимости от режима отображения:

  • при развертывании слева рядом с содержимым (в режиме отображения слева) цветом фона панели является сплошной серый цвет;
  • при открытии панели в качестве наложения поверх содержимого используется акрил приложения (в режиме отображения сверху, минимальном или компактном режимах).

Чтобы изменить фоновый цвет панели, вы можете переопределить ресурсы темы XAML, используемые для отображения фона в каждом режиме. (Для обеспечения поддержки разных фоновых цветов для различных режимов отображения обычно используется этот метод вместо свойства PaneBackground.)

В приведенной ниже таблице описано использование ресурсов темы в каждом режиме отображения.

Режим отображения Ресурсы темы
Left NavigationViewExpandedPaneBackground
LeftCompact
LeftMinimal
NavigationViewDefaultPaneBackground
Верх NavigationViewTopPaneBackground

В этом примере показано, как переопределить ресурсы темы в файле App.xaml. При переопределении ресурсов темы всегда необходимо предоставлять как минимум словарь ресурсов по умолчанию и HighContrast, а также при необходимости словари для светлых или темных ресурсов. Дополнительные сведения см. в статье о свойстве ResourceDictionary.ThemeDictionaries.

Внимание

В этом коде показано, как использовать Версию WinUI 2 АкрилБруш. Если вы используете для AcrylicBrush версию платформы, минимальной версией пакета SDK проекта приложения должна быть версия 16299 или выше. Для использования версии платформы удалите все ссылки на 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>

Пустое пространство вверху

Для IsTitleBarAutoPaddingEnabled этого свойства требуется WinUI 2.2 или более поздней версии.

В некоторых приложениях можно настроить заголовок окна, чтобы расширить содержимое приложения за счет этой области. Если NavigationView является корневым элементом в приложениях, в которых с помощью API ExtendViewIntoTitleBar можно выполнить такое расширение, элемент управления автоматически скорректирует расположение интерактивных элементов, чтобы не допустить перекрытия с перетаскиваемой областью.

Приложение, расширяющееся за счет строки заголовка

Если приложение задает перетаскиваемый регион, вызвав метод Window.SetTitleBar, и вы предпочитаете, чтобы кнопки назад и меню были бы ближе к верхней части окна приложения, задайте для falseisTitleBarAutoPaddingEnabledd.

Приложение, расширяющееся за счет строки заголовка без дополнительного заполнения

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

Замечания

Чтобы скорректировать расположение области заголовка NavigationView, переопределите ресурс темы XAML NavigationViewHeaderMargin (например, в ресурсах страницы).

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

Этот ресурс темы изменяет поля вокруг NavigationView.Header.