2 ページ間でのナビゲーションを実装する

フレームおよびページを使用した、アプリでの基本的なピア ツー ピアのナビゲーションについて説明します。

ピア ツー ピアのナビゲーション

ほぼすべてのアプリでページ間のナビゲーションが必要です。 1 つのコンテンツ ページを持つ単純なアプリでも、通常はナビゲーションを必要とする設定ページがあります。 この記事では、アプリに XAML Page を追加し、 を使用して Frame ページ間を移動する方法の基本について説明します。

重要

この例では、Microsoft Visual Studio の 空のアプリ テンプレートを使用します。 Windows アプリ SDK/WinUI 3 アプリと UWP アプリのテンプレートには違いがあるため、アプリの種類に適したタブを選択してください。

1.空のアプリの作成

Visual Studio で空のアプリを作成するには:

  1. 開発コンピューターをセット アップするには、「Windows App SDK 用のツールをインストールする」を参照してください。
  2. Microsoft Visual Studio のスタート ウィンドウで、[ 新しいプロジェクトの作成] を選択するか、Visual Studio メニューの [ ファイル>] [新しい>プロジェクト] の順に選択します。
  3. [ 新しいプロジェクトの作成 ] ダイアログのドロップダウン フィルターで、それぞれ [C# ] または [ C++]、[ Windows]、[ WinUI] を選択します。
  4. プロジェクト テンプレートとして [空のアプリ、パッケージ (WinUI 3 in Desktop)] を選択し、[次へ] をクリックします。 そのテンプレートで、WinUI 3 ベースのユーザー インターフェイスを使用したデスクトップ アプリが作成されます。
  5. [ プロジェクト名 ] ボックスに「」と入力 BasicNavigationし、[ 作成] をクリックします。
  6. プログラムを実行するには、メニューから [デバッグ]>[デバッグの開始] の順にクリックするか、F5 キーを押します。 開発用コンピューター上でソリューションをビルドして実行し、アプリがエラーなしで動作することを確認します。 空白のページが表示されます。
  7. デバッグを終了して Visual Studio に戻るには、アプリを終了するか、メニューから [デバッグの停止] クリックします。
  8. テンプレートに含まれているコード例を、 および MainWindow 分離コード ファイルからMainWindow.xaml削除します。

ヒント

詳細については、「初めての WinUI 3 (Windows アプリ SDK) プロジェクトを作成する」を参照してください。

2. フレームを使用してページ間を移動する

アプリに複数のページがある場合は、 Frame を使用してページ間を移動します。 クラスはFrameNavigateGoBack、GoForward などのさまざまなナビゲーション メソッドと、BackStackForwardStack、BackStackDepth などのプロパティをサポートしています。

Visual Studio で新しいWindows アプリ SDK プロジェクトを作成すると、プロジェクト テンプレートによって (Microsoft.UI.Xaml.Window 型の) クラスが作成MainWindowされます。 ただし、 フレーム または ページ は作成せず、ナビゲーション コードも提供しません。

ページ間のナビゲーションを有効にするには、 のMainWindowルート要素として を追加Frameします。 これを行うには、分離コード ファイルの Application.OnLaunched メソッドの App.xaml オーバーライドを使用します。 分離コード ファイルを App 開き、オーバーライドを OnLaunched 更新し、次に示すように NavigationFailed イベントを処理します。

// App.xaml.cs

protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    m_window = new MainWindow();

    // Create a Frame to act as the navigation context and navigate to the first page
    Frame rootFrame = new Frame();
    rootFrame.NavigationFailed += OnNavigationFailed;
    // Navigate to the first page, configuring the new page
    // by passing required information as a navigation parameter
    rootFrame.Navigate(typeof(MainPage), args.Arguments);

    // Place the frame in the current Window
    m_window.Content = rootFrame;
    // Ensure the MainWindow is active
    m_window.Activate();
}

void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
    throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
// App.xaml.h

// Add after OnLaunched declaration.
void OnNavigationFailed(IInspectable const&, Microsoft::UI::Xaml::Navigation::NavigationFailedEventArgs const&);

///////////////
// App.xaml.cpp

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    window = make<MainWindow>();
    Frame rootFrame = Frame();
    rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });
    rootFrame.Navigate(xaml_typename<BasicNavigation::MainPage>(), box_value(e.Arguments()));
    window.Content(rootFrame);
    window.Activate();
}

void App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e)
{
    throw hresult_error(E_FAIL, hstring(L"Failed to load Page ") + e.SourcePageType().Name);
}

Note

