兩個頁面之間的實作瀏覽Implement navigation between two pages

了解如何使用框架和頁面,以便在您的應用程式中能夠進行基本的對等瀏覽。Learn how to use a frame and pages to enable basic peer-to-peer navigation in your app.

重要 APIWindows.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. 在中央窗格中,選擇空白 appIn the center pane, choose Blank App.
  4. 在 [名稱] 方塊中輸入 NavApp1,然後選擇 [確定] 按鈕。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,請結束 app,或從功能表按一下 [停止偵錯]。To stop debugging and return to Visual Studio, exit the app, or click Stop Debugging from the menu.

2.新增基本頁面2. Add basic pages

接下來,將兩個頁面新增到專案。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,新增第二個頁面。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:

  • 名為 pageTitleTextBlock 元素,做為根 Grid 的子元素。A TextBlock element named pageTitle as a child element of the root Grid. Text 屬性變更為 Page 1Change 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 程式碼後置檔案中,新增下列程式碼以處理您先前新增之 HyperlinkButtonClick 事件,以瀏覽至 Page2.xaml。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:

  • 名為 pageTitleTextBlock 元素,做為根 Grid 的子元素。A TextBlock element named pageTitle as a child element of the root Grid. Text 屬性的值變更為 Page 2Change 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 程式碼後置檔案中,新增下列程式碼來處理您先前新增之 HyperlinkButtonClick 事件,以瀏覽至 Page1.xaml。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 的呼叫中指定 Page1,而不是 MainPageHere, 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. Navigate 傳回 true 時,表示已在瀏覽。When Navigate returns true, the navigation happens.

現在,建置並執行 app。Now, build and run the app. 按一下顯示為 [按一下以移至頁面 2] 的連結。Click the link that says "Click to go to 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,稱為 rootFrameFirst, a Frame called rootFrame is created for the app in the App.OnLaunched method in the App.xaml code-behind file. Frame 類別支援不同的瀏覽方法,例如 NavigateGoBack,以及 GoForward,也支援不同的各種屬性,例如 BackStackForwardStack,以及 BackStackDepthThe 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. 在我們的範例中,Page1 會傳遞至 Navigate 方法,此方法就會在 Frame 中載入 Page1In 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 類別具有唯讀的 Frame 屬性,這個屬性會取得包含 PageFrameThe 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 新增到 FrameBackStackForwardStack,以便進行歷程記錄和向後瀏覽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

我們的 app 可以在兩個頁面之間瀏覽,但這只是最基本的功能。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. 讓我們將一些資訊從第一頁傳送到第二頁。Let's pass some information from the first page to the second page.

在 Page1.xaml 中,使用下列 StackPanel 取代您稍早新增的 HyperlinkButtonIn 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 中,使用下列 StackPanel 取代您稍早新增的 HyperlinkButtonIn 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);
}

執行 app,在文字方塊中輸入您的名稱,然後按一下 [按一下以移至頁面 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

預設不會快取頁面內容和狀態,因此,若您想要快取資訊,就必須在 App 的每個頁面中啟用。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 上按一下返回按鈕,Page1 上的 TextBox (以及任何其他欄位) 會設為其預設狀態。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. 解決此問題的方式之一,是使用 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 的建構函式中,您可以將 NavigationCacheMode 設定為已啟用,以保留頁面的所有內容和狀態值,直到超過框架的頁面快取。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 限制,可將 NavigationCacheMode 設為必要,這樣就會指定瀏覽歷史記錄中可針對框架快取的頁數。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;
}