Compartir a través de


Información general sobre navegación

Windows Presentation Foundation (WPF) admite navegación de explorador que se puede utilizar en dos tipos de aplicaciones: aplicaciones independientes y XAML browser applications (XBAPs). Para empaquetar el contenido para la navegación, WPF proporciona la clase Page. Se puede navegar de un objeto Page a otro mediante declaración, utilizando un objeto Hyperlink, o mediante programación, utilizando el objeto NavigationService. WPF utiliza el diario para recordar las páginas desde y a las que se ha navegado.

Page, Hyperlink, NavigationService y el diario son los componentes esenciales de la compatibilidad de navegación proporcionada por WPF. En esta introducción se describen detalladamente estas características antes de abordar el tema de la compatibilidad de navegación avanzada, que incluye la navegación a archivos Extensible Application Markup Language (XAML) independientes, a archivos HTML y a objetos.

NotaNota

En este tema, el término "explorador" hace referencia únicamente a los exploradores que pueden hospedar aplicaciones WPF, que actualmente son Microsoft Internet Explorer y Firefox.Cuando sólo se admiten determinadas características de WPF en un explorador concreto, se hace referencia a la versión del explorador.

Este tema contiene las secciones siguientes.

  • Navegación en aplicaciones de WPF
  • La clase NavigationWindow
  • La clase Frame
  • Hosts de navegación
  • Navegar a contenido distinto de páginas XAML
  • Seguridad
  • Temas relacionados

En este tema se proporciona información general sobre las funciones de navegación principales en WPF. Estas funciones están disponibles para las aplicaciones independientes y XBAPs, aunque en este tema se describen en el contexto de XBAP.

NotaNota

En este tema no se explica cómo generar e implementar XBAPs.Para obtener más información sobre XBAPs, vea Información general sobre las aplicaciones de explorador XAML de WPF.

En esta sección se explican y muestran los aspectos siguientes de la navegación:

  • Implementar una página

  • Configurar una página principal

  • Configurar el título, ancho y alto de la ventana host

  • Navegación por hipervínculos

  • Navegación por fragmentos

  • Servicio de navegación

  • Navegación mediante programación con el servicio de navegación

  • Duración de la navegación

  • Recordar la navegación con el diario

  • Duración y diario de páginas

  • Conservar el estado del contenido con el historial de navegación

  • Cookies

  • Navegación estructurada

Implementar una página

En WPF, puede navegar a varios tipos de contenido, como objetos, objetos personalizados, valores de enumeración y controles de usuario de .NET Framework, archivos XAML y archivos HTML. Sin embargo, descubrirá que la forma más común y útil de empaquetar contenido consiste en utilizar Page. Además, Page implementa características específicas de la navegación para mejorar la apariencia y simplificar el desarrollo.

Con Page, puede implementar mediante declaración una página navegable de contenido XAML utilizando marcado como el siguiente.

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" />

Un objeto Page que se implementa en marcado XAML tiene Page como su elemento raíz y requiere la declaración de espacio de nombres WPFXML. El elemento Page incluye el contenido al que desea navegar y que desea mostrar. El contenido se agrega estableciendo el elemento de propiedad Page.Content, como se muestra en el marcado siguiente.

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Page.Content>
    <!-- Page Content -->
    Hello, Page!
  </Page.Content>
</Page>

¡Page.Content sólo puede contener un elemento secundario; en el ejemplo anterior, el contenido es una sola cadena, "Hello, Page!". En la práctica, utilizará normalmente un control de diseño como elemento secundario (vea Sistema de diseño) para incluir y crear el contenido.

Se considera que los elementos secundarios de un elemento Page son el contenido de Page y, por tanto, no necesita utilizar la declaración Page.Content explícita. El siguiente marcado es el equivalente declarativo del ejemplo anterior.

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <!-- Page Content -->
  Hello, Page!
</Page>

En este caso, Page.Content se establece automáticamente con los elementos secundarios del elemento Page. Para obtener más información, vea Modelo de contenido de WPF.

Un objeto Page de sólo marcado sirve para mostrar contenido. Sin embargo, un objeto Page puede mostrar también controles que permitan a los usuarios interactuar con la página, y puede responder a la interacción del usuario controlando eventos y la lógica de la aplicación de llamada. Un objeto Page interactivo se implementa mediante una combinación de marcado y código subyacente, como se muestra en el ejemplo siguiente.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.HomePage">
  Hello, from the XBAP HomePage!
</Page>

Imports System.Windows.Controls ' Page

Namespace SDKSample
    Partial Public Class HomePage
        Inherits Page
        Public Sub New()
            InitializeComponent()
        End Sub
    End Class
End Namespace
using System.Windows.Controls; // Page

namespace SDKSample
{
    public partial class HomePage : Page
    {
        public HomePage()
        {
            InitializeComponent();
        }
    }
}