より複雑なナビゲーションを使用するアプリの場合は、通常、MainWindow のルートとして NavigationView を使用し、ナビゲーション ビューのコンテンツとして を配置 Frame します。 詳細については、「 ナビゲーション ビュー」を参照してください。

Navigate メソッドは、この Frame内のコンテンツを表示するために使用されます。 ここでは、 MainPage.xaml が メソッドにNavigate渡されるため、 メソッドは にFrame読み込まれますMainPage

アプリの初期ウィンドウへのナビゲーションが失敗すると、 NavigationFailed イベントが発生し、このコードはイベント ハンドラーで例外をスローします。

3. 基本ページを追加する

空のアプリ テンプレートでは、複数のアプリ ページは作成されません。 ページ間を移動する前に、いくつかのページをアプリに追加する必要があります。

アプリに新しい項目を追加するには:

  1. ソリューション エクスプローラーで、プロジェクト ノードをBasicNavigation右クリックしてコンテキスト メニューを開きます。
  2. コンテキスト メニューから [新しい項目追加]> を選択します。
  3. [ 新しい項目の追加 ] ダイアログ ボックスで、左側のウィンドウで [WinUI ] ノードを選択し、中央のウィンドウで [空白ページ (WinUI 3)] を選択します。
  4. [ 名前 ] ボックスに「」と入力 MainPage し、[ 追加 ] ボタンを押します。
  5. 手順 1 から 4 を繰り返して 2 番目のページを追加しますが、[ 名前 ] ボックスに「」と入力 Page2します。

これで、これらのファイルがプロジェクトの BasicNavigation 一部として一覧表示されます。

C# C++
  • MainPage.xaml
  • MainPage.xaml.cs
  • Page2.xaml
  • Page2.xaml.cs
  • MainPage.xaml
  • MainPage.xaml.cpp
  • MainPage.xaml.h
  • Page2.xaml
  • Page2.xaml.cpp
  • Page2.xaml.h

重要

C++ プロジェクトの場合は、別のページを #include 参照する各ページのヘッダー ファイルに ディレクティブを追加する必要があります。 ここで示すページ間ナビゲーションの例では、mainpage.xaml.h ファイルには が含まれています #include "Page2.xaml.h"。さらに、page2.xaml.h には が #include "MainPage.xaml.h"含まれています。

C++ ページ テンプレートには、ページの XAML ファイルと分離コード ファイルから削除する必要がある例 Button とクリック ハンドラー コードも含まれています。

ページにコンテンツを追加する

MainPage.xaml、既存のページ コンテンツを次のコンテンツに置き換えます。

<Grid>
    <TextBlock x:Name="pageTitle" Text="Main Page"
               Margin="16" Style="{StaticResource TitleTextBlockStyle}"/>
    <HyperlinkButton Content="Click to go to page 2"
                     Click="HyperlinkButton_Click"
                     HorizontalAlignment="Center"/>
</Grid>

この XAML では、次の項目が追加されます。

  • Text プロパティが ルート Grid の子要素として にMain Page設定された という名前pageTitleTextBlock 要素。
  • ルート Grid の子要素として次のページに移動するために使用される HyperlinkButton 要素。

分離コード ファイルで MainPage 、次のコードを追加して、 Click へのナビゲーションを有効にするために追加した HyperlinkButton のイベントを処理します Page2.xaml

// MainPage.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(Page2));
}
// pch.h
// Add this include in pch.h to support winrt::xaml_typename

#include <winrt/Windows.UI.Xaml.Interop.h>

////////////////////
// MainPage.xaml.h

void HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

////////////////////
// MainPage.xaml.cpp

void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    Frame().Navigate(winrt::xaml_typename<BasicNavigation::Page2>());
}

MainPagePage クラスのサブクラスです。 Pageクラスには、 を含む をFrame取得する読み取り専用の Frame プロパティがありますPage。 の ClickMainPage イベント ハンドラーが をHyperlinkButton呼び出Frame.Navigate(typeof(Page2))すと、 Frame の内容Page2.xamlが表示されます。

ページがフレームに読み込まれるたびに、そのページは PageStackEntry としてフレームBackStack または ForwardStack に追加され、履歴と後方ナビゲーションが可能になります。

ここで、 で Page2.xaml同じ操作を行います。 既存のページ コンテンツを次の内容に置き換えます。

<Grid>
    <TextBlock x:Name="pageTitle" Text="Page 2"
               Margin="16" Style="{StaticResource TitleTextBlockStyle}"/>
    <HyperlinkButton Content="Click to go to main page"
                     Click="HyperlinkButton_Click"
                     HorizontalAlignment="Center"/>
