Lenguaje

Tutorial: Implementación de la navegación entre dos páginas

Aprende a usar un marco y páginas para habilitar la navegación punto a punto básica en una aplicación.

navegación punto a punto

Casi todas las aplicaciones requieren navegación entre páginas. Incluso una aplicación sencilla con una sola página de contenido normalmente tendrá una página de configuración que requiere navegación. En este artículo, se describen los conceptos básicos de agregar un XAML Page a la aplicación y usar un Frame para navegar entre páginas.

1. Crear una aplicación en blanco

Para crear una aplicación en blanco en Visual Studio:

  1. Para configurar el equipo de desarrollo, consulte Empezar a desarrollar aplicaciones de Windows.
  2. En la ventana de inicio de Microsoft Visual Studio, seleccione Crear un nuevo project, O bien, en el menú Visual Studio, elija File>New>Project.
  3. En el cuadro de diálogo Crear un nuevo proyecto, en los filtros desplegables, seleccione C# o C++, Windows y WinUI>, respectivamente.
  4. Seleccione la plantilla de proyecto WinUI Blank App (Empaquetado) y haga clic en Siguiente. Esa plantilla crea una aplicación de escritorio con una interfaz de usuario basada en WinUI.
  5. En el cuadro nombre del proyecto, escriba BasicNavigation y haga clic en Crear.
  6. Para ejecutar el programa, elija Depurar>Iniciar depuración en el menú o presione F5. Compile y ejecute la solución en el equipo de desarrollo para confirmar que la aplicación se ejecuta sin errores. Se muestra una página en blanco.
  7. Para detener la depuración y volver a Visual Studio, salga de la aplicación o haga clic en Stop Debugging en el menú.
  8. Elimina cualquier código de ejemplo que se incluya en la plantilla de los archivos de código subyacente MainWindow.xaml y MainWindow.

2. Usar un marco para navegar entre páginas

Cuando la aplicación tiene varias páginas, usa un marco para navegar entre ellas. La Frame clase admite varios métodos de navegación, como Navigate, GoBack y GoForward, y propiedades como BackStack, ForwardStack y BackStackDepth.

Al crear un nuevo proyecto de SDK de Aplicaciones para Windows en Visual Studio, la plantilla de proyecto crea una clase (de tipo Microsoft.UI.Xaml.Window). Sin embargo, no crea un marco ni una página y no proporciona ningún código de navegación.

Para habilitar la navegación entre páginas, agregue un Frame como elemento raíz de MainWindow. Puede hacerlo en la sobrescritura del método Application.OnLaunched del archivo App.xaml de código subyacente. Abra el App archivo de código subyacente, actualice la OnLaunched sobrescritura y controle el evento NavigationFailed de la manera que se muestra a continuación.

// 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>();
    Microsoft::UI::Xaml::Controls::Frame rootFrame = Microsoft::UI::Xaml::Controls::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);
}

Nota:

En el caso de las aplicaciones con navegación más compleja, normalmente se usa navigationView como raíz de MainWindow y se coloca Frame como el contenido de la vista de navegación. Para obtener más información, consulta Vista de navegación.

El método Navigate se usa para mostrar contenido en este Frame. Aquí, MainPage.xaml se pasa al método Navigate, por lo que el método carga MainPage en Frame.

Si se produce un error en la navegación a la ventana inicial de la aplicación, se produce un NavigationFailed evento y este código produce una excepción en el controlador de eventos.

3. Agregar páginas básicas

La plantilla Blank App no crea varias páginas de aplicación automáticamente. Para poder navegar entre páginas, debe agregar algunas páginas a la aplicación.

Para agregar un nuevo elemento a la aplicación:

  1. En Explorador de soluciones, haga clic con el botón derecho en el nodo BasicNavigation project para abrir el menú contextual.
  2. Elija Agregar>nuevo elemento en el menú contextual.
  3. En el cuadro de diálogo Agregar nuevo elemento , seleccione el nodo WinUI en el panel izquierdo y elija Página en blanco en el panel central.
  4. En el cuadro Nombre , escriba MainPage y presione el botón Agregar .
  5. Repita los pasos del 1 al 4 para agregar la segunda página, pero en el cuadro Nombre , escriba Page2.

Tip

Use la plantilla Elemento página en blanco para agregar páginas. Esta plantilla establece la acción de compilación del archivo XAML en Page, que genera la clase parcial de la página y su InitializeComponent método para que el archivo XAML se conecte a su código subyacente. Si agrega una página de otra forma y el compilador indica que InitializeComponent no está definido, seleccione el archivo XAML en Explorador de soluciones y confirme que su propiedad Acción de compilación está configurada como Page.

Ahora, estos archivos deben aparecer como parte de su BasicNavigation proyecto.

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

Importante

Para los proyectos de C++, debe agregar una #include directiva en el archivo de encabezado de cada página que haga referencia a otra página. Para el ejemplo de navegación entre páginas que se presenta aquí, el archivo MainPage.xaml.h contiene #include "Page2.xaml.h", a su vez, Page2.xaml.h contiene #include "MainPage.xaml.h".

Las plantillas de página de C++ también incluyen un ejemplo Button y código de controlador de clics que tendrás que quitar de los archivos XAML y de código subyacente de la página.

Agregar contenido a las páginas

En MainPage.xaml, reemplace el contenido de la página existente por el siguiente contenido:

<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>

Este XAML agrega:

  • Un elemento TextBlock denominado pageTitle con su propiedad Text establecida en Main Page, como elemento secundario del Grid raíz.
  • Elemento HyperlinkButton que se usa para navegar a la página siguiente como elemento secundario del Grid raíz.

