前回のレッスンで左サイドバーを表示する機能を実装しました。サイドバー内にFrameコントロールが配置され、メインウィンドウ起動時は既定で空ページが読み込まれるようになっています。しかし現状、左メニュー項目をクリックしても他のページへ切り替わりません。今回の授業でこの機能を完成させ、左側の各メニューをクリックすると対応するページ(Page)が開くように実装します。
最終的な動作イメージ

メインウィンドウのメニュー項目を編集
MainWindow.xaml を開いて編集します
<NavigationView x:Name="NavView" PaneDisplayMode="Left" SelectionChanged="OnNavViewSelectionChanged">
<NavigationView.MenuItems>
<NavigationViewItem Content="Dashboard" Tag="DashboardPage" Icon="Home"/>
<NavigationViewItem Content="Analytics" Tag="AnalyticsPage" Icon="Account"/>
<NavigationViewItem Content="Play" Tag="PlayPage" Icon="Play"/>
</NavigationView.MenuItems>
<Frame x:Name="MainFrame"/>
</NavigationView>Code language: HTML, XML (xml)
主な変更点:
- NavigationView に選択変更イベントを追加:SelectionChanged=”OnNavViewSelectionChanged。メニュー切り替え時にこのイベントが発火します。
- メニュー項目を追加・修正:<NavigationViewItem Content=”Play” Tag=”PlayPage” Icon=”Play”/>。Contentはメニューに表示する文字、Tagの文字列は遷移先ページ名、IconはWinUI標準アイコンです。
空ページを3つ作成:DashboardPage、AnalyticsPage、PlayPage
各ページのGrid内にTextBlockを配置し、それぞれ異なるテキストを表示してページを区別できるようにします。
<Grid>
<TextBlock Text="Dashboard Page" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"/>
</Grid>Code language: HTML, XML (xml)
<Grid>
<TextBlock Text="Analytics Page" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"/>
</Grid>Code language: HTML, XML (xml)
<Grid>
<TextBlock Text="Play Page" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"/>
</Grid>Code language: HTML, XML (xml)
ページ切り替え用関数を実装
XAML内のイベント名 OnNavViewSelectionChanged にカーソルを合わせ、F12 キーを押すと、Visual Studioが自動的にイベント関数を生成します。.hヘッダーに関数宣言が作成され(実装は記載されない)、対応する.cppファイルに実装用の雛形が作成されカーソルが移動します。利用者はヘッダーファイルを直接編集する必要はありません。

以下が MainWindow.xaml.cpp の実装コードです。
void winrt::AppWinui::implementation::MainWindow::OnNavViewSelectionChanged(winrt::Microsoft::UI::Xaml::Controls::NavigationView const& sender,
winrt::Microsoft::UI::Xaml::Controls::NavigationViewSelectionChangedEventArgs const& args)
{
// 選択されたメニュー項目を取得
auto selectedItem = args.SelectedItem().as<NavigationViewItem>();
if (!selectedItem) return;
// Tag文字列を取り出す
hstring tag = unbox_value<hstring>(selectedItem.Tag());
winrt::Windows::UI::Xaml::Interop::TypeName targetPage;
// Tagに応じてページ型を割り当て
if (tag == L"DashboardPage")
{
targetPage = xaml_typename<AppWinui::DashboardPage>();
}
else if (tag == L"AnalyticsPage")
{
targetPage = xaml_typename<AppWinui::AnalyticsPage>();
}
else if (tag == L"PlayPage")
{
targetPage = xaml_typename<AppWinui::PlayPage>();
}
else
{
return;
}
// Frameでページ遷移
MainFrame().Navigate(targetPage);
}Code language: C++ (cpp)
ファイル上部に名前空間とヘッダーを追加する必要があります
using namespace Microsoft::UI::Xaml;
#include "BlankPage.xaml.h"
#include "DashboardPage.xaml.h"
#include "AnalyticsPage.xaml.h"
#include "PlayPage.xaml.h"
#include <winrt/Windows.UI.Xaml.Interop.h>
using namespace winrt::Microsoft::UI::Xaml::Controls;Code language: C++ (cpp)
イベント関数の主要コード解説
auto selectedItem = args.SelectedItem().as<NavigationViewItem>(); ユーザーがクリックしたメニュー項目を取得
hstring tag = unbox_value<hstring>(selectedItem.Tag()); XAMLで設定したTag属性の文字列(遷移先ページ名)を取得
winrt::Windows::UI::Xaml::Interop::TypeName targetPage; ページ型情報を格納する変数を宣言。後続の MainFrame().Navigate(targetPage); の引数として使用しページ遷移を実行します。
if (tag == L"DashboardPage")
{
targetPage = xaml_typename<AppWinui::DashboardPage>();
}Code language: C++ (cpp)
Tagの文字列に一致するページ型を targetPage に代入します。
MainFrame().Navigate(targetPage); 最終的にページ遷移を実行
完全なソースコード
#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif
using namespace winrt;
using namespace Microsoft::UI::Xaml;
#include "BlankPage.xaml.h"
#include "DashboardPage.xaml.h"
#include "AnalyticsPage.xaml.h"
#include "PlayPage.xaml.h"
#include <winrt/Windows.UI.Xaml.Interop.h>
using namespace winrt::Microsoft::UI::Xaml::Controls;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace winrt::AppWinui::implementation
{
MainWindow::MainWindow()
{
InitializeComponent();
MainFrame().Navigate(xaml_typename<AppWinui::BlankPage>());
}
int32_t MainWindow::MyProperty()
{
throw hresult_not_implemented();
}
void MainWindow::MyProperty(int32_t /* value */)
{
throw hresult_not_implemented();
}
}
void winrt::AppWinui::implementation::MainWindow::OnNavViewSelectionChanged(winrt::Microsoft::UI::Xaml::Controls::NavigationView const& sender,
winrt::Microsoft::UI::Xaml::Controls::NavigationViewSelectionChangedEventArgs const& args)
{
// 選択されたメニュー項目を取得
auto selectedItem = args.SelectedItem().as<NavigationViewItem>();
if (!selectedItem) return;
// Tag文字列を取り出す
hstring tag = unbox_value<hstring>(selectedItem.Tag());
winrt::Windows::UI::Xaml::Interop::TypeName targetPage;
// Tagに応じてページ型を割り当て
if (tag == L"DashboardPage")
{
targetPage = xaml_typename<AppWinui::DashboardPage>();
}
else if (tag == L"AnalyticsPage")
{
targetPage = xaml_typename<AppWinui::AnalyticsPage>();
}
else if (tag == L"PlayPage")
{
targetPage = xaml_typename<AppWinui::PlayPage>();
}
else
{
return;
}
// Frameでページ遷移
MainFrame().Navigate(targetPage);
}
Code language: C++ (cpp)
ソースコードダウンロードリンク
左側ナビゲーションバーの項目をクリックすると各ページが開きます