NavigationViewを導入する【XAML】

NavigationViewは最近のアプリでよく見るスタイルのナビゲーションです。左側のナビゲーション・メニューでページを選ぶスタイルで、ナビゲーション・メニューのサイズはウィンドウ幅に応じてアダプティブに変化するのが特徴です。WinUI3では簡単に実装することができるので、ぜひ使ってみてアプリをワンランクアップさせましょう。

開発環境

  • .NET 6.0
  • WinUI 3.0 (Windows App SDK 1.0)

NavigationViewとは?

NavigationViewとはアプリの左側や上部にメニューが並んでいて、それを選ぶと表示される項目が変化するような構造のことです。メニューの大きさはアプリの表示サイズによって最適化されていて、ウィンドウが小さくなると自動的に隠れるようになっていて、メイン・コンテンツを妨げないようになっています。

例えばXAMLコントロールのカタログアプリであるXAML Controls GalleryがNavigationViewの代表的な例です。

XAML Controls Gallery

その他にもデザインはカスタマイズされていますが、Microsoft StoreもNavigationViewを用いていると思われます。

このようにNavigationViewは様々なアプリで頻用されているコントロールであり、これを活用することでアプリの見栄えをレベルアップさせることができます。

NavigationViewについてはこちらのドキュメントもご覧ください。

ナビゲーション・メニューの配置は左側と上部から選ぶことができ、それぞれの場合についてNavigationViewの各項目は次のように定義されています。

NavigationView の左側ペインの構造
https://docs.microsoft.com/ja-jp/windows/apps/design/controls/navigationview より抜粋
  1. メニュー ボタン
  2. ナビゲーション項目
  3. 区切り記号
  4. ヘッダー
  5. 検索ボックス
  6. 「設定」 ボタン
NavigationView の上部ペインの構造
https://docs.microsoft.com/ja-jp/windows/apps/design/controls/navigationview より抜粋
  1. ヘッダー
  2. ナビゲーション項目
  3. 区切り記号
  4. 検索ボックス
  5. 「設定」ボタン

NavigationViewを導入する

まずはNavigationViewに最低限の機能を実装したアプリを作成してみましょう。

ここでは、左側のメニューに「再生」「保存」「更新」「ダウンロード」の4つのメニューを用意し、それぞれのメニューからPage1 / Page2 / Page3 / Page4に遷移できるようにしておきましょう。

MainWindow

MainWindow.xaml
<Window ...(省略)... >

    <NavigationView Header="ヘッダー" PaneTitle="タイトル" SelectionChanged="NavigationView_SelectionChanged">
        <NavigationView.MenuItems>
            <NavigationViewItem Icon="Play" Content="再生" Tag="SamplePage1"/>
            <NavigationViewItem Icon="Save" Content="保存" Tag="SamplePage2"/>
            <NavigationViewItem Icon="Refresh" Content="更新" Tag="SamplePage3"/>
            <NavigationViewItem Icon="Download" Content="ダウンロード" Tag="SamplePage4"/>
        </NavigationView.MenuItems>
        <Frame x:Name="contentFrame"/>
    </NavigationView>
    
</Window>
MainWindow.xaml.cs
public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
    }

    private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
    {
        var selectedItem = (NavigationViewItem)args.SelectedItem;
        if ((string)selectedItem.Tag == "SamplePage1") contentFrame.Navigate(typeof (Page1));
        else if ((string)selectedItem.Tag == "SamplePage2") contentFrame.Navigate(typeof(Page2));
        else if ((string)selectedItem.Tag == "SamplePage3") contentFrame.Navigate(typeof(Page3));
        else if ((string)selectedItem.Tag == "SamplePage4") contentFrame.Navigate(typeof(Page4));
    }
}

NavigationViewMenuItemsプロパティにNavigationViewItemをコレクション構文で指定することで、メニューを追加することができます。 NavigationViewItemのTagプロパティに分かりやすい名前を付けておいて、どのメニューが選択されたかを受け取れるようにしておきます。メニューが選択されたときの動作はSelectionChangedイベントにNavigationView_SelectionChangedメソッドを登録しておきましょう。

遷移させるページは以下のようにPage1-Page4までを作成しておきます。

Page1

Page1.xaml
<Page ...(省略)... >

    <Grid>
        <TextBlock Text="ページ1"/>
    </Grid>
</Page>

Page2

Page2.xaml
<Page ...(省略)... >

    <Grid>
        <TextBlock Text="ページ2"/>
    </Grid>
</Page>

Page3

