2026年版 WinUIアプリ開発 Tips:NavigationViewとFrameで「戻る」が壊れない画面遷移を作る

スポンサーリンク

WinUI 3で複数画面の業務アプリを作るとき、最初につまずきやすいのが画面遷移です。ボタンのClickイベントでPageを切り替えるだけなら簡単ですが、画面が増えると「戻るボタンをどうするか」「同じ項目をもう一度押したらどうするか」「ウィンドウを狭くしたときメニューをどう見せるか」といった問題が一気に増えます。

そこで役立つのがNavigationViewとFrameの組み合わせです。NavigationViewはアプリのトップレベルナビゲーションを担当し、Frameは実際のPage遷移と履歴を担当します。今回は、この2つの役割を分けて「戻る」が自然に動く基本構成を作ります。

NavigationViewだけでは画面遷移は完成しない

NavigationViewは、左ペインや上部メニューを持つナビゲーションUIです。Microsoftの公式ガイドでは、画面サイズに適応しながら一貫したトップレベルナビゲーションを提供するコントロールとして説明されています。一方、NavigationViewItemを選択しただけでPageが自動的に切り替わるわけではありません。

ここでFrameを組み合わせます。FrameはPageを表示する入れ物で、Navigateによる遷移だけでなく、戻る履歴も管理します。イメージとしては、NavigationViewが「建物の案内板」、Frameが「実際に部屋を移動し、通った部屋を覚えている係」です。

まずはXAMLでナビゲーションの骨格を作る

次の例では、ホーム画面と設定画面の2項目を用意し、NavigationViewのContentとしてFrameを配置します。

<NavigationView x:Name="NavView"
                IsBackButtonVisible="Auto"
                IsBackEnabled="{x:Bind ContentFrame.CanGoBack, Mode=OneWay}"
                ItemInvoked="NavView_ItemInvoked"
                BackRequested="NavView_BackRequested">
    <NavigationView.MenuItems>
        <NavigationViewItem Content="ホーム"
                            Tag="home">
            <NavigationViewItem.Icon>
                <SymbolIcon Symbol="Home" />
            </NavigationViewItem.Icon>
        </NavigationViewItem>
        <NavigationViewItem Content="レポート"
                            Tag="report" />
    </NavigationView.MenuItems>

    <Frame x:Name="ContentFrame" />
</NavigationView>

IsBackButtonVisible="Auto"にすると、NavigationViewが表示モードなどに応じて戻るボタンの見せ方を扱えます。IsBackEnabledにはFrameのCanGoBackを結び付け、実際に戻れる履歴があるときだけ戻る操作を有効にします。

選択された項目からPageへ遷移する

コードビハインドでは、NavigationViewItemのTagを画面識別子として使い、遷移先の型を決めます。

private void NavView_ItemInvoked(
    NavigationView sender,
    NavigationViewItemInvokedEventArgs args)
{
    if (args.InvokedItemContainer is not NavigationViewItem item)
        return;

    Type? pageType = item.Tag switch
    {
        "home"   => typeof(HomePage),
        "report" => typeof(ReportPage),
        _ => null
    };

    if (pageType is null)
        return;

    if (ContentFrame.CurrentSourcePageType != pageType)
    {
        ContentFrame.Navigate(pageType);
    }
}

ここで大切なのは、CurrentSourcePageTypeを確認している点です。同じ「ホーム」を何度も押すたびにNavigateすると、同じPageが履歴へ積み重なります。その状態で戻ると「ホームからホームへ戻る」という不自然な履歴になります。同一ページへの不要なNavigateを避けるだけで、戻る履歴をかなりきれいに保てます。

戻る処理はFrameの履歴に任せる

NavigationViewの戻るボタンが押されたら、Frameが戻れることを確認してGoBackを呼びます。

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

自分で「直前のページ」を変数へ保存する方式でも2画面程度なら動きます。しかし、ホーム→レポート→詳細→設定のように遷移が増えると、履歴管理を自作するコードは複雑になります。FrameにはBackStackがあり、Navigateした履歴を持てるため、通常のページ遷移ではその仕組みを利用するほうが自然です。

