2 ページ間でのナビゲーションを実装するImplement navigation between two pages

フレームおよびページを使用した、アプリでの基本的なピア ツー ピアのナビゲーションについて説明します。Learn how to use a frame and pages to enable basic peer-to-peer navigation in your app.

重要な API:Windows.UI.Xaml.Controls.Frame クラス、Windows.UI.Xaml.Controls.Page クラス、Windows.UI.Xaml.Navigation 名前空間Important APIs: Windows.UI.Xaml.Controls.Frame class, Windows.UI.Xaml.Controls.Page class, Windows.UI.Xaml.Navigation namespace

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

1.空のアプリの作成1. Create a blank app

  1. Microsoft Visual Studio のメニューで、 [ファイル] > [新しいプロジェクト] の順にクリックします。On the Microsoft Visual Studio menu, choose File > New Project.
  2. [新しいプロジェクト] ダイアログ ボックスの左側のウィンドウで、 [Visual C#] > [Windows] > [ユニバーサル] ノード、または [Visual C++] > [Windows] > [ユニバーサル] ノードの順にクリックします。In the left pane of the New Project dialog box, choose the Visual C# > Windows > Universal or the Visual C++ > Windows > Universal node.
  3. 中央のウィンドウで、 [空のアプリケーション] をクリックします。In the center pane, choose Blank App.
  4. [名前] ボックスに「NavApp1」と入力し、 [OK] をクリックします。In the Name box, enter NavApp1, and then choose the OK button. ソリューションが作られ、プロジェクト ファイルがソリューション エクスプローラーに表示されます。The solution is created, and the project files appear in Solution Explorer.
  5. プログラムを実行するには、メニューから [デバッグ] > [デバッグの開始] の順にクリックするか、F5 キーを押します。To run the program, choose Debug > Start Debugging from the menu, or press F5. 空白のページが表示されます。A blank page is displayed.
  6. デバッグを終了して Visual Studio に戻るには、アプリを終了するか、メニューから [デバッグの停止] クリックします。To stop debugging and return to Visual Studio, exit the app, or click Stop Debugging from the menu.

2.基本ページの追加2. Add basic pages

次に、プロジェクトにページを 2 つ追加します。Next, add two pages to the project.

  1. ソリューション エクスプローラーで、 [BlankApp] プロジェクト ノードを右クリックして、ショートカット メニューを開きます。In Solution Explorer, right-click the BlankApp project node to open the shortcut menu.
  2. ショートカット メニューで、 [追加] > [新しい項目] を選択します。Choose Add > New Item from the shortcut menu.
  3. [新しい項目の追加] ダイアログ ボックスの中央のウィンドウで、 [空白のページ] をクリックします。In the Add New Item dialog box, choose Blank Page in the middle pane.
  4. [名前] ボックスに「Page1」(または「Page2」) と入力し、 [追加] をクリックします。In the Name box, enter Page1 (or Page2) and press the Add button.
  5. 手順 1 ~ 4 を繰り返して、2 つ目のページを追加します。Repeat steps 1-4 to add the second page.

これで、NavApp1 プロジェクトの一部としてこれらのファイルが表示されます。Now, these files should be listed as part of your NavApp1 project.

C#C# C++C++
  • Page1.xamlPage1.xaml
  • Page1.xaml.csPage1.xaml.cs
  • Page2.xamlPage2.xaml
  • Page2.xaml.csPage2.xaml.cs
  • Page1.xamlPage1.xaml
  • Page1.xaml.cppPage1.xaml.cpp
  • Page1.xaml.hPage1.xaml.h
  • Page2.xamlPage2.xaml
  • Page2.xaml.cppPage2.xaml.cpp
  • Page2.xaml.hPage2.xaml.h

Page1.xaml に次のコンテンツを追加します。In Page1.xaml, add the following content:

  • pageTitle という名前を付けた TextBlock 要素を、ルートの Grid の子要素として追加します。A TextBlock element named pageTitle as a child element of the root Grid. Text プロパティを Page 1 に変更します。Change the Text property to Page 1.
<TextBlock x:Name="pageTitle" Text="Page 1" />
<HyperlinkButton Content="Click to go to page 2"
                 Click="HyperlinkButton_Click"
                 HorizontalAlignment="Center"/>

Page1.xaml 分離コード ファイルに、Page2.xaml に移動するために追加した HyperlinkButtonClick イベントを処理する次のコードを追加します。In the Page1.xaml code-behind file, add the following code to handle the Click event of the HyperlinkButton you added to navigate to Page2.xaml.

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    this.Frame.Navigate(typeof(Page2));
}
void Page1::HyperlinkButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args)
{
    Frame().Navigate(winrt::xaml_typename<NavApp1::Page2>());
}
void Page1::HyperlinkButton_Click(Platform::Object^ sender, RoutedEventArgs^ e)
{
    this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(Page2::typeid));
}