Page3.xaml
<Page ...(省略)... >

    <Grid>
        <TextBlock Text="ページ3"/>
    </Grid>
</Page>

Page4

Page4.xaml
<Page ...(省略)... >

    <Grid>
        <TextBlock Text="ページ4"/>
    </Grid>
</Page>

これにより以下のようなアプリができました。

NavigationViewのデザインを調整する

メニューの表示位置を変える

NavigationViewのPaneDisplayModeプロパティでナビゲーション・メニューの表示位置を左側か上部かに指定することができます。

先ほどのサンプルアプリのナビゲーション・メニューを上部に表示してみましょう。

MainWindow

MainWindow.xaml
<Window ...(省略)... >

    <NavigationView Header="ヘッダー" PaneTitle="タイトル" PaneDisplayMode="Top"  SelectionChanged="NavigationView_SelectionChanged">
        <NavigationView.MenuItems>
            <NavigationViewItem Icon="Play" Content="再生" Tag="SamplePage1"/>
            <NavigationViewItem Icon="Save" Content="保存" Tag="SamplePage2"/>
            <NavigationViewItem Icon="Refresh" Content="更新" Tag="SamplePage3"/>
            <NavigationViewItem Icon="Download" Content="ダウンロード" Tag="SamplePage4"/>
        </NavigationView.MenuItems>
        <Frame x:Name="contentFrame"/>
    </NavigationView>
    
</Window>

なお、PaneDisplayModeプロパティで設定できる項目は以下の通りです。

  • Auto
  • Left
  • LeftCompact
  • LeftMinimal
  • Top

LeftCompactとLeftMinimalにすると以下のように表示されます。

LeftCompactLeftMinimal

なお、デフォルトではPaneDisplayModeプロパティはAutoに設定されており、アプリのウィンドウサイズを小さくすると自動的に「Left」→「LeftCompact」→「LeftMinimal」と変化します。この時表示モードが変わる境となるウィンドウ幅はそれぞれExpandedModeThresholdWidthプロパティとCompactModeThresholdWidthプロパティで指定されます。

メニューに階層構造を作る

今まではNavigationViewMenuItemsプロパティにNavigationViewItemを指定してきましたが、NavigationViewItem自体にもMenuItemsプロパティが用意されており、そこにさらにNavigationViewItemを指定することでメニューを階層構造にすることができます。

MainWindow

MainWindow.xaml
<Window ...(省略)... >

    <NavigationView Header="ヘッダー" PaneTitle="タイトル"  SelectionChanged="NavigationView_SelectionChanged">
        <NavigationView.MenuItems>
            <NavigationViewItem Icon="Play" Content="再生" Tag="SamplePage1"/>
            <NavigationViewItem Icon="Save" Content="保存" Tag="SamplePage2">
                <NavigationViewItem.MenuItems>
                    <NavigationViewItem Icon="Print" Content="印刷"/>
                    <NavigationViewItem Icon="Mail" Content="メール"/>
                </NavigationViewItem.MenuItems>
            </NavigationViewItem>
            <NavigationViewItem Icon="Refresh" Content="更新" Tag="SamplePage3"/>
            <NavigationViewItem Icon="Download" Content="ダウンロード" Tag="SamplePage4"/>
        </NavigationView.MenuItems>
        <Frame x:Name="contentFrame"/>
    </NavigationView>
    
</Window>

なお、ナビゲーション・メニュー内にラベルを付けて、メニューを整理させるためにはMenuItemsNavigationViewItemHeaderを配置させ、区切り線を入れるにはNavigationViewItemSeparatorを配置させます。

フッターメニューを配置する

NavigationViewのMenuItemsプロパティの代わりにFooterMenuItemsプロパティにNavigationViewItemをコレクション構文で指定することで、ナビゲーション・メニューの下部(Footer)にメニューを配置できます。なお、PaneDisplayModeがtopに設定されている場合は、ナビゲーション・メニューの右側に配置されます。

それでは、サンプルアプリのナビゲーション・メニューの下部に「メッセージ」「ユーザー」メニューを追加してみましょう。

MainWindow