Para permitir que un archivo de marcado y un archivo de código subyacente funcionen conjuntamente, se requiere la siguiente configuración:

  • En el marcado, el elemento Page debe incluir el atributo x:Class. Al generar la aplicación, la existencia de x:Class en el archivo de marcado permite que Microsoft build engine (MSBuild) cree una clase partial que se derive de Pagey tenga el nombre especificado por el atributo x:Class. Para ello, es necesario agregar una declaración de espacio de nombres XML para el esquema XAML (xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"). La clase partial generada implementa InitializeComponent, al que se llama para registrar los eventos y establecer las propiedades que se implementan en el marcado.

  • En el archivo de código subyacente, la clase debe ser una clase partial con el mismo nombre que el que especificó el atributo x:Class en el marcado, y debe derivarse de Page. Esto permite que el archivo de código subyacente se asocie a la clase partial que se genera para el archivo de marcado cuando se crea la aplicación (vea Compilar una aplicación de WPF (WPF)).

  • En el archivo de código subyacente, la clase Page debe implementar un constructor que llame al método InitializeComponent. La clase InitializeComponent se implementa mediante la clase partial generada del archivo de marcado para registrar eventos y establecer las propiedades que se definen en el marcado.

NotaNota

Al agregar un nuevo objeto Page a su proyecto con Microsoft Visual Studio, se implementa Page utilizando el marcado y el código subyacente; este control incluye la configuración necesaria para crear la asociación entre los archivos de código subyacente y de marcado tal como aquí se describe.

Cuando ya tenga un objeto Page, podrá navegar a él. Para especificar el primer objeto Page al que navega una aplicación, necesita configurar el objeto Page de inicio.

Configurar una página principal

Las XBAPs exigen que una determinada cantidad de infraestructura de la aplicación esté hospedada en un explorador. En WPF, la clase Application forma parte de una definición de aplicación que establece la infraestructura de aplicación necesaria (vea Información general sobre la administración de aplicaciones).

Una definición de aplicación se suele implementar mediante marcado y código subyacente, con el archivo de marcado configurado como un elemento ApplicationDefinition de MSBuild. A continuación se ofrece una definición de aplicación para XBAP.

<Application
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App" />

Imports System.Windows ' Application

Namespace SDKSample
    Partial Public Class App
        Inherits Application
    End Class
End Namespace
using System.Windows; // Application

namespace SDKSample
{
    public partial class App : Application { }
}

Una XBAP puede utilizar su definición de aplicación para especificar un objeto Page de inicio, que es el objeto Page que se carga automáticamente cuando se inicia la XBAP. Para ello, se establece la propiedad StartupUri con el uniform resource identifier (URI) del objeto Page deseado.

NotaNota

Normalmente, el objeto Page se compila o se implementa con una aplicación.En tales casos, el URI que identifica un objeto Pagees un pack URI, que es un URI compatible con el esquema pack.El paquete URIs se describe más detalladamente en Empaquetar URI en WPF. También puede navegar al contenido mediante el esquema http, que se describe a continuación.

Puede establecer StartupUri mediante declaración en el marcado, como se muestra en el ejemplo siguiente.

<Application
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App"
    StartupUri="PageWithHyperlink.xaml" />

En este ejemplo, el atributo StartupUri se establece con un pack URI relativo que identifica HomePage.xaml. Cuando se inicia XBAP, se navega automáticamente a HomePage.xaml y se muestra. Esto se muestra en la ilustración siguiente, en la que se inicia una XBAP desde un servidor web.

Página XBAP

NotaNota

Para obtener más información relacionada con el desarrollo y la implementación de XBAPs, vea Información general sobre las aplicaciones de explorador XAML de WPF y Implementar una aplicación de WPF.

Configurar el título, ancho y alto de la ventana host

Es posible que haya advertido que en la figura anterior el título del explorador y del panel de fichas es el URI de la XBAP. Además de largo, el título no tiene un aspecto atractivo ni aporta información. Por este motivo, Page proporciona un modo de cambiar el título estableciendo la propiedad WindowTitle. Asimismo, puede configurar el ancho y alto de la ventana del explorador estableciendo WindowWidth y WindowHeight, respectivamente.

Puede establecer WindowTitle, WindowWidth y WindowHeight mediante declaración en el marcado, como se muestra en el ejemplo siguiente.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.HomePage"
    WindowTitle="Page Title"
    WindowWidth="500"
    WindowHeight="200">
  Hello, from the XBAP HomePage!
</Page>

El resultado se muestra en la ilustración siguiente.

Título, alto y ancho de ventana

Una XBAP típica comprende varias páginas. La manera más simple de navegar de una página a otra es utilizar un objeto Hyperlink. Puede agregar mediante declaración un objeto Hyperlinka Page utilizando el elemento Hyperlink, que se muestra en el marcado siguiente.

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  WindowTitle="Page With Hyperlink"
  WindowWidth="250"
  WindowHeight="250">


...


<Hyperlink NavigateUri="UriOfPageToNavigateTo.xaml">
  Navigate to Another Page
</Hyperlink>


...


</Page>

Un elemento Hyperlink requiere lo siguiente:

  • El pack URI del objeto Page al que se va navegar, especificado por el atributo NavigateUri.

  • El contenido en el que un usuario puede hacer clic para iniciar la navegación, como texto e imágenes (para saber qué contenido se puede incluir en el elemento Hyperlink, vea Hyperlink).

En la ilustración siguiente se muestra una XBAP con Page que tiene un objeto Hyperlink.

Página con hipervínculo

Como era de prever, al hacer clic en Hyperlink XBAP se desplaza al control Page, identificado por el atributo NavigateUri. Además, la XBAP agrega una entrada para el objeto Page anterior a la lista Páginas recientes de Internet Explorer. Esto se muestra en la ilustración siguiente.

Botones Atrás y Adelante

Además de permitir la navegación de un objeto Page a otro, Hyperlink admite la navegación por fragmentos.

La navegación por fragmentos es la navegación a un fragmento de contenido en el objeto Page u otro objeto Page. En WPF, un fragmento de contenido es el contenido incluido en un elemento con nombre. Un elemento con nombre es un elemento que tiene establecido su atributo Name. En el marcado siguiente se muestra un elemento TextBlock con nombre que contiene un fragmento de contenido.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    WindowTitle="Page With Fragments" >


...


<!-- Content Fragment called "Fragment1" -->
<TextBlock Name="Fragment1">
  Ea vel dignissim te aliquam facilisis ...
</TextBlock>


...


</Page>

Para que un objeto Hyperlink navegue a un fragmento de contenido, el atributo NavigateUri debe incluir lo siguiente:

  • El URI del objeto Page con el fragmento de contenido al que se va a navegar.

  • Un carácter "#".

  • El nombre del elemento del objeto Page que contiene el fragmento de contenido.

Un URI de fragmento tiene el siguiente formato.

PageURI#ElementName

A continuación, se muestra un ejemplo de un objeto Hyperlink configurado para navegar a un fragmento de contenido.

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  WindowTitle="Page That Navigates To Fragment" >


...


<Hyperlink NavigateUri="PageWithFragments.xaml#Fragment1">
  Navigate To pack Fragment
</Hyperlink>


...


</Page>
NotaNota

En esta sección se describe la implementación de navegación por fragmentos predeterminada en WPF.WPF permite también implementar un esquema de navegación por fragmentos propio, que requiere parcialmente que se controle el evento NavigationService.FragmentNavigation.

Nota importanteImportante

Sólo puede navegar a fragmentos en páginas XAML independientes (archivos de XAML de sólo marcado con Page como elemento raíz) si las páginas se pueden examinar mediante HTTP.

Sin embargo, una página XAML independiente puede navegar a sus propios fragmentos.

Servicio de navegación

Aunque Hyperlink permite que un usuario inicie la navegación en un objeto Page determinado, la clase NavigationService es la encargada de buscar y descargar la página. Básicamente, NavigationService proporciona la capacidad de procesar una solicitud de navegación en nombre de código cliente, como Hyperlink. Además, NavigationService implementa la compatibilidad de nivel superior para realizar el seguimiento y dirigir las solicitudes de navegación.

Al hacer clic en Hyperlink, WPF llama a NavigationService.Navigate para buscar y descargar el objeto Page en el pack URI especificado. El objeto Page descargado se convierte en un árbol de objetos cuyo objeto raíz es una instancia del objeto Page descargado. En la propiedad NavigationService.Content se almacena una referencia al objeto Page raíz. El pack URI del contenido al que se navegó se almacena en la propiedad NavigationService.Source, mientras que NavigationService.CurrentSource almacena el pack URI de la última página a la que se navegó.

NotaNota

Es posible que una aplicación de WPF tenga más de un objeto NavigationService actualmente activo.Para obtener más información, vea Hosts de navegación más adelante en este tema.

No necesita conocer NavigationService si la navegación se implementa mediante declaración en el marcado utilizando Hyperlink, porque Hyperlink utiliza NavigationService en su nombre. Esto significa que, siempre y cuando el elemento primario directo o indirecto de Hyperlink sea un host de navegación (vea Hosts de navegación), Hyperlink podrá buscar y utilizar el servicio de navegación del host de desplazamiento para procesar una solicitud de navegación.

Sin embargo, hay situaciones en las que tendrá que usar NavigationService directamente, como las siguientes:

  • Cuando tenga que crear una instancia de Page utilizando un constructor no predeterminado.

  • Cuando tenga que establecer propiedades en el objeto Page antes de navegar a él.

  • Cuando el objeto Page al que hay que navegar sólo pueda determinarse en tiempo de ejecución.

En estas situaciones, deberá escribir código para iniciar la navegación mediante programación llamando al método Navigate del objeto NavigationService. Para ello, es necesario obtener una referencia a un objeto NavigationService.

Obtener una referencia a NavigationService

Por los motivos explicados en la sección Hosts de navegación, una aplicación de WPF puede tener más de un objeto NavigationService. Esto significa que el código necesita un modo de encontrar NavigationService, que normalmente es el objeto NavigationService que navegó al control Page actual. Puede obtener una referencia a NavigationService llamando al método static NavigationService.GetNavigationService. Para obtener el objeto NavigationService que navegó a un objeto Page determinado, tendrá que pasar una referencia al objeto Page como argumento del método GetNavigationService. En el ejemplo de código siguiente se muestra cómo obtener el NavigationService para el objeto Page actual.

' Get a reference to the NavigationService that navigated to this Page
Dim ns As NavigationService = NavigationService.GetNavigationService(Me)
using System.Windows.Navigation; // NavigationServce


...


// Get a reference to the NavigationService that navigated to this Page
NavigationService ns = NavigationService.GetNavigationService(this);

Para simplificar la búsqueda de un NavigationService para un objeto Page, Page implementa la propiedad NavigationService. Esto se muestra en el ejemplo siguiente.

' Get a reference to the NavigationService that navigated to this Page
Dim ns As NavigationService = Me.NavigationService
using System.Windows.Navigation; // NavigationServce


...


// Get a reference to the NavigationService that navigated to this Page
NavigationService ns = this.NavigationService;
NotaNota

Un objeto Page sólo puede obtener una referencia a su NavigationService cuando Page provoca el evento Loaded.

En el ejemplo siguiente se muestra cómo utilizar el objeto NavigationService para navegar a un objeto Page mediante programación. Se requiere la navegación mediante programación porque sólo se puede crear una instancia del control Page al que se navega mediante un constructor no predeterminado. El objeto Page con el constructor no predeterminado se muestra en el siguiente marcado y código.

<Page
    x:Class="SDKSample.PageWithNonDefaultConstructor"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="PageWithNonDefaultConstructor">

  <!-- Content goes here -->

</Page>

Namespace SDKSample
    Partial Public Class PageWithNonDefaultConstructor
        Inherits Page
        Public Sub New(ByVal message As String)
            InitializeComponent()

            Me.Content = message
        End Sub
    End Class
End Namespace
using System.Windows.Controls; // Page

namespace SDKSample
{
    public partial class PageWithNonDefaultConstructor : Page
    {
        public PageWithNonDefaultConstructor(string message)
        {
            InitializeComponent();

            this.Content = message;
        }
    }
}

El objeto Page que navega al objeto Page con el constructor no predeterminado se muestra en el siguiente marcado y código.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.NSNavigationPage">

  <Hyperlink Click="hyperlink_Click">
    Navigate to Page with Non-Default Constructor
  </Hyperlink>

</Page>

Namespace SDKSample
    Partial Public Class NSNavigationPage
        Inherits Page
        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub hyperlink_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Instantiate the page to navigate to
            Dim page As New PageWithNonDefaultConstructor("Hello!")

            ' Navigate to the page, using the NavigationService
            Me.NavigationService.Navigate(page)
        End Sub
    End Class
End Namespace
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService

namespace SDKSample
{
    public partial class NSNavigationPage : Page
    {
        public NSNavigationPage()
        {
            InitializeComponent();
        }

        void hyperlink_Click(object sender, RoutedEventArgs e)
        {
            // Instantiate the page to navigate to
            PageWithNonDefaultConstructor page = new PageWithNonDefaultConstructor("Hello!");

            // Navigate to the page, using the NavigationService
            this.NavigationService.Navigate(page);
        }
    }
}

Al hacer clic en el objeto Hyperlink de este Page, se inicia la navegación mediante la creación de una instancia del objeto Page al que se va a navegar con el constructor no predeterminado y llamando al método NavigationService.Navigate. Navigate acepta una referencia al objeto al que va a navegar el NavigationService, en lugar de un pack URI.

Si necesita crear un Pack URI mediante programación (por ejemplo, cuando sólo pueda determinar el Pack URI en tiempo de ejecución), puede utilizar el método NavigationService.Navigate. Esto se muestra en el ejemplo siguiente.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.NSUriNavigationPage">
  <Hyperlink Click="hyperlink_Click">Navigate to Page by Pack URI</Hyperlink>
</Page>

Namespace SDKSample
    Partial Public Class NSUriNavigationPage
        Inherits Page
        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub hyperlink_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Create a pack URI
            Dim uri As New Uri("AnotherPage.xaml", UriKind.Relative)

            ' Get the navigation service that was used to 
            ' navigate to this page, and navigate to 
            ' AnotherPage.xaml
            Me.NavigationService.Navigate(uri)
        End Sub
    End Class
End Namespace
using System; // Uri, UriKind
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService

namespace SDKSample
{
    public partial class NSUriNavigationPage : Page
    {
        public NSUriNavigationPage()
        {
            InitializeComponent();
        }

        void hyperlink_Click(object sender, RoutedEventArgs e)
        {
            // Create a pack URI
            Uri uri = new Uri("AnotherPage.xaml", UriKind.Relative);

            // Get the navigation service that was used to 
            // navigate to this page, and navigate to 
            // AnotherPage.xaml
            this.NavigationService.Navigate(uri);
        }
    }
}

Actualiza la página actual

Un objeto Page no se descarga si tiene el mismo pack URI que el pack URI almacenado en la propiedad NavigationService.Source. Para forzar a WPF a que descargue de nuevo la página actual, puede llamar al método NavigationService.Refresh, como se muestra en el ejemplo siguiente.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.NSRefreshNavigationPage">
 <Hyperlink Click="hyperlink_Click">Refresh this page</Hyperlink>
</Page>

Namespace SDKSample
    Partial Public Class NSRefreshNavigationPage
        Inherits Page


...


        Private Sub hyperlink_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Force WPF to download this page again
            Me.NavigationService.Refresh()
        End Sub
    End Class
End Namespace
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService

namespace SDKSample
{
    public partial class NSRefreshNavigationPage : Page
    {


...


        void hyperlink_Click(object sender, RoutedEventArgs e)
        {
            // Force WPF to download this page again
            this.NavigationService.Refresh();
        }
    }
}

Duración de la navegación

Como puede ver, hay muchas formas de iniciar la navegación. Cuando se inicia la navegación, y mientras la navegación está en curso, puede controlar y dirigir la navegación mediante los eventos siguientes implementados por NavigationService:

  • Navigating. Se produce cuando se solicita una nueva navegación. Se puede utilizar para cancelar la navegación.

  • NavigationProgress. Se produce periódicamente durante una descarga para proporcionar información sobre el progreso de navegación.

  • Navigated. Se produce cuando la página se ha encontrado y descargado.

  • NavigationStopped. Se produce cuando se detiene la navegación (llamando al método StopLoading), o cuando se solicita una nueva navegación mientras la navegación actual está en curso.

  • NavigationFailed. Se provoca cuando se produce un error al navegar al contenido solicitado.

  • LoadCompleted. Se produce cuando se ha cargado, se ha analizado y se ha empezado a presentar el contenido al que se navegó.

  • FragmentNavigation. Se produce cuando se inicia la navegación a un fragmento de contenido, que tiene lugar:

    • Inmediatamente, si el fragmento deseado está en el contenido actual.

    • Una vez cargado el contenido de origen, si el fragmento deseado está en contenido diferente.

Los eventos de navegación se provocan en el orden que se indica en la siguiente ilustración.

Gráfico de flujo de navegación de páginas

En general, los objetos Page no tienen que ocuparse de estos eventos. Es más probable que una aplicación tenga que ocuparse de ellos, razón por la cual la clase Application provoca también estos eventos:

Cada vez que NavigationService genera un evento, la clase Application genera el evento correspondiente. Frame y NavigationWindow ofrecen los mismos eventos para detectar la navegación dentro de sus ámbitos respectivos.

En algunos casos, un objeto Page podría tener que ocuparse de estos eventos. Por ejemplo, un objeto Page podría controlar el evento NavigationService.Navigating para determinar si debe cancelar o no la navegación fuera del propio objeto. Esto se muestra en el ejemplo siguiente.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.CancelNavigationPage">
  <Button Click="button_Click">Navigate to Another Page</Button>
</Page>

Namespace SDKSample
    Partial Public Class CancelNavigationPage
        Inherits Page
        Public Sub New()
            InitializeComponent()

            ' Can only access the NavigationService when the page has been loaded
            AddHandler Loaded, AddressOf CancelNavigationPage_Loaded
            AddHandler Unloaded, AddressOf CancelNavigationPage_Unloaded
        End Sub

        Private Sub button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Force WPF to download this page again
            Me.NavigationService.Navigate(New Uri("AnotherPage.xaml", UriKind.Relative))
        End Sub

        Private Sub CancelNavigationPage_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
            AddHandler NavigationService.Navigating, AddressOf NavigationService_Navigating
        End Sub

        Private Sub CancelNavigationPage_Unloaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
            RemoveHandler NavigationService.Navigating, AddressOf NavigationService_Navigating
        End Sub

        Private Sub NavigationService_Navigating(ByVal sender As Object, ByVal e As NavigatingCancelEventArgs)
            ' Does the user really want to navigate to another page?
            Dim result As MessageBoxResult
            result = MessageBox.Show("Do you want to leave this page?", "Navigation Request", MessageBoxButton.YesNo)

            ' If the user doesn't want to navigate away, cancel the navigation
            If result = MessageBoxResult.No Then
                e.Cancel = True
            End If
        End Sub
    End Class
End Namespace
using System; // Uri, UriKind
using System.Windows; // RoutedEventArgs, MessageBox, MessageBoxResult
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService, NavigatingCancelEventArgs

namespace SDKSample
{
    public partial class CancelNavigationPage : Page
    {
        public CancelNavigationPage()
        {
            InitializeComponent();

            // Can only access the NavigationService when the page has been loaded
            this.Loaded += new RoutedEventHandler(CancelNavigationPage_Loaded);
            this.Unloaded += new RoutedEventHandler(CancelNavigationPage_Unloaded);
        }

        void button_Click(object sender, RoutedEventArgs e)
        {
            // Force WPF to download this page again
            this.NavigationService.Navigate(new Uri("AnotherPage.xaml", UriKind.Relative));
        }

        void CancelNavigationPage_Loaded(object sender, RoutedEventArgs e)
        {
            this.NavigationService.Navigating += new NavigatingCancelEventHandler(NavigationService_Navigating);
        }

        void CancelNavigationPage_Unloaded(object sender, RoutedEventArgs e)
        {
            this.NavigationService.Navigating -= new NavigatingCancelEventHandler(NavigationService_Navigating);
        }

        void NavigationService_Navigating(object sender, NavigatingCancelEventArgs e)
        {
            // Does the user really want to navigate to another page?
            MessageBoxResult result;
            result = MessageBox.Show("Do you want to leave this page?", "Navigation Request", MessageBoxButton.YesNo);

            // If the user doesn't want to navigate away, cancel the navigation
            if (result == MessageBoxResult.No) e.Cancel = true;
        }
    }
}

Si registra un controlador con un evento de navegación desde un objeto Page, como en el ejemplo anterior, también debe cancelar el registro del controlador de eventos. Si no lo hace, se podrían producir efectos secundarios relacionados con el modo en que la navegación de WPF recuerda la navegación de Page a través del diario.

Recordar la navegación con el diario

WPF utiliza dos pilas para recordar las páginas desde las que se ha navegado: una pila de retroceso y una pila de avance. Al navegar desde el objeto Pageactual a un nuevo objeto Page o avanzar a un objeto Pageexistente, el objeto Page actual se agrega a la pila de retroceso. Al retroceder desde el objeto Page al objeto Page anterior, el objeto Page se agrega a la pila de avance. La pila de retroceso, la pila de avance y las funciones para administrar estas pilas reciben en conjunto el nombre de diario. Cada elemento de la pila de retroceso y de la pila de avance es una instancia de la clase JournalEntry y se hace referencia a él como una entrada del diario.

Conceptualmente, el diario funciona de la misma manera que los botones Atrás y Adelante de Internet Explorer. Este comportamiento se muestra en la siguiente ilustración.

Botones Atrás y Adelante

Para las XBAPs hospedadas por Internet Explorer, WPF integra el diario en la UI de navegación de Internet Explorer. Esto permite a los usuarios navegar por las páginas de XBAP utilizando los botones Atrás, Adelante y Páginas recientes de Internet Explorer. El diario no se integra en Microsoft Internet Explorer 6 de la misma manera que para Internet Explorer 7 o Internet Explorer 8. En lugar de ello, WPF representa una UI de navegación alternativa.

Nota importanteImportante

En Internet Explorer, cuando un usuario sale y vuelve a una XBAP, sólo se conservan en el diario las entradas de las páginas que no se mantuvieron activas.Para obtener una explicación sobre el mantenimiento activo de las páginas, vea Duración y diario de páginas más adelante en este tema.

De forma predeterminada, el texto de cada Page que aparece en la lista Páginas recientes de Internet Explorer es el URI de Page. En muchos casos, esto no le resulta particularmente significativo al usuario. Afortunadamente, puede cambiar el texto mediante una las opciones siguientes:

  1. El valor del atributo JournalEntry.Name asociado.

  2. El valor del atributo Page.Title.

  3. El valor del atributo Page.WindowTitle y el URI del objeto Page actual.

  4. El URI del objeto Page actual. (Valor predeterminado)

El orden en que se indican las opciones es el mismo que el orden de prioridad de la búsqueda de texto. Por ejemplo, si se establece JournalEntry.Name, se omiten los demás valores.

En el ejemplo siguiente se utiliza el atributo Page.Title para cambiar el texto que aparece para una entrada del diario.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.PageWithTitle"
    Title="This is the title of the journal entry for this page.">


...


</Page>

Namespace SDKSample
    Partial Public Class PageWithTitle
        Inherits Page


...


    End Class
End Namespace
using System.Windows.Controls; // Page

namespace SDKSample
{
    public partial class PageWithTitle : Page
    {


...


    }
}

Aunque un usuario puede navegar por el diario mediante los botones Atrás, Adelante y Páginas recientes de Internet Explorer, también puede utilizar para tal fin los mecanismos declarativos y de programación proporcionados por WPF. Esto puede ser necesario, por ejemplo, para proporcionar una UIs de navegación personalizada en sus páginas.

Puede permitir mediante declaración la navegación por el diario utilizando los comandos de navegación expuestos por NavigationCommands. En el siguiente ejemplo se muestra cómo utilizar el comando de navegación BrowseBack.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.NavigationCommandsPage">


...


<Hyperlink Command="NavigationCommands.BrowseBack">Back</Hyperlink>


...


<Hyperlink Command="NavigationCommands.BrowseForward">Forward</Hyperlink>


...


</Page>

Puede navegar por el diario mediante programación utilizando alguno de los miembros siguientes de la clase NavigationService:

El diario se puede manipular también mediante programación, como se describe en Conservar el estado del contenido con un historial de navegación más adelante en este tema.

Duración y diario de páginas

Considere una XBAP con varias páginas que hospedan contenido avanzado, como gráficos, animación y elementos multimedia. La superficie de memoria para páginas como estas podría ser bastante grande, sobre todo si se utilizan elementos multimedia de audio y vídeo. Como el diario "recuerda" las páginas a las que se ha navegado, una XBAP podría utilizar una cantidad considerable de memoria rápidamente.

Por esta razón, el comportamiento predeterminado del diario es almacenar los metadatos de Page en cada entrada del diario en lugar de una referencia a un objeto Page. Cuando se navega a una entrada del diario, se utilizan sus metadatos de Page para crear una nueva instancia del objeto Pageespecificado. Por consiguiente, cada objeto Page visitado tiene la duración que se muestra en la siguiente ilustración.

Duración de la página

Aunque el uso del comportamiento del diario predeterminado puede ahorrar memoria, podría dar lugar a una reducción del rendimiento de la representación de cada página, ya que crear una nueva instancia de un objeto Page puede ser laborioso, especialmente si tiene mucho contenido. Si necesita conservar una instancia de Page en el diario, puede utilizar dos técnicas para ello. En primer lugar, puede navegar mediante programación a un objeto Page llamando al método NavigationService.Navigate.

En segundo lugar, puede especificar que WPF conserve una instancia de Page en el diario estableciendo la propiedad KeepAlive en true (el valor predeterminado es false). Como se muestra en el ejemplo siguiente, puede establecer KeepAlive mediante declaración en el marcado.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.KeepAlivePage"
    KeepAlive="True">

  An instance of this page is stored in the journal.

</Page>

La duración de un objeto Page que se mantiene activo es ligeramente diferente al de uno inactivo. La primera vez que se navega a un objeto Page que se mantiene activo, se crea una instancia de dicho objeto, como ocurre con un objeto Page que no se mantiene activo. Sin embargo, como se conserva una instancia de Page en el diario, no se vuelve a crear nunca más una nueva instancia mientras ésta permanezca en el diario. Por tanto, si un objeto Page contiene lógica de inicialización a la que hay que llamar cada vez que se navega a Page, deberá mover esa lógica del constructor a un controlador del evento Loaded. Como se muestra en la ilustración siguiente, los eventos Loaded y Unloaded se provocan igualmente cada vez que se navega a y desde un objeto Page, respectivamente.

Cuándo se provocan los eventos Loaded y Unloaded

Cuando un objeto Page no se mantiene activo, no debe realizar ninguna de las operaciones siguientes:

  • Almacenar una referencia al objeto o a alguna parte del mismo.

  • Registrar controladores de eventos con eventos no implementados por el objeto.

Si realiza alguna de estas operaciones, creará referencias que obliguen al objeto Page a conservarse en memoria, incluso después de que se quite del diario.

En general, debería optar por el comportamiento Page predeterminado, que no mantiene el objeto Page activo. Sin embargo, este comportamiento tiene implicaciones que afectan al estado, descritas en la siguiente sección.

Conservar el estado del contenido con el historial de navegación

Si un objeto Page no se mantiene activo y tiene controles que recopilan datos del usuario, ¿qué ocurre con los datos si un usuario avanza y retrocede al objeto Page? Desde la perspectiva de la experiencia del usuario, el usuario debe esperar ver los datos que especificó previamente. Desgraciadamente, como se crea una nueva instancia de Page con cada navegación, se crean nuevas instancias de los controles que recopilaron los datos y los datos se pierden.

Por fortuna, el diario proporciona compatibilidad para recordar los datos durante la navegación por Page, incluidos los datos de los controles. En concreto, la entrada del diario de cada Page actúa como un contenedor temporal para el estado de Page asociado. En los pasos siguientes se explica brevemente cómo funciona esta compatibilidad cuando se navega desde un objeto Page:

  1. Se agrega una entrada del objeto Page actual al diario.

  2. El estado del objeto Page se almacena con la entrada del diario de esa página, que se agrega a la pila de retroceso.

  3. Se navega al nuevo objeto Page.

Cuando se retrocede al objeto Page, gracias al diario, se producen las siguientes operaciones:

  1. Se crea una instancia de Page (la entrada superior del diario en la pila de retroceso).

  2. El objeto Page se actualiza con el estado que se almacenó con la entrada del diario para el objeto Page.

  3. Se retrocede al objeto Page.

WPF utiliza automáticamente esta compatibilidad cuando se utilizan los controles siguientes en un objeto Page:

Si un objeto Page utiliza estos controles, los datos registrados en ellos se recuerdan durante la navegación por Page, como se muestra en Favorite colorListBox en la ilustración siguiente.

Página con controles que recuerdan el estado

Cuando un objeto Page tiene controles distintos de los de la lista anterior, o cuando el estado se almacena en objetos personalizados, debe escribir código que permita al diario recordar el estado durante la navegación por Page.

Si necesita recordar pequeños segmentos de estado durante la navegación por Page, puede utilizar propiedades de dependencia (vea DependencyProperty) que se configuran con el marcador de metadatos de FrameworkPropertyMetadata.Journal.

Si el estado que el objeto Page necesita recordar durante la navegación consta de varios segmentos de datos, puede resultarle más sencillo encapsular el estado en una clase única e implementar la interfaz IProvideCustomContentState.

Si necesita desplazarse por varios estados de un mismo objeto Page, sin navegar desde el propio objeto Page, puede utilizar IProvideCustomContentState y NavigationService.AddBackEntry.

Cookies

Otro modo en que las aplicaciones de WPF pueden almacenar datos es mediante cookies, que se crean, actualizan y eliminan con los métodos SetCookie y GetCookie. Las cookies que puede crear en WPF son las mismas cookies que utilizan otros tipos de aplicaciones web; las cookies son segmentos arbitrarios de datos que almacena una aplicación en un equipo cliente durante una o varias sesiones. Los datos de las cookies normalmente son pares de nombre y valor con el formato siguiente.

Nombre=Valor

Cuando se pasan los datos a SetCookie, junto con el Uri de la ubicación para la que se debe establecer la cookie, se crea una cookie en memoria, y sólo está disponible durante la sesión de la aplicación actual. Este tipo de cookie se denomina cookie de sesión.

Para almacenar una cookie en varias sesiones de la aplicación, debe agregarse una fecha de expiración a la cookie, con el formato siguiente.

NOMBRE=VALOR; expires=DAY, DD-MMM-YYYY HH:MM:SS GMT

Una cookie con fecha de expiración se almacena en la carpeta Archivos temporales de Internet de la instalación de Windows hasta que la cookie expira. Este tipo de cookie se denomina cookie persistente porque se conserva durante las sesiones de la aplicación.

Puede recuperar las cookies de sesión y persistentes llamando al método GetCookie, pasando el Uri de la ubicación donde se estableció la cookie con el método SetCookie.

A continuación, se indican algunas de las formas en que se admiten cookies en WPF:

  • Las aplicaciones de WPF independientes y las XBAPs pueden crear y administrar cookies.

  • Se puede tener acceso a las cookies creadas por una XBAP desde el explorador.

  • Las XBAPs del mismo dominio pueden crear y compartir cookies.

  • Las XBAPs y las páginas HTML del mismo dominio pueden crear y compartir cookies.

  • Las cookies se envían cuando las XBAPs y las páginas XAML independientes crean solicitudes web.

  • Las XBAPs de alto nivel y las XBAPs hospedadas en IFRAMES pueden tener acceso a las cookies.

  • La compatibilidad de las cookies en WPF es la misma para todos los exploradores compatibles.

  • En Internet Explorer, WPF aplica la directiva P3P relacionada con las cookies, especialmente en relación con XBAPs propias y de otros fabricantes.

Si necesita pasar datos de un objeto Page a otro, puede pasarlos como argumentos a un constructor no predeterminado de Page. Tenga en cuenta que si utiliza esta técnica, debe mantener el objeto Page activo ya que, de lo contrario, la próxima vez que navegue al objeto Page, WPF creará una nueva instancia del objeto Page mediante el constructor predeterminado.

Page puede implementar también propiedades que se establezcan con los datos que debe pasar. Sin embargo, las cosas se complican cuando un objeto Page tiene que volver a pasar datos al objeto Page que navegó a él. El problema reside en que la navegación no permite de forma nativa mecanismos que garanticen que se vuelva a un objeto Page una vez abandonado. Esencialmente, la navegación no admite la semántica de llamada/devolución. Para resolver este problema, WPF proporciona la clase PageFunction<T>, que se puede utilizar para garantizar que se vuelva a un objeto Page de un modo previsible y estructurado. Para obtener más información, vea Información general sobre la navegación estructurada.

La clase NavigationWindow

Llegados a este punto, ya se han abordado los servicios de navegación que probablemente utilizará con más frecuencia para crear aplicaciones con contenido navegable. Estos servicios se describen en el contexto de las XBAPs, pero no se limitan a las XBAPs. Los sistemas operativos modernos y las aplicaciones de Windows aprovechan la experiencia de los usuarios con el uso de los exploradores para incorporar una navegación similar a la de un explorador en las aplicaciones independientes. Algunos ejemplos son:

  • Diccionario de sinónimos de Word: navegación por opciones de palabras.

  • Explorador de archivos: navegación por archivos y carpetas.

  • Asistentes: descomposición de una tarea compleja en varias páginas por las que se puede navegar. Un ejemplo es el Asistente para componentes de Windows que controla la incorporación y eliminación de características de Windows.

Para incorporar una navegación similar a la de los exploradores en sus aplicaciones independientes, puede usar la clase NavigationWindow. NavigationWindow se deriva de Window y la extiende con la misma compatibilidad de navegación que proporciona XBAPs. Puede utilizar NavigationWindow como la ventana principal de la aplicación independiente o como una ventana secundaria, como un cuadro de diálogo.

Para implementar NavigationWindow, al igual que con la mayoría de las clases de nivel superior de WPF (Window, Page, etc.), se utiliza una combinación de marcado y código subyacente. Esta implementación se muestra en el ejemplo siguiente.

<NavigationWindow
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.MainWindow" 
    Source="HomePage.xaml"/>

Namespace SDKSample
    Partial Public Class MainWindow
        Inherits NavigationWindow
        Public Sub New()
            InitializeComponent()
        End Sub
    End Class
End Namespace
using System.Windows.Navigation; // NavigationWindow

namespace SDKSample
{
    public partial class MainWindow : NavigationWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

Este código crea un objeto NavigationWindow que navega automáticamente a un objeto Page (HomePage.xaml) cuando se abre NavigationWindow. Si NavigationWindow es la ventana principal de la aplicación, puede utilizar el atributo StartupUri para iniciarla. Esto queda reflejado en el marcado siguiente.

<Application
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    StartupUri="MainWindow.xaml" />

En la ilustración siguiente se muestra el objeto NavigationWindow como la ventana principal de una aplicación independiente.

Ventana principal

En la ilustración, puede ver que NavigationWindow tiene un título, aunque no se estableció en el código de implementación de NavigationWindow del ejemplo anterior. El título se establece mediante la propiedad WindowTitle, que se muestra en el código siguiente.

<Page 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Title="Home Page"
    WindowTitle="NavigationWindow">


...


</Page>

El establecimiento de las propiedades WindowWidth y WindowHeight afecta también al objeto NavigationWindow.

Normalmente, implementará su propio NavigationWindow cuando necesite personalizar su comportamiento o su apariencia. Si no es el caso, hay una alternativa más simple. Si especifica el pack URI de un objeto Page como StartupUri en una aplicación independiente, Application crea automáticamente un objeto NavigationWindow para hospedar el objeto Page. Esta operación se muestra en el marcado siguiente.

<Application
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    StartupUri="HomePage.xaml" />

Si desea que una ventana de la aplicación secundaria como un cuadro de diálogo sea un objeto NavigationWindow, puede utilizar el código del ejemplo siguiente para abrirla.

            ' Open a navigation window as a dialog box
            Dim dlg As New NavigationWindowDialogBox()
            dlg.Source = New Uri("HomePage.xaml", UriKind.Relative)
            dlg.Owner = Me
            dlg.ShowDialog()
// Open a navigation window as a dialog box
NavigationWindowDialogBox dlg = new NavigationWindowDialogBox();
dlg.Source = new Uri("HomePage.xaml", UriKind.Relative);
dlg.Owner = this;
dlg.ShowDialog();

En la ilustración siguiente se muestra el resultado.

Cuadro de diálogo

Como puede ver, NavigationWindow muestra los botones Atrás y Adelante con el formato de Internet Explorer, que permiten a los usuarios navegar por el diario. Estos botones proporcionan la misma experiencia del usuario, como se muestra en la ilustración siguiente.

Botones Atrás y Adelante en NavigationWindow

Si sus páginas proporcionan su propia compatibilidad e interfaz de usuario de navegación por el diario, puede ocultar los botones Atrás y Adelante mostrados por NavigationWindow estableciendo el valor de la propiedad ShowsNavigationUI en false.

También puede utilizar la compatibilidad de personalización de WPF para reemplazar la UI del propio NavigationWindow.

La clase Frame

Tanto el explorador como NavigationWindow son ventanas que hospedan contenido navegable. En algunos casos, las aplicaciones tienen contenido que no necesita hospedarse en una ventana completa. Este contenido se puede hospedar dentro de otro contenido. Puede insertar contenido navegable en otro contenido utilizando la clase Frame. Frame proporciona la misma compatibilidad que NavigationWindow y XBAPs.

En el ejemplo siguiente se muestra cómo agregar mediante declaración un objeto Frame a Page con el elemento Frame.

<Page 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  WindowTitle="Page that Hosts a Frame"
  WindowWidth="250"
  WindowHeight="250">


...


<Frame Source="FramePage1.xaml" />


...


</Page>

Este marcado establece el atributo Source del elemento Frame con un pack URI para el Page al que Frame debe navegar inicialmente. En la ilustración siguiente se muestra una XBAP con un objeto Page que tiene un Frame que ha navegado por varias páginas.

Marco que ha navegado entre varias páginas

No sólo tiene que utilizar Frame dentro del contenido de un objeto Page. También es habitual hospedar un Frame dentro del contenido de un objeto Window.

De forma predeterminada, Frame sólo utiliza su propio diario si no existe ningún otro. Si un Frame forma parte del contenido que se hospeda dentro de un objeto NavigationWindow o XBAP, Frame utiliza el diario que pertenece a NavigationWindow o XBAP. Sin embargo, en ocasiones, puede que Frame necesite responsabilizarse de su propio diario. Sin embargo, en algunas ocasiones, es posible que un objeto Frame tenga que ocuparse de su propio diario. Esto se muestra en la ilustración siguiente.

Diagrama de marco y página

En este caso, puede configurar el objeto Frame para que utilice su propio diario estableciendo la propiedad JournalOwnership de Frame en OwnsJournal. Esto queda reflejado en el marcado siguiente.

<Page 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  WindowTitle="Page that Hosts a Frame"
  WindowWidth="250"
  WindowHeight="250">


...


<Frame Source="FramePage1.xaml" JournalOwnership="OwnsJournal" />


...


</Page>

En la ilustración siguiente se muestra el efecto de navegar dentro de un objeto Frame que utiliza su propio diario.

Marco que usa su propio diario

Observe que es la UI de navegación de Frame y no Internet Explorer, la que muestra las entradas del diario.

NotaNota

Si un objeto Frame forma parte del contenido hospedado en Window, Frame utiliza su propio diario y, por tanto, presenta su propia UI de navegación.

Si la experiencia de usuario requiere que un objeto Frame proporcione su propio diario sin mostrar la UI de navegación, puede ocultar la UI de navegación estableciendo NavigationUIVisibility en Hidden. Esto queda reflejado en el marcado siguiente.

<Page 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  WindowTitle="Page that Hosts a Frame"
  WindowWidth="250"
  WindowHeight="250">


...


<Frame 
  Source="FramePage1.xaml" 
  JournalOwnership="OwnsJournal" 
  NavigationUIVisibility="Hidden" />


...


</Page>

Hosts de navegación

Frame y NavigationWindow son clases que se denominan hosts de navegación. Un host de navegación es una clase que puede navegar a contenido y mostrarlo. Para tal fin, cada host de navegación utiliza su propio NavigationService y diario. La creación básica de un host de navegación se muestra en la ilustración siguiente.

Diagramas de navegador

Básicamente, este host permite que NavigationWindow y Frame proporcionen la misma compatibilidad de navegación que la que proporciona una XBAP cuando se hospeda en el explorador.

Además de utilizar NavigationService y un diario, los hosts de navegación implementan los mismos miembros que implementa NavigationService. Esto se muestra en la ilustración siguiente.

Diario en un marco y en NavigationWindow

Esto permite programar directamente en ellos la compatibilidad de navegación. Puede considerar esto si necesita proporcionar una UI de navegación personalizada para un control Frame hospedado en Window. Además, ambos tipos implementan miembros adicionales, relacionados con la navegación, incluidos BackStack (NavigationWindow.BackStack, Frame.BackStack) y ForwardStack (NavigationWindow.ForwardStack, Frame.ForwardStack), que permiten enumerar las entradas del diario en la pila de retroceso y de reenvío, respectivamente.

Como se indicó anteriormente, puede haber varios diarios en una aplicación. En la ilustración siguiente se proporciona un ejemplo de esta circunstancia.

Varios diarios dentro de una aplicación

A lo largo de este tema, se han utilizado Page y XBAPs de paquete para mostrar las distintas opciones de navegación de WPF. Sin embargo, un objeto Page compilado en una aplicación no es el único tipo de contenido al que se puede navegar, y las XBAPs de paquete no constituyen el único modo de identificar contenido.

Como se muestra en esta sección, puede navegar también a archivos XAML independientes, a archivos HTML y a objetos.

Un archivo XAML independiente es un archivo con las características siguientes:

  • Sólo contiene XAML (es decir, no contiene código).

  • Tiene una declaración de espacio de nombres adecuada.

  • Tiene la extensión de nombre de archivo .xaml.

Considere, por ejemplo, el contenido siguiente que está almacenado como un archivo XAML independiente, Person.xaml.

<!-- Person.xaml -->
<TextBlock xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <TextBlock FontWeight="Bold">Name:</TextBlock>
  <TextBlock>Nancy Davolio</TextBlock>
  <LineBreak />
  <TextBlock FontWeight="Bold">Favorite Color:</TextBlock>
  <TextBlock>Yellow</TextBlock>
</TextBlock>

Al hacer doble clic en el archivo, el explorador se abre, se desplaza al contenido y lo muestra. Este comportamiento se muestra en la ilustración siguiente.

Presentación del contenido del archivo Person.XAML

Puede mostrar un archivo XAML independiente desde los siguientes elementos:

  • Un sitio web en el equipo local, la intranet o Internet.

  • Un recurso compartido de archivos Universal Naming Convention (UNC).

  • El disco local.

Un archivo XAML independiente se puede agregar a los favoritos del explorador o convertirse en la página principal del explorador.

NotaNota

Para obtener más información sobre cómo publicar e iniciar páginas XAML independientes, vea Implementar una aplicación de WPF.

Una limitación de los archivos XAML independientes es que sólo permiten hospedar contenido que se pueda ejecutar de forma segura en una relación de confianza parcial. Por ejemplo, Window no puede ser el elemento raíz de un archivo XAML independiente. Para obtener más información, vea Seguridad de confianza parcial de WPF.

Como cabe esperar, también es posible navegar a HTML. Sólo tiene que proporcionar un URI que utilice el esquema http. Por ejemplo, el XAML siguiente muestra un objeto Frame que navega a una página HTML.

<Frame Source="https://www.microsoft.com/default.aspx" />

Para navegar a HTML se requieren permisos especiales. Por ejemplo, no se puede navegar desde XBAP en ejecución en el recinto de seguridad de confianza parcial de la zona de Internet. Para obtener más información, vea Seguridad de confianza parcial de WPF.

El control WebBrowser admite el hospedaje de documentos HTML, la navegación y la interoperabilidad de script/código administrado. Para obtener información detallada acerca del control WebBrowser, vea WebBrowser.

Al igual que sucede con Frame, para navegar a HTML mediante WebBrowser se necesitan permisos especiales. Por ejemplo, desde una aplicación de confianza parcial, únicamente puede navegar hasta el HTML que se encuentra en el sitio de origen. Para obtener más información, vea Seguridad de confianza parcial de WPF.

Si tiene datos que están almacenados como objetos personalizados, una manera de mostrar esos datos es crear un objeto Page con contenido enlazado a esos objetos (vea Información general sobre el enlace de datos). Si puede prescindir del trabajo adicional que supone crear una página completa para mostrar simplemente los objetos, puede navegar directamente a ellos.

Considere la clase Person que se implementa en el código siguiente.


Namespace SDKSample
    Public Class Person
        Private _name As String
        Private _favoriteColor As Color

        Public Sub New()
        End Sub
        Public Sub New(ByVal name As String, ByVal favoriteColor As Color)
            Me._name = name
            Me._favoriteColor = favoriteColor
        End Sub

        Public Property Name() As String
            Get
                Return Me._name
            End Get
            Set(ByVal value As String)
                Me._name = value
            End Set
        End Property

        Public Property FavoriteColor() As Color
            Get
                Return Me._favoriteColor
            End Get
            Set(ByVal value As Color)
                Me._favoriteColor = value
            End Set
        End Property
    End Class
End Namespace
using System.Windows.Media; // Color

namespace SDKSample
{
    public class Person
    {
        string name;
        Color favoriteColor;

        public Person() { }
        public Person(string name, Color favoriteColor)
        {
            this.name = name;
            this.favoriteColor = favoriteColor;
        }

        public string Name
        {
            get { return this.name; }
            set { this.name = value; }
        }

        public Color FavoriteColor
        {
            get { return this.favoriteColor; }
            set { this.favoriteColor = value; }
        }
    }
}

Para navegar a ella, llama al método NavigationWindow.Navigate, como se muestra en el código siguiente.

<Page 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.HomePage"
  WindowTitle="Page that Navigates to an Object">


...


<Hyperlink Name="hyperlink" Click="hyperlink_Click">
  Navigate to Nancy Davolio
</Hyperlink>


...


</Page>

Namespace SDKSample
    Partial Public Class HomePage
        Inherits Page
        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub hyperlink_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Dim person As New Person("Nancy Davolio", Colors.Yellow)
            Me.NavigationService.Navigate(person)
        End Sub
    End Class
End Namespace
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Media; // Colors

namespace SDKSample
{
    public partial class HomePage : Page
    {
        public HomePage()
        {
            InitializeComponent();
        }

        void hyperlink_Click(object sender, RoutedEventArgs e)
        {
            Person person = new Person("Nancy Davolio", Colors.Yellow);
            this.NavigationService.Navigate(person);
        }
    }
}

En la ilustración siguiente se muestra el resultado.

Página que navega a una clase

En esta ilustración, puede ver que no se muestra ninguna información útil. De hecho, el valor que se muestra es el valor devuelto por el método ToString para el objeto Person; de forma predeterminada, éste es el único valor que WPF puede utilizar para representar el objeto. Podría invalidar el método ToString para devolver información más útil, pero seguiría siendo simplemente un valor de cadena. Una técnica posible que aprovecha las funciones de presentación WPF es usar una plantilla de datos. Puede implementar una plantilla de datos que WPF pueda asociar a un objeto de un tipo determinado. En el código siguiente se muestra una plantilla de datos para el objeto Person.

<Application
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SDKSample" 
    x:Class="SDKSample.App"
    StartupUri="HomePage.xaml">

  <Application.Resources>

    <!-- Data Template for the Person Class -->
    <DataTemplate DataType="{x:Type local:Person}">
      <TextBlock xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
        <TextBlock FontWeight="Bold">Name:</TextBlock>
        <TextBlock Text="{Binding Path=Name}" />
        <LineBreak />
        <TextBlock FontWeight="Bold">Favorite Color:</TextBlock>
        <TextBlock Text="{Binding Path=FavoriteColor}" />
      </TextBlock>
    </DataTemplate>

  </Application.Resources>

</Application>

Aquí, la plantilla de datos está asociada al tipo Person mediante la extensión de marcado x:Type del atributo DataType. La plantilla de datos enlaza los elementos TextBlock (vea TextBlock) a las propiedades de la clase Person. En la ilustración siguiente se muestra el aspecto actualizado del objeto Person.

Navegar a una clase que tiene una plantilla de datos

Una ventaja de esta técnica es la coherencia conseguida al ser capaz de reutilizar la plantilla de datos para mostrar los objetos con un aspecto similar en cualquier lugar de la aplicación.

Para obtener más información sobre las plantillas de datos, vea Información general sobre plantillas de datos.

Seguridad

La compatibilidad de navegación de WPF permite utilizar las XBAPs para toda la navegación por Internet, y permite que las aplicaciones hospeden contenido de otros fabricantes. Para proteger las aplicaciones y a los usuarios de un comportamiento malintencionado, WPF proporciona un conjunto de características de seguridad que se describen en Seguridad (WPF) y Seguridad de confianza parcial de WPF.

Vea también

Referencia

SetCookie

GetCookie

Conceptos

Información general sobre la administración de aplicaciones

Empaquetar URI en WPF

Información general sobre la navegación estructurada

Información general sobre topologías de navegación

Implementar una aplicación de WPF

Otros recursos

Temas "Cómo..." de navegación