Compartir vía


Información general sobre la navegación estructurada

Contenido que se puede hospedar en una aplicación del explorador XAML (XBAP), un Frame o una NavigationWindow se compone de páginas que pueden identificarse mediante identificadores de recursos uniformes (URI) del paquete y en las que se puede navegar mediante hipervínculos. La estructura de páginas y las formas en que se puede navegar por ellas, tal como se define mediante hipervínculos, se conoce como topología de navegación. Esta topología se adapta a diversos tipos de aplicaciones, especialmente a aquéllas que navegan por documentos. Con estas aplicaciones, el usuario puede navegar de una página a otra sin necesidad de saber nada sobre la otra.

Sin embargo, otros tipos de aplicaciones tienen páginas que necesitan saber cuándo se ha navegado entre ellas. Por ejemplo, suponga una aplicación de recursos humanos que tiene una página con una lista de todos los empleados de una organización, la página "Lista de empleados". Esta página también podría permitir a los usuarios agregar a un nuevo empleado haciendo clic en un hipervínculo. Al hacer clic en ella, la página navega a una página "Agregar un empleado" para recopilar los datos del nuevo empleado y llevarlos a la página "Lista de empleados" para crear al nuevo empleado y actualizar la lista. Este estilo de navegación es similar a llamar a un método para realizar algún procesamiento y devolver un valor, que se conoce como programación estructurada. Por tanto, este estilo de navegación se conoce como navegación estructurada.

La clase Page no implementa la compatibilidad con la navegación estructurada. En su lugar, la clase PageFunction<T> se deriva de Page y se extiende con las estructuras básicas requeridas para la navegación estructurada. Este tema muestra cómo establecer una navegación estructurada mediante PageFunction<T>.

Navegación estructurada

Cuando una página llama a otra página en una navegación estructurada, se requieren algunos o todos los comportamientos siguientes:

  • La página que llama navega a la página llamada y, opcionalmente, pasa los parámetros requeridos por la página llamada.

  • La página llamada, cuando un usuario ha terminado de usar la página que llama, vuelve específicamente a la página que llama y, opcionalmente:

    • Devuelve información de estado que describe cómo se completó la página que llama (por ejemplo, si un usuario presionó un botón Aceptar o Cancelar).

    • Devuelve los datos recopilados del usuario (por ejemplo, los datos de un nuevo empleado).

  • Cuando se devuelve la página que llama a la página llamada, la página llamada se quita del historial de navegación para aislar cada instancia de una página llamada de otra.

En la ilustración siguiente se muestran estos comportamientos:

Captura de pantalla que muestra el flujo entre la página que llama y la página a la que se llama.

Puede implementar estos comportamientos usando una clase PageFunction<T> como página llamada.

Navegación estructurada con PageFunction

Este tema muestra cómo implementar los mecanismos básicos de navegación estructurada que implica un solo elemento PageFunction<T>. En este ejemplo, una clase Page llama a una clase PageFunction<T> para obtener un valor String del usuario y devolverlo.

Creación de una página que llama

La página que llama a una clase PageFunction<T> puede ser una clase Page o PageFunction<T>. En este ejemplo, es una clase Page, como se muestra en el código siguiente.

<Page 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="StructuredNavigationSample.CallingPage"
    WindowTitle="Calling Page" 
    WindowWidth="250" WindowHeight="150">
</Page>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CallingPage : Page
    {
        public CallingPage()
        {
            InitializeComponent();
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CallingPage
    Inherits Page
    Public Sub New()
        Me.InitializeComponent()
}
End Sub
    }
}
End Class

End Namespace

Creación de una función de página para realizar la llamada

Puesto que la página que llama puede utilizar la página llamada para recopilar y devolver datos del usuario, PageFunction<T> se implementa como una clase genérica cuyo argumento de tipo especifica el tipo del valor que devolverá la página llamada. El código siguiente muestra la implementación inicial de la página llamada, con una clase PageFunction<T> que devuelve un valor String.

<PageFunction
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib" 
    x:Class="StructuredNavigationSample.CalledPageFunction"
    x:TypeArguments="sys:String"
    Title="Page Function" 
    WindowWidth="250" WindowHeight="150">

  <Grid Margin="10">

    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition />
    </Grid.RowDefinitions>

    <!-- Data -->
    <Label Grid.Column="0" Grid.Row="0">DataItem1:</Label>
    <TextBox Grid.Column="1" Grid.Row="0" Name="dataItem1TextBox"></TextBox>

    <!-- Accept/Cancel buttons -->
    <TextBlock Grid.Column="1" Grid.Row="1" HorizontalAlignment="Right">
      <Button Name="okButton" IsDefault="True" MinWidth="50">OK</Button>
      <Button Name="cancelButton" IsCancel="True" MinWidth="50">Cancel</Button>
    </TextBlock>

  </Grid>

</PageFunction>
using System;
using System.Windows;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CalledPageFunction : PageFunction<String>
    {
        public CalledPageFunction()
        {
            InitializeComponent();
        }
Imports System.Windows
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CalledPageFunction
    Inherits PageFunction(Of String)
    Public Sub New()
        Me.InitializeComponent()
    End Sub
    }
}
End Class