MainWindow.xaml
<Window ...(省略)... >

    <NavigationView Header="ヘッダー" PaneTitle="タイトル" SelectionChanged="NavigationView_SelectionChanged">
        <NavigationView.MenuItems>
            <NavigationViewItem Icon="Play" Content="再生" Tag="SamplePage1"/>
            <NavigationViewItem Icon="Save" Content="保存" Tag="SamplePage2"/>
            <NavigationViewItem Icon="Refresh" Content="更新" Tag="SamplePage3"/>
            <NavigationViewItem Icon="Download" Content="ダウンロード" Tag="SamplePage4"/>
        </NavigationView.MenuItems>
        <NavigationView.FooterMenuItems>
            <NavigationViewItem Icon="Message" Content="メッセージ"/>
            <NavigationViewItem Icon="OtherUser" Content="ユーザー"/>
        </NavigationView.FooterMenuItems>
        <Frame x:Name="contentFrame"/>
    </NavigationView>
    
</Window>

これでナビゲーション・メニューの下部(Footer)に「メッセージ」「ユーザー」メニューを追加することができました。

PaneDisplayMode=”top”の場合は次のようになります。

「設定」ボタン・「戻る」ボタンの表示・非表示を切り替える

NavigationViewIsSettingsVisibleプロパティで設定ボタンの表示・非表示を、IsBackButtonVisibleプロパティで戻るボタンの表示・非表示を切り替えることができます。

設定ボタン・戻るボタン共に表示しないようにしてみましょう。

MainWindow

MainWindow.xaml
<Window ...(省略)... >

    <NavigationView Header="ヘッダー" PaneTitle="タイトル" SelectionChanged="NavigationView_SelectionChanged" IsSettingsVisible="False" IsBackButtonVisible="Collapsed">
        <NavigationView.MenuItems>
            <NavigationViewItem Icon="Play" Content="再生" Tag="SamplePage1"/>
            <NavigationViewItem Icon="Save" Content="保存" Tag="SamplePage2"/>
            <NavigationViewItem Icon="Refresh" Content="更新" Tag="SamplePage3"/>
            <NavigationViewItem Icon="Download" Content="ダウンロード" Tag="SamplePage4"/>
        </NavigationView.MenuItems>
        <Frame x:Name="contentFrame"/>
    </NavigationView>
    
</Window>

検索ボックスを組み込む

NavigationViewAutoSuggestBoxプロパティにAutoSuggestBoxを指定することで、ナビゲーション・メニューに検索ボックスを組み込むことができます。

MainWindow

MainWindow.xaml
<Window ...(省略)... >

    <NavigationView Header="ヘッダー" PaneTitle="タイトル" SelectionChanged="NavigationView_SelectionChanged">
        <NavigationView.AutoSuggestBox>
            <AutoSuggestBox QueryIcon="Find"/>
        </NavigationView.AutoSuggestBox>
        <NavigationView.MenuItems>
            <NavigationViewItem Icon="Play" Content="再生" Tag="SamplePage1"/>
            <NavigationViewItem Icon="Save" Content="保存" Tag="SamplePage2"/>
            <NavigationViewItem Icon="Refresh" Content="更新" Tag="SamplePage3"/>
            <NavigationViewItem Icon="Download" Content="ダウンロード" Tag="SamplePage4"/>
        </NavigationView.MenuItems>
        <Frame x:Name="contentFrame"/>
    </NavigationView>
    
</Window>

ナビゲーション領域に任意のコントロールを配置する

NavigationViewPaneCustomContentプロパティに任意のコントロールを配置させることが可能です。ここで配置させた要素はナビゲーション・メニューの一番上に配置されます。

例えば以下のようにしてボタンを配置させてみましょう。

MainWindow

MainWindow.xaml
<Window ...(省略)... >

    <NavigationView Header="ヘッダー" PaneTitle="タイトル" SelectionChanged="NavigationView_SelectionChanged">
        <NavigationView.PaneCustomContent>
            <StackPanel Orientation="Horizontal">
                <Button Content="ボタン1"/>
                <Button Content="ボタン2"/>
                <Button Content="ボタン3"/>
            </StackPanel>
        </NavigationView.PaneCustomContent>
        <NavigationView.MenuItems>
            <NavigationViewItem Icon="Play" Content="再生" Tag="SamplePage1"/>
            <NavigationViewItem Icon="Save" Content="保存" Tag="SamplePage2"/>
            <NavigationViewItem Icon="Refresh" Content="更新" Tag="SamplePage3"/>
            <NavigationViewItem Icon="Download" Content="ダウンロード" Tag="SamplePage4"/>
        </NavigationView.MenuItems>
        <Frame x:Name="contentFrame"/>
    </NavigationView>
    
</Window>

NavigationViewの動作を定義する

メニューから表示させるページを遷移させる

NavigatioViewではコンテントプロパティにFrameを組み込み、そのFrameの中でPageを遷移させます。Frameを用いたナビゲーションについては以下後ご覧ください。