</Grid>

分離コード ファイルでPage2HyperlinkButton のイベントを処理Clickして に移動する次のコードをMainPage.xaml追加します。

// Page2.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(MainPage));
}
// Page2.xaml.h

void HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

/////////////////
// Page2.xaml.cpp

void winrt::BasicNavigation::implementation::Page2::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    Frame().Navigate(winrt::xaml_typename<BasicNavigation::MainPage>());
}

アプリケーションをビルドし、実行します。 "Click to go to page 2" と書かれているリンクをクリックします。 上部に "Page 2" と書かれた 2 番目のページが読み込まれ、フレームに表示される必要があります。 次に、ページ 2 のリンクをクリックしてメイン ページに戻ります。

4. ページ間で情報を渡す

これで、アプリは 2 つのページ間を移動しますが、まだ興味深いことは何も行われません。 多くの場合、アプリに複数のページがあれば、ページ間で情報を共有する必要があります。 次に、最初のページから 2 番目のページにいくつかの情報を渡します。

MainPage.xaml、前に追加した を HyperlinkButton 次の StackPanel に置き換えます。 これにより、テキスト文字列を入力するための TextBlock ラベルと TextBoxname が追加されます。

<StackPanel VerticalAlignment="Center">
    <TextBlock HorizontalAlignment="Center" Text="Enter your name"/>
    <TextBox HorizontalAlignment="Center" Width="200" x:Name="name"/>
    <HyperlinkButton Content="Click to go to page 2"
                              Click="HyperlinkButton_Click"
                              HorizontalAlignment="Center"/>
</StackPanel>

次に、 メソッドの 2 番目のオーバーロードを Navigate 使用し、テキスト ボックスから 2 番目のパラメーターとしてテキストを渡します。 この Navigate オーバーロードのシグネチャを次に示します。

public bool Navigate(System.Type sourcePageType, object parameter);
bool Navigate(TypeName const& sourcePageType, IInspectable const& parameter);

HyperlinkButton_Click分離コード ファイルのイベント ハンドラーで、テキスト ボックスの MainPage プロパティをNavigate参照する 2 番目のパラメーターを Text メソッドにname追加します。

// MainPage.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(Page2), name.Text);
}
// MainPage.xaml.cpp

void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{ 
    Frame().Navigate(xaml_typename<BasicNavigation::Page2>(), winrt::box_value(name().Text()));
}

Page2.xaml、前に追加した HyperlinkButton を次 StackPanelの に置き換えます。 これにより、 からMainPage渡されたテキスト文字列を表示するための TextBlock が追加されます。

<StackPanel VerticalAlignment="Center">
    <TextBlock HorizontalAlignment="Center" x:Name="greeting"/>
    <HyperlinkButton Content="Click to go to page 1"
                     Click="HyperlinkButton_Click"
                     HorizontalAlignment="Center"/>
</StackPanel>

分離コード ファイルで Page2 、次のコードを追加して メソッドを OnNavigatedTo オーバーライドします。

// Page2.xaml.cs

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (e.Parameter is string && !string.IsNullOrWhiteSpace((string)e.Parameter))
    {
        greeting.Text = $"Hello, {e.Parameter.ToString()}";
    }
    else
    {
        greeting.Text = "Hello!";
    }
    base.OnNavigatedTo(e);
}
// Page2.xaml.h

void Page2::OnNavigatedTo(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e)
{
	auto propertyValue{ e.Parameter().as<Windows::Foundation::IPropertyValue>() };
	if (propertyValue.Type() == Windows::Foundation::PropertyType::String)
	{
		auto name{ winrt::unbox_value<winrt::hstring>(e.Parameter()) };
		if (!name.empty())
		{
			greeting().Text(L"Hello, " + name);
			__super::OnNavigatedTo(e);
			return;
		}
	}
	greeting().Text(L"Hello!");
	__super::OnNavigatedTo(e);
}

アプリを実行し、テキスト ボックスに自分の名前を入力し、 というリンク Click to go to page 2をクリックします。

の イベントが Click を呼び出Frame.Navigate(typeof(Page2), name.Text)すと、 name.Text プロパティが にPage2渡され、イベント データの値がページに表示されるメッセージに使用HyperlinkButtonされます。MainPage

5. ページをキャッシュする

ページのコンテンツと状態は既定ではキャッシュされないため、情報をキャッシュする場合は、アプリの各ページでキャッシュを有効にする必要があります。