NavigationViewとFrameの役割を混ぜない

初心者が混乱しやすいのは、「選択中のメニュー」と「現在表示しているPage」を同じものとして扱うことです。トップレベルのNavigationViewItemは大きなカテゴリを表しますが、Frameの履歴にはそのカテゴリ内の詳細Pageも入ることがあります。

たとえば「レポート」を選び、ReportPageからReportDetailPageへ進んだ場合、NavigationViewでは引き続き「レポート」を選択状態にしたいはずです。詳細PageをNavigationViewのMenuItemsへ追加する必要はありません。NavigationViewはアプリの主要な場所、Frameはその中を含む実際の移動履歴、と役割を分けると設計しやすくなります。

ウィンドウ幅への対応はNavigationViewに任せやすい

NavigationViewの強みは、単にメニューを表示できることではありません。PaneDisplayModeで左側や上部などのナビゲーション方式を選べ、既定のAdaptive動作では利用可能な幅に応じて表示状態を変えられます。Microsoftも、NavigationViewをさまざまな画面サイズへ適応するトップレベルナビゲーションとして位置付けています。

そのため、独自Gridで「幅が狭くなったらメニューを隠す」処理を一から組む前に、NavigationViewの表示モードで要件を満たせないか確認するとよいでしょう。業務アプリでも、ノートPCの狭いウィンドウと大型モニターの最大化表示の両方に対応しやすくなります。

実務では文字列Tagから一段進める

今回の例では分かりやすさを優先してTag="home"のような文字列を使いました。小規模アプリなら十分ですが、画面数が増えると文字列のタイプミスやswitch文の肥大化が起きます。

実務では、ナビゲーション先を表すモデルやサービスを用意し、Page型とメニュー項目の対応を一か所へ集約する方法を検討できます。さらにMVVMを採用するなら、画面遷移そのものをNavigationServiceとして分離すると、ViewModelがWindowやFrameへ直接依存しない構成にしやすくなります。

ただし、最初から抽象化を増やしすぎる必要はありません。まずNavigationViewとFrameの責務を理解し、画面数やテスト要件が増えてからサービスへ切り出すほうが、仕組みを理解しやすいでしょう。

注意点:Pageの状態と履歴は別問題

Frameが戻る履歴を持っていても、Pageインスタンスの状態が必ずそのまま残るとは限りません。フォームへの入力内容や検索条件など「戻ったときに復元したい状態」がある場合は、Pageのキャッシュ、ViewModel、アプリ側の状態管理などを別途設計する必要があります。

また、戻る操作にはNavigationViewのボタン以外にも、マウスの戻るボタンやキーボード操作などを考慮するアプリがあります。今回のコードはNavigationView上の基本的な戻る操作に絞った例であり、アプリ全体の入力方式を網羅したものではありません。

2026年時点でのWindows App SDKも確認する

WinUI 3はWindows App SDKの一部として提供されています。Microsoftの公式情報では、2026年9月時点でWindows App SDK 1.8系の安定版が公開されています。新規プロジェクトでは、利用するWindows App SDKとサポート期間を確認しながら開発してください。この記事のNavigationViewとFrameの基本パターンは特定の新機能だけに依存するものではありませんが、実際のプロジェクトでは参照しているSDKバージョンの公式ドキュメントも合わせて確認することが重要です。

まとめ

WinUI 3の複数画面アプリでは、NavigationViewを「トップレベルの案内」、Frameを「Page表示と履歴管理」として分けると構成が整理できます。NavigationViewItemからFrame.Navigateを呼び、戻るときはFrame.CanGoBackを確認してGoBackする、という流れが基本です。

さらに、同じPageへの重複Navigateを避ける、詳細PageまでNavigationViewへ並べない、Pageの状態保持とナビゲーション履歴を別の問題として考える。この3点を意識すると、画面が増えても「戻る」が壊れにくい設計になります。ナビゲーションは見た目のメニューではなく、ユーザーがアプリの中で迷わないための道筋です。最初に役割を整理しておくと、その後の画面追加もずっと楽になります。

参考資料

Please follow and like us:

コメント

タイトルとURLをコピーしました