NavigationViewItemが選択されると、NavigationViewに次のようなイベントが発生します。

現在選択されているアイテムと同じものが選択されたときに、SelectionChangedイベントは発生しませんが、ItemInvokedはイベント発生するという違いがあります。

ここではSelectionChangedイベントに処理を登録していきましょう。XAMLのコード・ビハインドに以下のようなNavigationView_SelectionChangedメソッドを作成し、これを登録します。(プログラム全体は最初のサンプルアプリをご参照ください)

MainWindow

MainWindow.xaml.cs
private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
    var selectedItem = (NavigationViewItem)args.SelectedItem;
    if ((string)selectedItem.Tag == "SamplePage1") contentFrame.Navigate(typeof(Page1));
    else if ((string)selectedItem.Tag == "SamplePage2") contentFrame.Navigate(typeof(Page2));
    else if ((string)selectedItem.Tag == "SamplePage3") contentFrame.Navigate(typeof(Page3));
    else if ((string)selectedItem.Tag == "SamplePage4") contentFrame.Navigate(typeof(Page4));
}

選択されたメニューはNavigationViewSelectionChangedEventArgsオブジェクトのSelectedItemプロパティで受け取ります。選択されたメニューのTagによって条件分岐し、FrameNavigateメソッドで指定のPageを表示させています。

「設定」ボタンで設定ページを表示させる

設定ボタンを選択しても発生するイベントは他のメニューと同じで、ItemInvokedイベントやSelectionChangedイベントとなります。SelectionChangedイベントの場合はNavigationViewSelectionChangedEventArgsオブジェクトが引数として渡されますが、そのオブジェクトのIsSettingsSelectedプロパティで「設定」ボタンが選択されているかどうかを取得することができます。

「設定」ボタンの処理を定義する際は、これを用いて「設定」ボタンが選択されたか否かを条件分岐しましょう。以下は「設定」ボタンを選択すると、あらかじめ作成しておいたSettingsPageが表示されるようにした書き換えたプログラムです。

MainWindow

MainWindow.xaml.cs
public sealed partial class MainWindow : Window
{

    ...(省略)...

        private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
        {
            if (args.IsSettingsSelected)
            {
                contentFrame.Navigate(typeof(SettingsPage));
            }
            else
            {
                var selectedItem = (NavigationViewItem)args.SelectedItem;
                if ((string)selectedItem.Tag == "SamplePage1") contentFrame.Navigate(typeof(Page1));
                else if ((string)selectedItem.Tag == "SamplePage2") contentFrame.Navigate(typeof(Page2));
                else if ((string)selectedItem.Tag == "SamplePage3") contentFrame.Navigate(typeof(Page3));
                else if ((string)selectedItem.Tag == "SamplePage4") contentFrame.Navigate(typeof(Page4));
            }
        }

    ...(省略)...

}

「戻る」ボタンの処理を定義する

NavigationViewの「戻る」ボタンはデフォルトでは表示はされていますが、クリックできない状態となっています。まずはIsBackEnabledプロパティをTrueに設定して有効化しましょう。「戻る」ボタンがクリックされるとBackRequestedイベントが発生するので、ここに処理を登録します。

以下の例ではNavigationView_BackRequestedメソッドを作成し、BackRequestedイベントに登録しています。実際の処理自体はFrameのナビゲーションを用います。

MainWindow

MainWindow.xaml
<Window ...(省略)... >

    <NavigationView Header="ヘッダー" PaneTitle="タイトル" SelectionChanged="NavigationView_SelectionChanged" IsBackEnabled="True" BackRequested="NavigationView_BackRequested">
        <NavigationView.MenuItems>
            <NavigationViewItem Icon="Play" Content="再生" Tag="SamplePage1"/>
            <NavigationViewItem Icon="Save" Content="保存" Tag="SamplePage2"/>
            <NavigationViewItem Icon="Refresh" Content="更新" Tag="SamplePage3"/>
            <NavigationViewItem Icon="Download" Content="ダウンロード" Tag="SamplePage4"/>
        </NavigationView.MenuItems>
        <Frame x:Name="contentFrame"/>
    </NavigationView>
    
</Window>
MainWindow.xaml.cs
public sealed partial class MainWindow : Window
{

    ...(省略)...

        private void NavigationView_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
        {
            if (contentFrame.CanGoBack)
            {
                contentFrame.GoBack();
            }
        }

    ...(省略)...

}

関連記事・スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)