Page2.xaml に次のコンテンツを追加します。In Page2.xaml, add the following content:

  • pageTitle という名前を付けた TextBlock 要素を、ルートの Grid の子要素として追加します。A TextBlock element named pageTitle as a child element of the root Grid. Text プロパティの値を Page 2 に変更します。Change the value of the Text property to Page 2.
<TextBlock x:Name="pageTitle" Text="Page 2" />
<HyperlinkButton Content="Click to go to page 1" 
                 Click="HyperlinkButton_Click"
                 HorizontalAlignment="Center"/>

Page2.xaml 分離コード ファイルに、Page1.xaml に移動するための HyperlinkButtonClick イベントを処理する次のコードを追加します。In the Page2.xaml code-behind file, add the following code to handle the Click event of the HyperlinkButton to navigate to Page1.xaml.

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    this.Frame.Navigate(typeof(Page1));
}
void Page2::HyperlinkButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args)
{
    Frame().Navigate(winrt::xaml_typename<NavApp1::Page1>());
}
void Page2::HyperlinkButton_Click(Platform::Object^ sender, RoutedEventArgs^ e)
{
    this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(Page1::typeid));
}

注意

C++ プロジェクトの場合は、別のページを参照する各ページのヘッダー ファイルに #include ディレクティブを追加する必要があります。For C++ projects, you must add a #include directive in the header file of each page that references another page. ここで示したページ間のナビゲーションの例では、page1.xaml.h ファイルに #include "Page2.xaml.h" が、page2.xaml.h に #include "Page1.xaml.h" が含まれています。For the inter-page navigation example presented here, page1.xaml.h file contains #include "Page2.xaml.h", in turn, page2.xaml.h contains #include "Page1.xaml.h".

ページが用意できたら、Page1.xaml をアプリの開始時に表示されるように設定する必要があります。Now that we've prepared the pages, we need to make Page1.xaml display when the app starts.

App.xaml 分離コードファイルを開き、OnLaunched ハンドラーを変更します。Open the App.xaml code-behind file and change the OnLaunched handler.

次に、Frame.Navigate の呼び出しに、MainPage ではなく Page1 を追加します。Here, we specify Page1 in the call to Frame.Navigate instead of MainPage.

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    Frame rootFrame = Window.Current.Content as Frame;
 
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == null)
    {
        // Create a Frame to act as the navigation context and navigate to the first page
        rootFrame = new Frame();
        rootFrame.NavigationFailed += OnNavigationFailed;
 
        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
        {
            //TODO: Load state from previously suspended application
        }
 
        // Place the frame in the current Window
        Window.Current.Content = rootFrame;
    }
 
    if (rootFrame.Content == null)
    {
        // When the navigation stack isn't restored navigate to the first page,
        // configuring the new page by passing required information as a navigation
        // parameter
        rootFrame.Navigate(typeof(Page1), e.Arguments);
    }
    // Ensure the current window is active
    Window.Current.Activate();
}
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    Frame rootFrame{ nullptr };
    auto content = Window::Current().Content();
    if (content)
    {
        rootFrame = content.try_as<Frame>();
    }

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        // Create a Frame to act as the navigation context and associate it with
        // a SuspensionManager key
        rootFrame = Frame();

        rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });

        if (e.PreviousExecutionState() == ApplicationExecutionState::Terminated)
        {
            // Restore the saved session state only when appropriate, scheduling the
            // final launch steps after the restore is complete
        }

        if (e.PrelaunchActivated() == false)
        {
            if (rootFrame.Content() == nullptr)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(xaml_typename<NavApp1::Page1>(), box_value(e.Arguments()));
            }
            // Place the frame in the current Window
            Window::Current().Content(rootFrame);
            // Ensure the current window is active
            Window::Current().Activate();
        }
    }
    else
    {
        if (e.PrelaunchActivated() == false)
        {
            if (rootFrame.Content() == nullptr)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(xaml_typename<NavApp1::Page1>(), box_value(e.Arguments()));
            }
            // Ensure the current window is active
            Window::Current().Activate();
        }
    }
}
void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e)
{
    auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content);

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        // Create a Frame to act as the navigation context and associate it with
        // a SuspensionManager key
        rootFrame = ref new Frame();

        rootFrame->NavigationFailed += 
            ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(
                this, &App::OnNavigationFailed);

        if (e->PreviousExecutionState == ApplicationExecutionState::Terminated)
        {
            // TODO: Load state from previously suspended application
        }
        
        // Place the frame in the current Window
        Window::Current->Content = rootFrame;
    }

    if (rootFrame->Content == nullptr)
    {
        // When the navigation stack isn't restored navigate to the first page,
        // configuring the new page by passing required information as a navigation
        // parameter
        rootFrame->Navigate(Windows::UI::Xaml::Interop::TypeName(Page1::typeid), e->Arguments);
    }

    // Ensure the current window is active
    Window::Current->Activate();
}