基本的なピア ツー ピアの例では、 のリンクPage2TextBoxClick to go to page 1クリックすると、 (およびその他のフィールド) MainPage が既定の状態に設定されます。 これを回避する方法の 1 つは、NavigationCacheMode プロパティを使って、ページがフレームのページ キャッシュに追加されるように指定することです。

既定では、ナビゲーションが発生するたびに、既定値を使用して新しいページ インスタンスが作成されます。 でMainPage.xaml、 を (開始Pageタグ内で) にEnabled設定NavigationCacheModeしてページをキャッシュし、フレームのページ キャッシュを超えるまでページのすべてのコンテンツと状態の値を保持します。 CacheSize の制限を無視する場合は、NavigationCacheModeRequired に設定します。これで、フレームにキャッシュできる、ナビゲーション履歴内のページ数を指定します。 ただし、キャッシュ サイズの制限は、デバイスのメモリの制限に依存しており、重要である可能性があることに注意してください。

<Page
    x:Class="BasicNavigation.MainPage"
    ...
    mc:Ignorable="d"
    NavigationCacheMode="Enabled">

ここで、メインページに戻ると、テキスト ボックスに入力した名前が表示されます。

6. ページ切り替えアニメーションをカスタマイズする

既定では、ナビゲーションが発生すると、各ページがフレームにアニメーション化されます。 既定のアニメーションは、ウィンドウの下部からページを上にスライドさせる "開始" アニメーションです。 ただし、アプリのナビゲーションに適したさまざまなアニメーション オプションを選択できます。 たとえば、"ドリルイン" アニメーションを使用して、ユーザーがアプリに深く入り込んでいるような感覚を与えたり、水平スライド アニメーションを使用して 2 つのページがピアであるという感覚を与えたりできます。 詳細については、「 ページ切り替え」を参照してください。

これらのアニメーションは、 NavigationTransitionInfo のサブクラスで表されます。 ページ切り替えに使用するアニメーションを指定するには、 メソッドの 3 番目のオーバーロードをNavigate使用し、3 番目のパラメーター (infoOverride) としてサブクラスを渡NavigationTransitionInfoします。 この Navigate オーバーロードのシグネチャを次に示します。

public bool Navigate(System.Type sourcePageType, 
                     object parameter,
                     NavigationTransitionInfo infoOverride);
bool Navigate(TypeName const& sourcePageType, 
              IInspectable const& parameter, 
              NavigationTransitionInfo const& infoOverride);

分離コード ファイルのHyperlinkButton_ClickMainPageイベント ハンドラーで、Effect プロパティが FromRightNavigate設定された SlideNavigationTransitionInfo にパラメーターを設定infoOverrideする 3 番目のパラメーターを メソッドに追加します。

// MainPage.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(Page2), 
                   name.Text,
                   new SlideNavigationTransitionInfo() 
                       { Effect = SlideNavigationTransitionEffect.FromRight});
}
// pch.h

#include <winrt/Microsoft.UI.Xaml.Media.Animation.h>

////////////////////
// MainPage.xaml.cpp

using namespace winrt::Microsoft::UI::Xaml::Media::Animation;

// ...

void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{   
    // Create the slide transition and set the transition effect to FromRight.
    SlideNavigationTransitionInfo slideEffect = SlideNavigationTransitionInfo();
    slideEffect.Effect(SlideNavigationTransitionEffect(SlideNavigationTransitionEffect::FromRight));
    Frame().Navigate(winrt::xaml_typename<BasicNavigation::Page2>(),
        		     winrt::box_value(name().Text()),
                     slideEffect);
}

HyperlinkButton_Click分離コード ファイルのPage2イベント ハンドラーで、 パラメーターを infoOverrideSlideNavigationTransitionInfo に設定し、Effect プロパティを FromLeft に設定します。

// Page2.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(MainPage),
                   null,
                   new SlideNavigationTransitionInfo() 
                       { Effect = SlideNavigationTransitionEffect.FromLeft});
}
// Page2.xaml.cpp

using namespace winrt::Microsoft::UI::Xaml::Media::Animation;

// ...

void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{   
    // Create the slide transition and set the transition effect to FromLeft.
    SlideNavigationTransitionInfo slideEffect = SlideNavigationTransitionInfo();
    slideEffect.Effect(SlideNavigationTransitionEffect(SlideNavigationTransitionEffect::FromLeft));
    Frame().Navigate(winrt::xaml_typename<BasicNavigation::MainPage>(),
        		     nullptr,
                     slideEffect);
}

ページ間を移動すると、ページは左右にスライドします。これにより、この切り替えに対してより自然な感覚が得られ、ページ間の接続が強化されます。