End Namespace

La declaración de una clase PageFunction<T> es similar a la declaración de una clase Page con la adición de los argumentos de tipo. Como puede ver en el ejemplo de código, se especifican los argumentos de tipo en el marcado XAML, con el atributo x:TypeArguments, y en el código subyacente, con la sintaxis del argumento de tipo genérico estándar.

No tiene que usar sólo clases de .NET Framework como argumentos de tipo. Una clase PageFunction<T> podría invocarse para recopilar datos específicos de dominio que se resuman como un tipo personalizado. El código siguiente muestra cómo utilizar un tipo personalizado como un argumento de tipo para una clase PageFunction<T>.

namespace SDKSample
{
    public class CustomType
    {
Public Class CustomType
    }
}
End Class
<PageFunction
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SDKSample" 
    x:Class="SDKSample.CustomTypePageFunction"
    x:TypeArguments="local:CustomType">
</PageFunction>
using System.Windows.Navigation;

namespace SDKSample
{
    public partial class CustomTypePageFunction : PageFunction<CustomType>
    {
Partial Public Class CustomTypePageFunction
    Inherits System.Windows.Navigation.PageFunction(Of CustomType)
    }
}
End Class

Los argumentos de tipo para la clase PageFunction<T> proporciona la base para la comunicación entre una página que llama y la página llamada, que se describe en las siguientes secciones.

Como verá, el tipo que se identifica con la declaración de una clase PageFunction<T> desempeña un rol importante en la devolución de datos de una clase PageFunction<T> a la página que llama.

Llamada a una clase PageFunction y transmisión de parámetros

Para llamar a una página, la página que llama debe crear una instancia de la página llamada y navegar hasta ella mediante el método Navigate. Esto permite que la página que llama pase los datos iniciales a la página llamada, como valores predeterminados para los datos recopilados por la página llamada.

El código siguiente muestra la página llamada con un constructor que no es sin parámetros para aceptar parámetros de la página que llama.

using System;
using System.Windows;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CalledPageFunction : PageFunction<String>
    {
Imports System.Windows
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CalledPageFunction
    Inherits PageFunction(Of String)
public CalledPageFunction(string initialDataItem1Value)
{
    InitializeComponent();

Public Sub New(ByVal initialDataItem1Value As String)
    Me.InitializeComponent()
    // Set initial value
    this.dataItem1TextBox.Text = initialDataItem1Value;
}
    ' Set initial value
    Me.dataItem1TextBox.Text = initialDataItem1Value
End Sub
    }
}
End Class

End Namespace

El código siguiente muestra cómo la página que llama controla el evento Click de la clase Hyperlink para crear una instancia de la página llamada y pasarle un valor de cadena inicial.

<Hyperlink Name="pageFunctionHyperlink">Call Page Function</Hyperlink>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CallingPage : Page
    {
        public CallingPage()
        {
            InitializeComponent();
            this.pageFunctionHyperlink.Click += new RoutedEventHandler(pageFunctionHyperlink_Click);
        }
        void pageFunctionHyperlink_Click(object sender, RoutedEventArgs e)
        {

            // Instantiate and navigate to page function
            CalledPageFunction CalledPageFunction = new CalledPageFunction("Initial Data Item Value");
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CallingPage
    Inherits Page
    Public Sub New()
        Me.InitializeComponent()
        AddHandler Me.pageFunctionHyperlink.Click, New RoutedEventHandler(AddressOf Me.pageFunctionHyperlink_Click)
    End Sub
    Private Sub pageFunctionHyperlink_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
}
End Sub
    }
}
End Class

End Namespace

No es necesario pasar parámetros a la página llamada. En su lugar, podría hacer lo siguiente:

Pero, como verá en breve, aún necesitará utilizar código para crear una instancia y navegar a la página llamada para recopilar los datos devueltos por la página llamada. Por esta razón, debe mantener la clase PageFunction<T> activa; de lo contrario, la próxima vez que navegue a PageFunction<T>, WPF creará una instancia de PageFunction<T> mediante el constructor sin parámetros.

Sin embargo, antes de la página llamada pueda volver, debe devolver los datos para que los pueda recuperar la página que llama.

Devolución de los resultados y los datos de la tarea de una tarea a una página que llama

Una vez que el usuario ha terminado de utilizar la página llamada, en este ejemplo indicado al presionar los botones Aceptar o Cancelar, la página llamada debe volver. Puesto que la página que llama utilizó la página llamada para recopilar datos del usuario, la página que llama requiere dos tipos de información:

  1. Si el usuario canceló la página llamada (presionando el botón Aceptar o el botón Cancelar en este ejemplo). Esto permite que la página que llama determine si se procesan los datos que recopiló del usuario.

  2. Los datos proporcionados por el usuario.

Para devolver información, PageFunction<T> implementa el método OnReturn. El siguiente código muestra cómo llamarlo.

