Реализация навигации между двумя страницами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.NavigationImportant 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 > Universal или Visual C++ > Windows > Universal.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, а затем нажмите кнопку ОК.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

Далее добавьте в проект две страницы.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:

  • Добавьте элемент TextBlock с именем pageTitle в качестве дочернего элемента корневого элемента 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 в качестве дочернего элемента корневого элемента Grid и после элемента pageTitle TextBlock.A HyperlinkButton element as a child element of the root Grid and after the pageTitle TextBlock element.
<HyperlinkButton Content="Click to go to page 2"
                 Click="HyperlinkButton_Click"
                 HorizontalAlignment="Center"/>

В файле кода программной части Page1.xaml добавьте следующий код для обработки события Click для HyperlinkButton, которое было добавлено для перехода в файл 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:

  • Добавьте элемент TextBlock с именем pageTitle в качестве дочернего элемента корневого элемента 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 в качестве дочернего элемента корневого элемента Grid и после элемента pageTitle TextBlock.A HyperlinkButton element as a child element of the root Grid and after the pageTitle TextBlock element.
<HyperlinkButton Content="Click to go to page 1" 
                 Click="HyperlinkButton_Click"
                 HorizontalAlignment="Center"/>

В файле кода программной части Page2.xaml добавьте следующий код для обработки события Click для HyperlinkButton, которое было добавлено для перехода в файл 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.

Здесь мы определяем Page1 в вызове Frame.Navigate вместо MainPage.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();
}

Примечание

В этом коде используется возвращаемое значение метода Frame.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.

Теперь выполните сборку и запустите приложение.Now, build and run the app. Щелкните ссылку «Click to go to page 2» (Нажмите, чтобы перейти к странице 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 и PageAbout 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.

Сначала для приложения создается класс Frame с именем rootFrame в методе App.OnLaunched файла кода программной части App.xaml.First, a Frame called rootFrame is created for the app in the App.OnLaunched method in the App.xaml code-behind file. Класс Frame поддерживает различные методы навигации, например Navigate, GoBack и GoForward, а также свойства, такие как BackStack, ForwardStack и BackStackDepth.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. В нашем примере Page1передается методу Navigate, поэтому метод загружает Page1 в Frame.In our example, Page1 is passed to the Navigate method, so the method loads Page1 in the Frame.

Page1 является подклассом класса Page.Page1 is a subclass of the Page class. Класс Page имеет свойство только для чтения Frame, которое получает Frame, содержащий Page.The Page class has a read-only Frame property that gets the Frame containing the Page. Когда обработчик событий Click элемента HyperlinkButton в Page1 вызывает 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 в параметр BackStack или ForwardStack объекта Frame, что позволяет выполнять навигацию по журналу и навигацию в обратном направлении.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. Давайте передадим какую-нибудь информацию с первой страницы на вторую.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>

В обработчике событий HyperlinkButton_Click для файла кода программной части Page1.xaml добавьте параметр, ссылающийся на Textсвойство name TextBox, в методе 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 (Нажмите, чтобы перейти к странице 2).Run the app, type your name in the text box, and then click the link that says Click to go to page 2.

Когда событие Click, принадлежащее HyperlinkButton в Page1, вызывает метод 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, TextBox (и любое другое поле) на Page1 будет установлено в состояние по умолчанию.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 значение Enabled, чтобы сохранить все содержимое и значения состояния для страницы, пока кэш страницы для кадра не превысит свой размер.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. Задайте параметру NavigationCacheMode значение Required, если требуется игнорировать ограничения CacheSize, обозначающие число страниц в журнале навигации, которые можно кэшировать для кадра.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;
}