注意

このコードは、アプリの初期ウィンドウ フレームへのナビゲーションが失敗した場合に、Navigate の戻り値を使ってアプリの例外をスローします。The code here uses the return value of Navigate to throw an app exception if the navigation to the app's initial window frame fails. Navigatetrue を返す場合は、ナビゲーションが行われます。When Navigate returns true, the navigation happens.

次に、アプリをビルドして実行します。Now, build and run the app. "Click to go to page 2" と書かれているリンクをクリックします。Click the link that says "Click to go to page 2". 上部に "Page 2" と書かれた 2 番目のページが読み込まれ、フレームに表示される必要があります。The second page that says "Page 2" at the top should be loaded and displayed in the frame.

Frame クラスと Page クラスについてAbout the Frame and Page classes

アプリにさらに機能を加える前に、追加したページに用意されているアプリ内のナビゲーションについて見てみましょう。Before we add more functionality to our app, let's look at how the pages we added provide navigation within our app.

まず、App.xaml 分離コード ファイルの App.OnLaunched メソッドで、アプリの Frame (rootFrame) が作成されます。First, a Frame called rootFrame is created for the app in the App.OnLaunched method in the App.xaml code-behind file. Frame クラスは、NavigateGoBackGoForward などのさまざまなナビゲーション メソッドと、BackStackForwardStackBackStackDepth などのプロパティをサポートしています。The Frame class supports various navigation methods such as Navigate, GoBack, and GoForward, and properties such as BackStack, ForwardStack, and BackStackDepth.   Navigate メソッドを使って、この Frame にコンテンツが表示されます。The Navigate method is used to display content in this Frame. 既定では、このメソッドは MainPage.xaml を読み込みます。By default, this method loads MainPage.xaml. この例では、Page1Navigate メソッドに渡されるため、メソッドは FramePage1 を読み込みます。In our example, Page1 is passed to the Navigate method, so the method loads Page1 in the Frame.

Page1Page クラスのサブクラスです。Page1 is a subclass of the Page class. Page クラスには、Page が含まれる Frame を取得する読み取り専用の Frame プロパティがあります。The Page class has a read-only Frame property that gets the Frame containing the Page. Page1HyperlinkButtonClick イベント ハンドラーが this.Frame.Navigate(typeof(Page2)) を呼び出すと、Frame に Page2.xaml のコンテンツが表示されます。When the Click event handler of the HyperlinkButton in Page1 calls this.Frame.Navigate(typeof(Page2)), the Frame displays the content of Page2.xaml.

最後に、フレームにページが読み込まれるたびに、そのページが PageStackEntry として、FrameBackStack または ForwardStack に追加され、履歴と前に戻る移動が可能になります。Finally, whenever a page is loaded into the frame, that page is added as a PageStackEntry to the BackStack or ForwardStack of the Frame, allowing for history and backwards navigation.

3.ページ間での情報の受け渡し3. Pass information between pages

このアプリでは、ページ間の移動は行いますが、実際に何かの処理を行うわけではありません。Our app navigates between two pages, but it really doesn't do anything interesting yet. 多くの場合、アプリに複数のページがあれば、ページ間で情報を共有する必要があります。Often, when an app has multiple pages, the pages need to share information. 最初のページから 2 番目のページへ情報を渡してみましょう。Let's pass some information from the first page to the second page.

Page1.xaml で、前に追加した HyperlinkButton を次の StackPanel に置き換えます。In Page1.xaml, replace the HyperlinkButton you added earlier with the following StackPanel.

次に、テキスト文字列を入力するための TextBlock ラベルと TextBox name を追加します。Here, we add a TextBlock label and a TextBox name for entering a text string.

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

Page1.xaml 分離コード ファイルの HyperlinkButton_Click イベント ハンドラーで、name TextBoxText プロパティを参照するパラメーターを Navigate メソッドに追加します。In the HyperlinkButton_Click event handler of the Page1.xaml code-behind file, add a parameter referencing the Text property of the name TextBox to the Navigate method.

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    this.Frame.Navigate(typeof(Page2), name.Text);
}
void Page1::HyperlinkButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args)
{
    Frame().Navigate(winrt::xaml_typename<NavApp1::Page2>(), winrt::box_value(name().Text()));
}
void Page1::HyperlinkButton_Click(Platform::Object^ sender, RoutedEventArgs^ e)
{
    this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(Page2::typeid), name->Text);
}