using System;
using System.Windows;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CalledPageFunction : PageFunction<String>
    {
Imports System.Windows
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CalledPageFunction
    Inherits PageFunction(Of String)
        void okButton_Click(object sender, RoutedEventArgs e)
        {
            // Accept when Ok button is clicked
            OnReturn(new ReturnEventArgs<string>(this.dataItem1TextBox.Text));
        }

        void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            // Cancel
            OnReturn(null);
        }
    }
}
    Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        ' Accept when Ok button is clicked
        Me.OnReturn(New ReturnEventArgs(Of String)(Me.dataItem1TextBox.Text))
    End Sub

    Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        ' Cancel
        Me.OnReturn(Nothing)
    End Sub
End Class

End Namespace

En este ejemplo, si un usuario presiona el botón Cancelar, se devuelve un valor de null a la página que llama. En cambio, si se presiona el botón Aceptar, se devuelve el valor de cadena proporcionado por el usuario. OnReturn es un método protected virtual al que se llama para devolver los datos a la página que llama. Los datos deben empaquetarse en una instancia del tipo ReturnEventArgs<T> genérico, cuyo argumento de tipo especifica el tipo de valor que devuelve Result. De este modo, cuando se declara una clase PageFunction<T> con un argumento de tipo determinado, se indica que una clase PageFunction<T> devolverá una instancia del tipo especificado por el argumento de tipo. En este ejemplo, el argumento de tipo y, por consiguiente, el valor devuelto es de tipo String.

Cuando se llama a OnReturn, la página que llama necesita recibir de alguna manera el valor devuelto de la clase PageFunction<T>. Por este motivo, PageFunction<T> implementa el evento Return para que las páginas que llaman lo controlen. Cuando se llama a OnReturn, se genera Return, por lo que la página que llama puede registrarse en Return para recibir la notificación.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CallingPage : Page
    {
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CallingPage
    Inherits Page
        void pageFunctionHyperlink_Click(object sender, RoutedEventArgs e)
        {

            // Instantiate and navigate to page function
            CalledPageFunction CalledPageFunction = new CalledPageFunction("Initial Data Item Value");
            CalledPageFunction.Return += pageFunction_Return;
            this.NavigationService.Navigate(CalledPageFunction);
        }
        void pageFunction_Return(object sender, ReturnEventArgs<string> e)
        {
            this.pageFunctionResultsTextBlock.Visibility = Visibility.Visible;

            // Display result
            this.pageFunctionResultsTextBlock.Text = (e != null ? "Accepted" : "Canceled");

            // If page function returned, display result and data
            if (e != null)
            {
                this.pageFunctionResultsTextBlock.Text += "\n" + e.Result;
            }
        }
    }
}
    Private Sub pageFunctionHyperlink_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        ' Instantiate and navigate to page function
        Dim calledPageFunction As New CalledPageFunction("Initial Data Item Value")
        AddHandler calledPageFunction.Return, New ReturnEventHandler(Of String)(AddressOf Me.calledPageFunction_Return)
        MyBase.NavigationService.Navigate(calledPageFunction)
    End Sub
    Private Sub calledPageFunction_Return(ByVal sender As Object, ByVal e As ReturnEventArgs(Of String))

        Me.pageFunctionResultsTextBlock.Visibility = Windows.Visibility.Visible

        ' Display result
        Me.pageFunctionResultsTextBlock.Text = IIf((Not e Is Nothing), "Accepted", "Canceled")

        ' If page function returned, display result and data
        If (Not e Is Nothing) Then
            Me.pageFunctionResultsTextBlock.Text = (Me.pageFunctionResultsTextBlock.Text & ChrW(10) & e.Result)
        End If

    End Sub
End Class

End Namespace

Eliminación de páginas de tarea cuando se completa una tarea

Cuando vuelve una página llamada y el usuario no la había cancelado, la página que llama procesará los datos proporcionados por el usuario y los devueltos desde la página llamada. La adquisición de datos de esta manera suele ser una actividad aislada; cuando la página llamada vuelve, la página que llama debe crear y navegar a una nueva página que llama para capturar más datos.

Sin embargo, a menos que una página llamada se quite del diario, un usuario podrá volver a una instancia anterior de la página que llama. Si se conserva o no una clase PageFunction<T> en el diario está determinado por la propiedad RemoveFromJournal. De forma predeterminada, una función de página se quita automáticamente cuando se llama a OnReturn porque RemoveFromJournal está establecido en true. Para mantener una función de página en el historial de navegación después de llamar a OnReturn, establezca RemoveFromJournal en false.

Otros tipos de navegación estructurada

En este tema se muestra el uso más básico de una clase PageFunction<T> para permitir la navegación estructurada mediante llamada/devolución. Esta base proporciona la capacidad de crear tipos más complejos de navegación estructurada.

Por ejemplo, a veces son necesarias varias páginas en una página que llama para recopilar suficientes datos de un usuario o para realizar una tarea. El uso de varias páginas se conoce como un "asistente".

En otros casos, las aplicaciones pueden tener topologías de navegación complejas que dependen de la navegación estructurada para funcionar eficazmente. Para más información, consulte Información general sobre topologías de navegación.

Vea también