En el MainPage archivo de código subyacente, agregue el código siguiente para controlar el Click evento de HyperlinkButton que agregó para habilitar la navegación a 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/Microsoft.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>());
}

MainPage es una subclase de la clase Page . La clase Page tiene una propiedad Frame de solo lectura que obtiene el Frame que contiene el Page. Cuando el Click controlador de eventos de HyperlinkButton en MainPage llama a Frame.Navigate(typeof(Page2)), Frame muestra el contenido de Page2.xaml.

Cada vez que una página se carga en el marco, dicha página se agrega como PageStackEntry a la BackStack o la ForwardStack del Frame, lo que permite el historial y navegación hacia atrás.

Ahora, haga lo mismo en Page2.xaml. Reemplace el contenido de la página existente por el siguiente contenido:

<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>

En el archivo Page2 de código tras, añade el siguiente código para administrar el evento Click del HyperlinkButton y navegar a 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>());
}

Compile y ejecute la aplicación. Haga clic en el vínculo que dice "Haga clic para ir a la página 2". La segunda página que dice "Página 2" en la parte superior debe cargarse y mostrarse en el marco. Ahora haz clic en el enlace de la página 2 para volver a la página principal.

4. Pasar información entre páginas

La aplicación ahora navega entre dos páginas, pero realmente no hace nada interesante aún. A menudo, cuando una aplicación tiene varias páginas, las páginas necesitan compartir información. Ahora vas a pasar información de la primera página a la segunda.

En MainPage.xaml, reemplace el HyperlinkButton elemento que agregó anteriormente por el siguiente StackPanel. Esto agrega una etiqueta TextBlock y un TextBoxname para escribir una cadena de texto.

<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>

Ahora utilizarás la segunda sobrecarga del método Navigate y pasarás el texto del cuadro de texto como segundo parámetro. Esta es la firma de esta sobrecarga de Navigate:

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

En el controlador de eventos HyperlinkButton_Click del archivo de código subyacente MainPage, añade un segundo parámetro al método Navigate que haga referencia a la propiedad Text del cuadro de texto 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()));
}

En Page2.xaml, reemplace el HyperlinkButton elemento que agregó anteriormente por el siguiente StackPanel. Esto agrega un TextBlock para mostrar la cadena de texto pasada desde MainPage.

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

En el Page2 archivo de código subyacente, agregue el código siguiente para invalidar el OnNavigatedTo método :

// 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);
}

Ejecute la aplicación, escriba el nombre en el cuadro de texto y, a continuación, haga clic en el vínculo que indica Click to go to page 2.

Cuando el evento Click de HyperlinkButton en MainPage llama a Frame.Navigate(typeof(Page2), name.Text), la propiedad name.Text se pasa a Page2, y el valor de los datos del evento se utiliza para el mensaje que se muestra en la página.

5. Almacenar en caché una página

El contenido y el estado de la página no se almacenan en caché de manera predeterminada, por lo que si quieres almacenar información en la caché, debes habilitar esta opción en todas las páginas de la aplicación.

En nuestro ejemplo básico de peer-to-peer, al hacer clic en el enlace Click to go to page 1 de Page2, el campo TextBox (y cualquier otro campo) de MainPage se establece en su estado predeterminado. Una manera de solucionar esto es usar la propiedad NavigationCacheMode para especificar que se agregue una página a la memoria caché de páginas del marco.

De forma predeterminada, se crea una nueva instancia de página con sus valores predeterminados cada vez que se produce la navegación. En MainPage.xaml, establezca NavigationCacheMode a Enabled (en la etiqueta de apertura Page) para almacenar en caché la página y conservar todos los valores de contenido y estado de la página hasta que se supere la memoria caché de la página del marco. Establece NavigationCacheMode en Required si quieres ignorar los límites de CacheSize, que especifican el número de páginas en el historial de navegación que pueden almacenarse en la caché para el marco. Sin embargo, no olvides que los límites de tamaño de la caché pueden ser esenciales en función de los límites de memoria de un dispositivo.

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

Ahora, al hacer clic de nuevo en la página principal, el nombre que escribió en el cuadro de texto sigue estando ahí.

6. Personalizar animaciones de transición de página

De forma predeterminada, cada página se anima en el marco cuando se produce la navegación. La animación predeterminada es una animación de "entrada" que hace que la página se deslice hacia arriba desde la parte inferior de la ventana. Sin embargo, puedes elegir diferentes opciones de animación que mejor se adapten a la navegación de tu aplicación. Por ejemplo, puedes utilizar una animación de profundización para dar la sensación de que el usuario se adentra más en tu aplicación, o una animación de deslizamiento horizontal para dar la sensación de que dos páginas son equivalentes. Para obtener más información, consulta Transiciones de página.

Estas animaciones se representan mediante sub clases de NavigationTransitionInfo. Para especificar la animación que se utilizará en una transición de página, debes utilizar la tercera sobrecarga del método Navigate y pasar una subclase de NavigationTransitionInfo como tercer parámetro (infoOverride). Esta es la firma de esta sobrecarga de Navigate:

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

En el HyperlinkButton_Click controlador de eventos del archivo de código subyacente MainPage, agregue un tercer parámetro al método Navigate que asigna al parámetro infoOverride un SlideNavigationTransitionInfo con su propiedad Effect establecida en FromRight.

// 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);
}

En el controlador de eventos HyperlinkButton_Click del archivo de código subyacente Page2, establece el parámetro infoOverride en un objeto SlideNavigationTransitionInfo con su propiedad Effect establecida en 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::Page2::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);
}

Ahora, al navegar entre páginas, las páginas se deslizan a la izquierda y a la derecha, lo que proporciona una sensación más natural para esta transición y refuerza la conexión entre las páginas.