Page2.xaml で、前に追加した HyperlinkButton を次の StackPanel に置き換えます。In Page2.xaml, replace the HyperlinkButton you added earlier with the following StackPanel.

次に、TextBlock を追加して、Page1 から渡された文字列を表示します。Here, we add a TextBlock for displaying the text string passed from Page1.

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

Page2.xaml 分離コード ファイルで、次のコードを追加して OnNavigatedTo メソッドをオーバーライドします。In the Page2.xaml code-behind file, add the following to override the OnNavigatedTo method:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (e.Parameter is string && !string.IsNullOrWhiteSpace((string)e.Parameter))
    {
        greeting.Text = $"Hi, {e.Parameter.ToString()}";
    }
    else
    {
        greeting.Text = "Hi!";
    }
    base.OnNavigatedTo(e);
}
void Page2::OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e)
{
    auto propertyValue{ e.Parameter().as<Windows::Foundation::IPropertyValue>() };
    if (propertyValue.Type() == Windows::Foundation::PropertyType::String)
    {
        greeting().Text(L"Hi, " + winrt::unbox_value<winrt::hstring>(e.Parameter()));
    }
    else
    {
        greeting().Text(L"Hi!");
    }
    __super::OnNavigatedTo(e);
}
void Page2::OnNavigatedTo(NavigationEventArgs^ e)
{
    if (dynamic_cast<Platform::String^>(e->Parameter) != nullptr)
    {
        greeting->Text = "Hi, " + e->Parameter->ToString();
    }
    else
    {
        greeting->Text = "Hi!";
    }
    ::Windows::UI::Xaml::Controls::Page::OnNavigatedTo(e);
}

アプリを実行し、テキスト ボックスに自分の名前を入力し、 [Click to go to page 2] と書かれているリンクをクリックします。Run the app, type your name in the text box, and then click the link that says Click to go to page 2.

Page1HyperlinkButtonClick イベントで this.Frame.Navigate(typeof(Page2), name.Text) を呼び出すと、name.Text プロパティが Page2 に渡され、イベント データの値がページに表示されるメッセージに使用されます。When the Click event of the HyperlinkButton in Page1 calls this.Frame.Navigate(typeof(Page2), name.Text), the name.Text property is passed to Page2, and the value from the event data is used for the message displayed on the page.

4.ページのキャッシュ4. Cache a page

ページのコンテンツと状態は既定ではキャッシュされないため、情報をキャッシュする場合は、アプリの各ページでキャッシュを有効にする必要があります。Page content and state is not cached by default, so if you'd like to cache information, you must enable it in each page of your app.

この基本的なピア ツー ピアの例では、戻るボタンはありませんが (戻るナビゲーションは「前に戻る移動」で示しました)、Page2 で戻るボタンをクリックした場合、Page1TextBox (およびその他のすべてのフィールド) は既定の状態に設定されます。In our basic peer-to-peer example, there is no back button (we demonstrate back navigation in backwards navigation), but if you did click a back button on Page2, the TextBox (and any other field) on Page1 would be set to its default state. これを回避する方法の 1 つは、NavigationCacheMode プロパティを使って、ページがフレームのページ キャッシュに追加されるように指定することです。One way to work around this is to use the NavigationCacheMode property to specify that a page be added to the frame's page cache.

Page1 のコンストラクターで、NavigationCacheModeEnabled に設定して、フレームのページ キャッシュを超えるまでページのすべてのコンテンツと状態の値を保持することができます。In the constructor of Page1, you can set NavigationCacheMode to Enabled to retains all content and state values for the page until the page cache for the frame is exceeded. CacheSize の制限を無視する場合は、NavigationCacheModeRequired に設定します。これで、フレームにキャッシュできる、ナビゲーション履歴内のページ数を指定します。Set NavigationCacheMode to Required if you want to ignore CacheSize limits, which specify the number of pages in the navigation history that can be cached for the frame. ただし、キャッシュ サイズの制限は、デバイスのメモリの制限に依存しており、重要である可能性があることに注意してください。However, keep in mind that cache size limits might be crucial, depending on the memory limits of a device.

public Page1()
{
    this.InitializeComponent();
    this.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
}
Page1::Page1()
{
    InitializeComponent();
    NavigationCacheMode(Windows::UI::Xaml::Navigation::NavigationCacheMode::Enabled);
}
Page1::Page1()
{
    this->InitializeComponent();
    this->NavigationCacheMode = Windows::UI::Xaml::Navigation::NavigationCacheMode::Enabled;
}