[WPF] NavigationView（ナビゲーションビュー）を使う

# ■概要

こんなの
![000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/1543feda-3c55-4a2f-9752-0e452e08ea76.png)

# ■準備

[🔗ここ](https://qiita.com/Kosen-amai/items/607b9ba3af9222aa7225 "[WPF] Windows 10に馴染むテーマを適用する") を参考に「2. プロジェクト作成」から「5. テーマ適用」まで実施する。

※「2. プロジェクト作成」でプロジェクト名は`WpfAppNaviView`、フレームワークは.NET 5.0にした。
※「4. NuGet」は「ModernWpfUI」だけ入れればOK、「ModernWpf.MessageBox」は今回のサンプルでは使っていない。

# ■切り替えるページ追加

`Pages`フォルダを作成し、その中に「追加」-「ページ (WPF)」で以下の名前でページを作成する。

* AccountPage
* BlankPage
* DocumentPage
* HomePage

![010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/24927b34-f2b8-57a1-276e-3b18819d326d.png)

# ■MainWindow

## ◇cs

enum定義。

```MainWindow.xaml.cs
：

namespace WpfAppNaviView
{
    // 新しいページが増えたら追加
    public enum NaviIcon
    {
        Home,
        Account,
        Document,

        None,
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    ：
```

## ◇xaml

「Window」に`xmlns:muxc="http://schemas.modernwpf.com/2019"`を追加。
「Width」「Height」変更。
`ResizeMode="CanResizeWithGrip"`追加。

```xml:MainWindow.xaml
<Window
    x:Class="WpfAppNaviView.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfAppNaviView"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:muxc="http://schemas.modernwpf.com/2019"
    xmlns:ui="http://schemas.modernwpf.com/2019"
    Title="MainWindow"
    Width="1010"
    Height="700"
    ui:WindowHelper.UseModernWindowStyle="True"
    ResizeMode="CanResizeWithGrip"
    mc:Ignorable="d">
```

「Grid」を「NavigationView」に書き換え。
「NavigationViewItem」が選択変更されたら「Frame」のコンテンツを切り替えるように作っていく。
![020_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/56646961-89d6-ba57-0284-57f30d1eae0a.png)
![025_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/61688de7-ddb2-457d-de90-232186ba869a.png)

「NavigationViewItem」の「Tag」に先ほど定義したenum値を設定。

```xml:MainWindow.xaml
    <muxc:NavigationView
        x:Name="NaviView"
        Header="★ヘッダー★"
        IsBackButtonVisible="Collapsed"
        IsSettingsVisible="False"
        IsTitleBarAutoPaddingEnabled="False"
        PaneDisplayMode="Auto"
        PaneTitle=""
        SelectionChanged="NaviView_SelectionChanged">
        <muxc:NavigationView.MenuItems>
            <muxc:NavigationViewItem
                Content="ホーム"
                Icon="Home"
                IsSelected="True"
                Tag="{x:Static local:NaviIcon.Home}" />
            <muxc:NavigationViewItem
                Content="アカウント"
                Icon="Contact"
                Tag="{x:Static local:NaviIcon.Account}" />
            <muxc:NavigationViewItem
                Content="ドキュメント"
                Icon="Page2"
                Tag="{x:Static local:NaviIcon.Document}" />
            <muxc:NavigationViewItem Content="ダウンロード" Icon="Download" />
            <muxc:NavigationViewItem Content="ミュージック" Icon="Audio" />
            <muxc:NavigationViewItem Content="ビデオ" Icon="Video" />
            <muxc:NavigationViewItem Content="編集" Icon="Edit" />
            <muxc:NavigationViewItem Content="ネットワーク" Icon="Globe" />
            <muxc:NavigationViewItem Content="メール" Icon="Mail" />
            <muxc:NavigationViewItem Content="すべてのアプリ" Icon="AllApps" />
            <muxc:NavigationViewItem Content="検索" Icon="Find" />
            <muxc:NavigationViewItem Content="計算" Icon="Calculator" />
            <muxc:NavigationViewItem Content="カレンダー" Icon="Calendar" />
            <muxc:NavigationViewItem Content="ゴミ箱" Icon="Delete" />
        </muxc:NavigationView.MenuItems>

        <ScrollViewer Margin="0,0,0,12">
            <ui:Frame x:Name="ContentFrame" Padding="12,0,12,12" />
        </ScrollViewer>
    </muxc:NavigationView>
</Window>
```

## ◇cs

enumと実際のページを紐づけるDictionaryを定義。
NavigationViewが選択変更されたら対応するページを表示する処理追加。

```cs:MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Windows;
using ui = ModernWpf.Controls;

namespace WpfAppNaviView
{
    // 新しいページが増えたら追加
    public enum NaviIcon
    {
        Home,
        Account,
        Document,

        None,
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // 新しいページが増えたら追加
        private static IReadOnlyDictionary<NaviIcon, Type> _pages = new Dictionary<NaviIcon, Type>()
        {
            {NaviIcon.Home, typeof(Pages.HomePage)},
            {NaviIcon.Account, typeof(Pages.AccountPage)},
            {NaviIcon.Document, typeof(Pages.DocumentPage)},
            // 空ページ
            {NaviIcon.None, typeof(Pages.BlankPage)},
        };

        public MainWindow()
        {
            InitializeComponent();
        }

        private void NaviView_SelectionChanged(ui.NavigationView sender, ui.NavigationViewSelectionChangedEventArgs args)
        {
            try
            {
                var selectedItem = (ui.NavigationViewItem)args.SelectedItem;
                // Tag取得
                string iconName = selectedItem.Tag?.ToString();
                // ヘッダー設定
                sender.Header = iconName;

                if (Enum.TryParse(iconName, out NaviIcon icon))
                {
                    // 対応するページ表示
                    ContentFrame.Navigate(_pages[icon]);
                }
                else
                {
                    // 空ページ表示
                    ContentFrame.Navigate(_pages[NaviIcon.None]);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

    }
}
```

# ■各ページ内容

```xml:HomePage.xaml
<Page
    x:Class="WpfAppNaviView.Pages.HomePage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfAppNaviView.Pages"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="HomePage"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">

    <Grid>
        <TextBlock
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            FontSize="72"
            Text="ホーム" />
    </Grid>
</Page>
```

```xml:AccountPage.xaml
<Page
    x:Class="WpfAppNaviView.Pages.AccountPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfAppNaviView.Pages"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="AccountPage"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">

    <Grid>
        <TextBlock
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            FontSize="72"
            Text="アカウント" />
    </Grid>
</Page>
```

```xml:DocumentPage.xaml
<Page
    x:Class="WpfAppNaviView.Pages.DocumentPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfAppNaviView.Pages"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="DocumentPage"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">

    <StackPanel>
        <StackPanel.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="72" />
                <Setter Property="Margin" Value="0,0,0,12" />
            </Style>
        </StackPanel.Resources>
        <TextBlock Text="ドキュメント1" />
        <TextBlock Text="ドキュメント2" />
        <TextBlock Text="ドキュメント3" />
        <TextBlock Text="ドキュメント4" />
        <TextBlock Text="ドキュメント5" />
        <TextBlock Text="ドキュメント6" />
        <TextBlock Text="ドキュメント7" />
        <TextBlock Text="ドキュメント8" />
    </StackPanel>
</Page>
```

まだ作っていないページはとりあえずこれを表示する。

```xml:BlankPage.xaml
<Page
    x:Class="WpfAppNaviView.Pages.BlankPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfAppNaviView.Pages"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="BlankPage"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">

    <Grid />
</Page>
```

# ■実行

![030.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/d2f023b9-c64c-9861-99d3-71b628060a09.png)

「ドキュメント」をクリック。
![040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/7c7193ad-ff99-b8e5-c649-7b5bf378d2c3.png)

OSのテーマを「白」に変更。
![050.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/07f83746-2b42-fc21-86c2-918252d8ed2e.png)

ウィンドウサイズを小さくするとメニューがコンパクト化。
![060.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/42064269-c780-c193-fb1b-f7ddad2efa8f.png)

ハイコントラスト指定。
![070.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/83f48db2-361c-6d30-dd0c-f8fcc42b74aa.png)