Cenni preliminari sulla navigazione

Windows Presentation Foundation (WPF) supporta la navigazione di tipo browser che può essere utilizzata in due tipi di applicazioni: le applicazioni autonome e le XAML browser applications (XBAPs). Per assemblare un contenuto ai fini della navigazione, in WPF viene fornita la classe Page. È possibile spostarsi da un oggetto Page a un altro in modo dichiarativo mediante Hyperlink oppure a livello di codice mediante NavigationService. In WPF viene utilizzato il journal per memorizzare le pagine da cui ci si è spostati e tornarvi nuovamente.

Page, Hyperlink, NavigationService e il journal costituiscono gli elementi essenziali del supporto per la navigazione offerto da WPF. In questo argomento vengono descritte in dettaglio le suddette funzionalità, per poi illustrare il supporto per la navigazione avanzata che include la navigazione su file Extensible Application Markup Language (XAML) separati, file HTML e oggetti.

NotaNota

Il termine "browser" qui utilizzato fa riferimento soltanto ai browser in grado di ospitare applicazioni WPF, che attualmente includono Microsoft Internet Explorer e Firefox.Nel caso in cui determinate funzionalità di WPF siano supportate unicamente da un particolare browser, verrà fatto riferimento alla versione del browser.

Nel presente argomento sono contenute le seguenti sezioni.

  • Navigazione nelle applicazioni WPF
  • Classe NavigationWindow
  • Classe Frame
  • Host di navigazione
  • Navigazione su contenuto diverso dalle pagine XAML
  • Sicurezza
  • Argomenti correlati

In questo argomento viene fornita una panoramica sulle principali funzionalità di navigazione in WPF. Queste funzionalità sono disponibili sia per le applicazioni autonome che per le applicazioni XBAPs. Qui verranno presentate nel contesto di un'applicazione XBAP.

NotaNota

La compilazione e la distribuzione delle applicazioni XBAPs non vengono trattate in questo argomento.Per ulteriori informazioni sulle applicazioni XBAPs, vedere Panoramica delle applicazioni browser XAML di WPF.

In questa sezione vengono illustrati i seguenti aspetti della navigazione:

  • Implementazione di una pagina

  • Configurazione di una pagina iniziale

  • Configurazione del titolo, della larghezza e dell'altezza della finestra host

  • Navigazione mediante collegamenti ipertestuali

  • Navigazione su un frammento

  • Servizio di navigazione

  • Navigazione a livello di codice mediante servizio di navigazione

  • Durata della navigazione

  • Memorizzazione della navigazione mediante journal

  • Durata della pagina e journal

  • Mantenimento dello stato del contenuto mediante cronologia di navigazione

  • Cookie

  • Navigazione strutturata

Implementazione di una pagina

WPF consente di spostarsi su diversi tipi di contenuto, tra cui oggetti .NET Framework, oggetti personalizzati, valori di enumerazione, controlli utente, file XAML e file HTML. Il metodo più comune e conveniente per assemblare il contenuto consiste tuttavia nell'utilizzo di Page. Inoltre, Page implementa funzionalità specifiche della navigazione che consentono di migliorarne l'aspetto e semplificarne lo sviluppo.

Utilizzando Page è possibile implementare in modo dichiarativo una pagina di contenuto XAML navigabile tramite markup analogo al seguente.

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

Un oggetto Page implementato nel markup XAML è caratterizzato dall'elemento radice Page e richiede la dichiarazione dello spazio dei nomi XML WPF. L'elemento Page include il contenuto sul quale spostarsi per la visualizzazione. Per aggiungere contenuto è necessario impostare l'elemento della proprietà Page.Content, come illustrato nel seguente markup.

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

Page.Content può contenere soltanto un elemento figlio. Nell'esempio precedente, il contenuto è una stringa unica, "Hello, Page!". In genere si utilizza quindi un controllo di layout come elemento figlio (vedere Sistema di layout) per contenere e comporre il contenuto.

Gli elementi figlio di un elemento Page vengono considerati come contenuto di Page e, di conseguenza, non sarà necessario utilizzare la dichiarazione Page.Content esplicita. Il markup che segue è l'equivalente dichiarativo dell'esempio precedente.

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

In questo caso, Page.Content viene automaticamente impostato con gli elementi figlio dell'elemento Page. Per ulteriori informazioni, vedere Modello di contenuto WPF.

Un oggetto Page solo markup è utile per la visualizzazione di contenuto. Tuttavia Page può anche visualizzare controlli che consentono agli utenti di interagire con la pagina, nonché rispondere all'interazione dell'utente mediante gestione di eventi e chiamata alla logica dell'applicazione. Un oggetto Page interattivo viene implementato mediante una combinazione di markup e code-behind, come illustrato nell'esempio che segue.

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

Per consentire il funzionamento congiunto di un file di markup e un file code-behind, è necessaria la seguente configurazione:

  • Nel markup, l'elemento Page deve includere l'attributo x:Class. Quando l'applicazione viene compilata, la presenza di x:Class nel file di markup fa sì che Microsoft build engine (MSBuild) crei una classe partial derivante da Page e avente il nome specificato dall'attributo x:Class. Questo richiede l'aggiunta di una dichiarazione dello spazio dei nomi XML per lo schema XAML (xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"). La classe partial generata implementa InitializeComponent, il quale viene chiamato per registrare gli eventi e impostare le proprietà implementate nel markup.

  • Nel code-behind, la classe deve essere una classe partial avente lo stesso nome specificato dall'attributo x:Class nel markup e deve derivare da Page. In questo modo il file code-behind può essere associato alla classe partial generata per il file di markup durante la compilazione dell'applicazione (vedere Compilazione di un'applicazione WPF (WPF)).

  • Nel code-behind, la classe Page deve implementare un costruttore che chiama il metodo InitializeComponent. Il metodo InitializeComponent viene implementato dalla classe partial generata per il file di markup per registrare gli eventi e impostare le proprietà definite nel markup.

NotaNota

Quando si aggiunge un nuovo oggetto Page al progetto utilizzando Microsoft Visual Studio, questo viene implementato tramite markup e code-behind e include la configurazione necessaria per creare l'associazione tra il file di markup e il file code-behind, come descritto in questo argomento.

Una volta creato Page, sarà possibile spostarsi su di esso. Per specificare il primo oggetto Page sul quale si sposta un'applicazione, è necessario configurare l'oggetto Page iniziale.

Configurazione di una pagina iniziale

Le applicazioni XBAPs richiedono una determinata infrastruttura per essere ospitate in un browser. In WPF, la classe Application fa parte di una definizione di applicazione che stabilisce l'infrastruttura dell'applicazione richiesta (vedere Cenni preliminari sulla gestione di applicazioni).

In genere una definizione di applicazione viene implementata tramite markup e code-behind, con il file di markup configurato come elemento ApplicationDefinition MSBuild. Di seguito viene riportata una definizione di applicazione per un'applicazione 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 { }
}

In un'applicazione XBAP è possibile utilizzare la definizione di applicazione per specificare un oggetto Page iniziale, ovvero l'oggetto Page caricato automaticamente all'avvio dell'applicazione XBAP. A tale scopo è necessario impostare la proprietà StartupUri con lo uniform resource identifier (URI) per l'oggetto Page desiderato.

NotaNota

Nella maggior parte dei casi, Page viene compilato all'interno di un'applicazione o distribuito con essa.In questi casi, l'URI che identifica Page è un URI di tipo pack, ovvero un URI conforme allo schema pack.Gli URIs di tipo pack verranno ulteriormente trattati in URI di tipo pack in WPF. Per spostarsi su un contenuto è anche possibile utilizzare lo schema HTTP, illustrato di seguito.

È possibile impostare StartupUri in modo dichiarativo nel markup, come illustrato nell'esempio che segue.

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

In questo esempio, l'attributo StartupUri è impostato con un URI di tipo pack relativo che identifica HomePage.xaml. Quando l'applicazione XBAP viene avviata, ci si sposta automaticamente su HomePage.xaml visualizzandolo. Quanto detto viene illustrato nella figura che segue, in cui viene rappresentata un'applicazione XBAP avviata da un server Web.

Pagina XBAP

NotaNota

Per ulteriori informazioni sullo sviluppo e la distribuzione delle applicazioni XBAPs, vedere Panoramica delle applicazioni browser XAML di WPF e Distribuzione di un'applicazione WPF (WPF).

Configurazione del titolo, della larghezza e dell'altezza della finestra host

Come si può notare dalla figura precedente, il titolo del browser e del riquadro della scheda è l'URI dell'applicazione XBAP. Oltre a essere lungo, il titolo non è visivamente gradevole né informativo. Per questa ragione, Page offre la possibilità di modificare il titolo impostando la proprietà WindowTitle. È anche possibile configurare la larghezza e l'altezza della finestra del browser impostando rispettivamente WindowWidth e WindowHeight.

WindowTitle, WindowWidth e WindowHeight possono essere impostate in modo dichiarativo nel markup, come illustrato nell'esempio che segue.

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

Nella figura riportata di seguito viene illustrato il risultato.

Titolo, altezza e larghezza della finestra

Un'applicazione XBAP tipica comprende diverse pagine. Il modo più semplice per spostarsi da una pagina all'altra consiste nell'utilizzo di Hyperlink. Per aggiungere in modo dichiarativo Hyperlink a Page, utilizzare l'elemento Hyperlink, illustrato nel seguente markup.

<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 necessita dei seguenti elementi:

  • L'URI di tipo pack dell'oggetto Page sul quale ci si deve spostare, come specificato dall'attributo NavigateUri.

  • Un contenuto sul quale un utente possa fare clic per avviare la navigazione, ad esempio testo o immagini. Per informazioni sul contenuto dell'elemento Hyperlink, vedere Hyperlink.

Nella figura riportata di seguito viene illustrata un'applicazione XBAP con un oggetto Page contenente un oggetto Hyperlink.

Pagina con collegamento ipertestuale

Come previsto, facendo clic su Hyperlink l'applicazione XBAP si sposta sull'oggetto Page identificato dall'attributo NavigateUri. Inoltre l'applicazione XBAP aggiunge una voce relativa all'oggetto Page precedente all'elenco Pagine recenti di Internet Explorer, come illustrato nella figura che segue.

Pulsanti Back e Forward

Oltre a supportare la navigazione da un oggetto Page all'altro, Hyperlink supporta anche la navigazione su un frammento.

La navigazione su un frammento è l'azione mediante la quale ci si sposta su un frammento di contenuto dell'oggetto Page corrente o di un altro oggetto Page. In WPF un frammento equivale al contenuto incluso in un elemento denominato, ovvero un elemento con l'attributo Name impostato. Nel markup che segue viene illustrato un elemento TextBlock denominato contenente un frammento di contenuto.

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

Per fare in modo che Hyperlink si sposti su un frammento di contenuto, l'attributo NavigateUri deve includere quanto segue:

  • L'URI dell'oggetto Page contenente il frammento sul quale ci si deve spostare.

  • Un carattere "#".

  • Il nome dell'elemento di Page contenente il frammento di contenuto.

L'URI di un frammento ha il formato che segue.

PageURI#ElementName

Di seguito viene illustrato un esempio di Hyperlink configurato per la navigazione su un frammento di contenuto.

<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

In questa sezione viene descritta l'implementazione della navigazione su un frammento predefinita in WPF.WPF consente anche di implementare uno schema di navigazione personalizzato che, in parte, richiede la gestione dell'evento NavigationService.FragmentNavigation.

Nota importanteImportante

È possibile spostarsi su frammenti contenuti in pagine XAML separate, ovvero file XAML solo markup aventi Page come elemento radice, soltanto se le pagine possono essere visualizzate tramite HTTP.

Tuttavia, una pagina XAML separata può eseguire una navigazione sui propri frammenti.

Servizio di navigazione

Mentre Hyperlink consente a un utente di avviare la navigazione su un particolare oggetto Page, l'individuazione e lo scaricamento della pagina vengono eseguiti dalla classe NavigationService. Essenzialmente, NavigationService consente di elaborare una richiesta di navigazione da parte del codice client, quale ad esempio Hyperlink. Inoltre, NavigationService implementa un supporto di livello superiore grazie al quale è possibile tenere traccia di una richiesta di navigazione nonché influenzare tale richiesta.

Facendo clic su Hyperlink, WPF chiama NavigationService.Navigate per individuare e scaricare l'oggetto Page nell'URI di tipo pack specificato. Una volta scaricato, Page viene convertito in una struttura ad albero di oggetti il cui oggetto radice è un'istanza del medesimo oggetto Page scaricato. Un riferimento all'oggetto Page radice viene archiviato nella proprietà NavigationService.Content. L'URI di tipo pack del contenuto sul quale ci si è spostati viene archiviato nella proprietà NavigationService.Source, mentre NavigationService.CurrentSource archivia l'URI di tipo pack dell'ultima pagina sulla quale è avvenuta la navigazione.

NotaNota

Un'applicazione WPF può avere più oggetti NavigationService attualmente attivi.Per ulteriori informazioni, vedere Host di navigazione più avanti in questo argomento.

Se la navigazione viene implementata in modo dichiarativo nel markup tramite Hyperlink, non occorre conoscere NavigationService in quanto Hyperlink utilizza NavigationService per conto dell'utente. Ciò significa che, se l'elemento padre diretto o indiretto di un oggetto Hyperlink è un host di navigazione (vedere Host di navigazione), Hyperlink sarà in grado di individuare e utilizzare il servizio di navigazione dell'host per elaborare una richiesta di navigazione.

In alcuni casi, tuttavia, è necessario utilizzare direttamente NavigationService. Di seguito vengono riportati alcuni di questi casi:

  • Per creare un'istanza di Page utilizzando un costruttore non predefinito.

  • Per impostare le proprietà di Page prima di spostarsi su di esso.

  • Quando l'oggetto Page sul quale ci si deve spostare può essere determinato solo in fase di esecuzione.

In questi casi è richiesta la scrittura di codice per avviare la navigazione a livello di codice mediante chiamata al metodo Navigate dell'oggetto NavigationService. A tal proposito è necessario ottenere un riferimento a NavigationService.

Ottenimento di un riferimento a NavigationService

Per ragioni analizzate nella sezione Host di navigazione, un'applicazione WPF può avere più oggetti NavigationService. Ciò significa che il codice necessita di un metodo per individuare un particolare oggetto NavigationService, in genere l'oggetto NavigationService che ha effettuato la navigazione sull'oggetto Page corrente. Per ottenere un riferimento a NavigationService, chiamare il metodo static NavigationService.GetNavigationService. Per ottenere l'oggetto NavigationService che ha effettuato la navigazione su un particolare oggetto Page, passare un riferimento a Page come argomento del metodo GetNavigationService. Nel codice riportato di seguito viene illustrato come ottenere NavigationService per l'oggetto Page corrente.

' 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);

Un'alternativa più rapida per la ricerca di NavigationService viene offerta da Page, il quale implementa la proprietà NavigationService, come illustrato nell'esempio che segue.

' 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

Page può ottenere un riferimento a NavigationService soltanto quando genera l'evento Loaded.

Nell'esempio seguente viene illustrato come utilizzare NavigationService per spostarsi a livello di codice su un oggetto Page. Si richiede la navigazione a livello di codice in quanto è possibile creare un'istanza dell'oggetto Page sul quale ci si sposta soltanto mediante un unico costruttore non predefinito. Nel markup e nel codice che seguono viene illustrato Page con il costruttore non predefinito.

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

Nel markup e nel codice che seguono viene illustrato l'oggetto Page che effettua la navigazione su Page con il costruttore non predefinito.

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

Facendo clic su Hyperlink nell'oggetto Page in questione, la navigazione viene avviata mediante creazione di un'istanza dell'oggetto Page sul quale ci si deve spostare tramite costruttore non predefinito e chiamata al metodo NavigationService.Navigate. Navigate accetta un riferimento all'oggetto sul quale si sposterà NavigationService, anziché un URI di tipo pack.

Per costruire un URI di tipo pack a livello di codice, ad esempio nel caso in cui sia possibile determinare l'URI di tipo pack unicamente in fase di esecuzione, è possibile utilizzare il metodo NavigationService.Navigate, come illustrato nell'esempio che segue.

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

Aggiornamento della pagina corrente

Page non viene scaricato se il relativo URI di tipo pack è equivalente all'URI archiviato nella proprietà NavigationService.Source. Per forzare WPF a scaricare nuovamente la pagina corrente, è possibile chiamare il metodo NavigationService.Refresh, come illustrato nell'esempio che segue.

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

Durata della navigazione

Come si è visto, esistono diversi modi per avviare una navigazione. Una volta avviata la navigazione e durante la relativa esecuzione è possibile tenerne traccia nonché influenzarla utilizzando gli eventi riportati di seguito, implementati da NavigationService:

  • Navigating. Si verifica quando viene richiesto una nuova navigazione. Può essere utilizzato per annullare la navigazione.

  • NavigationProgress. Si verifica periodicamente durante un download per fornire informazioni sullo stato di avanzamento della navigazione.

  • Navigated. Si verifica quando la pagina è stata individuata e scaricata.

  • NavigationStopped. Si verifica quando la navigazione viene interrotta mediante una chiamata a StopLoading oppure quando viene richiesto una nuova navigazione mentre quella corrente è ancora in corso.

  • NavigationFailed. Si verifica quando viene generato un errore durante la navigazione sul contenuto richiesto.

  • LoadCompleted. Si verifica quando il contenuto sul quale ci si è spostati è stato caricato e analizzato ed è iniziata l'esecuzione del rendering.

  • FragmentNavigation. Si verifica quando inizia la navigazione su un frammento di contenuto; tale navigazione avviene:

    • Immediatamente, se il frammento desiderato si trova nel contenuto corrente.

    • Una volta caricato il contenuto di origine, se il frammento desiderato si trova in un contenuto diverso.

Gli eventi di navigazione vengono generati nell'ordine illustrato nella figura che segue.

Grafico del flusso di spostamento nella pagina

In genere questi eventi non riguardano Page. È più probabile che interessino un'applicazione e, per tale ragione, vengono generati anche dalla classe Application:

Ogni qualvolta NavigationService genera un evento, la classe Application genera l'evento corrispondente. Frame e NavigationWindow offrono gli stessi eventi per rilevare la navigazione all'interno dei rispettivi ambiti.

In alcuni casi è possibile che questi eventi interessino Page. Ad esempio, Page può gestire l'evento NavigationService.Navigating per determinare se annullare o meno la navigazione da se stesso, come illustrato nell'esempio che segue.

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

Nel caso in cui venga registrato un gestore con un evento di navigazione da Page, come avviene nell'esempio precedente, occorre anche annullare la registrazione del gestore eventi. In caso contrario, potrebbero esserci effetti collaterali circa il modo in cui WPF memorizza la navigazione da Page mediante il journal.

Memorizzazione della navigazione mediante journal

WPF utilizza due stack per memorizzare le pagine dalle quali ci si è spostati: uno stack indietro e uno stack avanti. Quando si effettua la navigazione dall'oggetto Page corrente a un nuovo oggetto Page oppure quando ci si sposta in avanti su un oggetto Page esistente, l'oggetto Page corrente viene aggiunto allo stack indietro. Quando si effettua la navigazione dall'oggetto Page corrente all'oggetto Page precedente, l'oggetto Page corrente viene aggiunto allo stack avanti. Lo stack indietro, lo stack avanti e la funzionalità di gestione degli stack vengono complessivamente definiti come il journal. Ogni elemento contenuto nello stack indietro e nello stack avanti è un'istanza della classe JournalEntry e viene definito voce del journal.

Dal punto di vista concettuale, il journal funziona esattamente come i pulsanti Indietro e Avanti di Internet Explorer, illustrati nella figura che segue.

Pulsanti Back e Forward

Nel caso delle applicazioni XBAPs ospitate da Internet Explorer, WPF integra il journal nell'UI di navigazione di Internet Explorer. In questo modo gli utenti possono spostarsi sulle pagine di un'applicazione XBAP utilizzando i pulsanti Indietro, Avanti e Pagine recenti di Internet Explorer. Per quanto concerne Microsoft Internet Explorer 6, il journal non viene integrato allo stesso modo di Internet Explorer 7 o Internet Explorer 8. Al contrario, WPF esegue il rendering di un'UI di navigazione sostitutiva.

Nota importanteImportante

Nel caso di Internet Explorer, se un utente si sposta da un'applicazione XBAP e poi vi fa ritorno, nel journal vengono conservate soltanto le voci relative alle pagine che non sono state mantenute attive.Per informazioni su come mantenere attive le pagine, vedere Durata della pagina e journal più avanti in questo argomento.

Per impostazione predefinita, il testo relativo a ogni oggetto Page visualizzato nell'elenco Pagine recenti di Internet Explorer è equivalente all'URI di Page. In diversi casi questo testo non risulta molto significativo agli occhi dell'utente. Fortunatamente è possibile modificarlo utilizzando una delle seguenti opzioni:

  1. Il valore dell'attributo JournalEntry.Name associato.

  2. Il valore dell'attributo Page.Title.

  3. Il valore dell'attributo Page.WindowTitle e l'URI dell'oggetto Page corrente.

  4. L'URI dell'oggetto Page corrente (Valore predefinito)

L'ordine nel quale sono elencate le opzioni corrisponde all'ordine di precedenza utilizzato per cercare il testo. Se ad esempio JournalEntry.Name è impostato, gli altri valori vengono ignorati.

Nell'esempio che segue viene utilizzato l'attributo Page.Title per modificare il testo visualizzato per una voce del journal.

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


...


    }
}

Benché sia possibile spostarsi nel journal utilizzando i pulsanti Indietro, Avanti e Pagine recenti di Internet Explorer, è anche possibile effettuare la stessa operazione tramite meccanismi dichiarativi e a livello di codice forniti da WPF. Questo metodo può essere utilizzato, ad esempio, per fornire UIs di navigazione personalizzate nelle pagine.

Per aggiungere in modo dichiarativo un supporto per la navigazione nel journal, è possibile utilizzare i comandi di navigazione esposti da NavigationCommands. Nell'esempio che segue viene illustrato come utilizzare il comando di navigazione 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>

Per spostarsi nel journal a livello di codice, è possibile utilizzare uno dei seguenti membri della classe NavigationService:

Il journal può anche essere modificato a livello di codice, come illustrato in Mantenimento dello stato del contenuto mediante cronologia di navigazione più avanti in questo argomento.

Durata della pagina e journal

Si consideri un'applicazione XBAP con diverse pagine che includono un contenuto complesso, ad esempio grafici, animazioni e contenuti multimediali. Il footprint di memoria per pagine simili può essere piuttosto grande, in particolare se vengono utilizzati contenuti audio e video. Considerando il fatto che il journal "memorizza" le pagine sulle quali ci si è spostati, un'applicazione XBAP di questo tipo potrebbe utilizzare rapidamente una notevole quantità di memoria.

Per questa ragione, il comportamento predefinito del journal prevede l'archiviazione dei metadati di Page in ciascuna voce del journal anziché di un riferimento a un oggetto Page. Quando ci si sposta su una voce del journal, i metadati di Page vengono utilizzati per creare una nuova istanza dell'oggetto Page specificato. Di conseguenza, ogni oggetto Page sul quale si effettua la navigazione possiede la durata illustrata nella figura che segue.

Durata delle pagine

Benché l'utilizzo del comportamento di inserimento nel journal predefinito consenta di ridurre il consumo di memoria, è possibile che anche le prestazioni di rendering delle singole pagine vengano ridotte. La creazione di una nuova istanza di Page può richiedere molto tempo, in particolare se è presente una grande quantità di contenuto. Per conservare un'istanza di Page nel journal, è possibile sfruttare due tecniche diverse. Primo, è possibile spostarsi a livello di codice su un oggetto Page mediante una chiamata al metodo NavigationService.Navigate.

Secondo, è possibile fare in modo che WPF conservi un'istanza di Page nel journal impostando la proprietà KeepAlive su true (l'impostazione predefinita è false). Come illustrato nell'esempio che segue, KeepAlive può essere impostata in modo dichiarativo nel markup.

<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 durata di un oggetto Page mantenuto attivo è leggermente diversa rispetto agli altri oggetti. La prima volta in cui si effettua la navigazione su un oggetto Page mantenuto attivo, ne viene creata un'istanza proprio come avviene per gli oggetti Page che non vengono mantenuti attivi. Tuttavia, poiché nel journal viene conservata un'istanza di Page, non sarà più necessario creare nuove istanze dello stesso fintanto che tale istanza resterà nel journal. Di conseguenza, nel caso in cui Page possieda una logica di inizializzazione che deve essere chiamata ogni qualvolta ci si sposta sull'oggetto in questione, sarebbe opportuno spostarlo dal costruttore in un gestore per l'evento Loaded. Come illustrato nella figura che segue, gli eventi Loaded e Unloaded vengono tuttora generati ogni qualvolta avviene la navigazione rispettivamente su o da Page.

Generazione di eventi Loaded e Unloaded

Quando Page non viene mantenuto attivo, occorre evitare di:

  • Archiviare un riferimento all'oggetto o parte di esso.

  • Registrare gestori eventi con eventi che non siano implementati dall'oggetto.

In caso contrario verrebbero creati riferimenti in base ai quali Page verrebbe conservato in memoria anche dopo essere stato rimosso dal journal.

In genere si preferisce il comportamento predefinito per cui Page non viene mantenuto attivo. Ciò comporta tuttavia implicazioni sullo stato, che verranno trattate nella sezione successiva.

Mantenimento dello stato del contenuto mediante cronologia di navigazione

Se un oggetto Page dotato di controlli per la raccolta di dati dall'utente non viene mantenuto attivo, cosa accade ai dati nel momento in cui ci si sposta da tale oggetto per poi farvi nuovamente ritorno? Dal punto di vista dell'esperienza utente, ci si potrebbe aspettare di visualizzare i dati immessi in precedenza. Sfortunatamente, a ogni navigazione viene creata una nuova istanza di Page e di conseguenza anche dei controlli di raccolta dei dati, pertanto i dati immessi vengono persi.

Il journal fornisce però un supporto per la memorizzazione dei dati, inclusi quelli dei controlli, durante la navigazione da un oggetto Page all'altro. Nello specifico, la voce del journal per ogni oggetto Page funge da contenitore temporaneo per lo stato dell'oggetto Page associato. Nella procedura che segue viene illustrato l'utilizzo di questo supporto in caso di navigazione da Page:

  1. Una voce per l'oggetto Page corrente viene aggiunta al journal.

  2. Lo stato di Page viene archiviato con la voce del journal relativa alla pagina in questione, la quale viene aggiunta allo stack indietro.

  3. Viene effettuato la navigazione sul nuovo oggetto Page.

Quando si torna sull'oggetto Page precedente utilizzando il journal, avviene quanto segue:

  1. Viene creata un'istanza di Page, ossia della prima voce del journal nello stack indietro.

  2. Page viene aggiornato con lo stato archiviato nella voce del journal corrispondente.

  3. Ci si sposta nuovamente su Page.

WPF utilizza automaticamente questo supporto quando in Page vengono utilizzati i seguenti controlli:

Se Page utilizza questi controlli, i dati immessi al loro interno vengono memorizzati tra una navigazione e l'altra, come illustrato dall'oggetto ListBox Favorite Color nella figura che segue.

Pagina con controlli che memorizzano lo stato

Quando Page possiede controlli diversi da quelli precedentemente elencati oppure quando lo stato viene archiviato in oggetti personalizzati, è necessario scrivere codice per fare in modo che il journal memorizzi lo stato durante le navigazioni da un oggetto Page all'altro.

Per memorizzare stati di piccole dimensioni durante le navigazioni da un oggetto Page all'altro, è possibile utilizzare le proprietà di dipendenza (vedere DependencyProperty) configurate con il flag di metadati FrameworkPropertyMetadata.Journal.

Se lo stato che deve essere memorizzato da Page tra le varie navigazioni comprende più dati, potrebbe risultare più semplice a livello di codice incapsularlo in un'unica classe e implementare l'interfaccia IProvideCustomContentState.

Per spostarsi tra diversi stati di un unico oggetto Page senza però spostarsi da Page, è possibile utilizzare IProvideCustomContentState e NavigationService.AddBackEntry.

Un altro metodo di archiviazione dei dati per le applicazioni WPF consiste nell'utilizzo dei cookie, i quali vengono creati, aggiornati ed eliminati utilizzando i metodi SetCookie e GetCookie. I cookie che è possibile creare in WPF sono gli stessi cookie utilizzati da altri tipi di applicazioni Web. I cookie sono dati arbitrari che vengono archiviati da un'applicazione su un computer client durante una sessione dell'applicazione o tra una sessione e l'altra. I dati dei cookie assumono in genere la forma di una coppia nome/valore nel formato che segue.

Nome=Valore

Quando i dati vengono passati a SetCookie, insieme all'oggetto Uri del percorso per il quale il cookie deve essere impostato, viene creato un cookie in memoria, il quale sarà disponibile soltanto per la durata della sessione dell'applicazione corrente. Questo tipo di cookie viene definito cookie di sessione.

Per archiviare un cookie tra una sessione e l'altra dell'applicazione, occorre aggiungervi una data di scadenza utilizzando il formato che segue.

N0ME=VALORE; expires=DAY, DD-MMM-YYYY HH:MM:SS GMT

Un cookie con una data di scadenza viene archiviato nella cartella dei file temporanei Internet dell'installazione di Windows corrente fino alla scadenza. Questo tipo di cookie viene definito cookie permanente in quanto permane tra una sessione e l'altra dell'applicazione.

Per recuperare i cookie di sessione e permanenti, chiamare il metodo GetCookie e passare l'oggetto Uri del percorso in cui è stato impostato il cookie con il metodo SetCookie.

Di seguito vengono elencati alcuni tipi di supporto dei cookie in WPF:

  • Le applicazioni autonome WPF e le applicazioni XBAPs possono creare e gestire i cookie.

  • I cookie creati da un'applicazione XBAP sono accessibili dal browser.

  • Le applicazioni XBAPs appartenenti allo stesso dominio possono creare e condividere i cookie.

  • Le applicazioni XBAPs e le pagine HTML appartenenti allo stesso dominio possono creare e condividere i cookie.

  • I cookie vengono inviati quando le applicazioni XBAPs e le pagine XAML separate effettuano richieste Web.

  • Sia le applicazioni XBAPs di livello superiore che le applicazioni XBAPs ospitate in IFRAMES possono accedere ai cookie.

  • Il supporto dei cookie in WPF è lo stesso per tutti i browser supportati.

  • In Internet Explorer WPF applica i criteri P3P pertinenti ai cookie, con particolare riferimento alle applicazioni XBAPs del produttore e di terze parti.

I dati possono essere passati da un oggetto Page a un altro sotto forma di argomenti, mediante passaggio a un costruttore non predefinito di Page. In caso di utilizzo di questa tecnica, è necessario mantenere attivo Page; in caso contrario, nel momento in cui ci si sposta nuovamente su Page, WPF ne crea una nuova istanza utilizzando il costruttore predefinito.

In alternativa, Page può implementare proprietà impostate con i dati che devono essere passati. La situazione si complica, tuttavia, quando Page deve passare nuovamente i dati all'oggetto Page che ha effettuata la navigazione su di esso. Il problema è che, a livello nativo, la navigazione non supporta alcun meccanismo in grado di garantire che, una volta effettuata una navigazione da Page, si tornerà nuovamente su tale oggetto. In pratica, la navigazione non supporta la semantica di tipo chiamata/ritorno. Per risolvere questo problema WPF fornisce la classe PageFunction<T>, utilizzabile per garantire il ritorno su Page in modo prevedibile e strutturato. Per ulteriori informazioni, vedere Cenni preliminari sulla navigazione strutturata.

Classe NavigationWindow

Fino a questo punto sono stati analizzati i servizi di navigazione utilizzati più di frequente per compilare applicazioni con contenuto navigabile. Tali servizi sono stati trattati nel contesto delle applicazioni XBAPs, benché non siano limitati alle applicazioni XBAPs. Le applicazioni Windows e i sistemi operativi moderni sfruttano l'esperienza utente del browser per incorporare una navigazione di tipo browser nelle applicazioni autonome. Di seguito vengono riportati alcuni esempi comuni:

  • Thesaurus di Word: navigazione sui diversi vocaboli.

  • Esplora file: navigazione su file e cartelle.

  • Procedure guidate: suddivisione di un'attività complessa in più pagine tra le quali è possibile spostarsi. Un esempio è dato dall'Aggiunta guidata componenti di Windows, che consente di gestire l'aggiunta e la rimozione delle funzionalità di Windows.

Per incorporare una navigazione di tipo browser nelle applicazioni autonome, è possibile utilizzare la classe NavigationWindow. NavigationWindow deriva da Window e lo estende con lo stesso supporto per la navigazione fornito dalle applicazioni XBAPs. È possibile utilizzare NavigationWindow come finestra principale dell'applicazione autonoma oppure come finestra secondaria, quale ad esempio una finestra di dialogo.

L'implementazione di NavigationWindow, analogamente a quanto avviene con la maggior parte delle classi di livello superiore in WPF (Window, Page e così via), richiede l'utilizzo di una combinazione di markup e code-behind, come illustrato nell'esempio che segue.

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

Questo codice crea un oggetto NavigationWindow il quale, nel momento in cui viene aperto, si sposta automaticamente su Page (HomePage.xaml). Se NavigationWindow è la finestra principale dell'applicazione, è possibile utilizzare l'attributo StartupUri per l'avvio, come illustrato nel markup che segue.

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

Nella figura riportata di seguito viene illustrato NavigationWindow come finestra principale di un'applicazione autonoma.

Finestra principale

Dalla figura risulta evidente che NavigationWindow possiede un titolo, benché questo non sia stato impostato nel relativo codice di implementazione riportato nell'esempio precedente. In questo caso il titolo viene impostato utilizzando la proprietà WindowTitle, illustrata nel codice che segue.

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


...


</Page>

Anche l'impostazione delle proprietà WindowWidth e WindowHeight influisce su NavigationWindow.

In genere si implementa un oggetto NavigationWindow personalizzato quando si desidera personalizzarne il comportamento o l'aspetto. Se tutto ciò non fosse necessario, è possibile utilizzare un'alternativa più rapida. Se si specifica l'URI di tipo pack di Page come StartupUri in un'applicazione autonoma, Application crea automaticamente NavigationWindow per ospitare Page. Nel markup che segue viene illustrata la procedura necessaria in proposito.

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

Per fare in modo che una finestra secondaria dell'applicazione, ad esempio una finestra di dialogo, sia un oggetto NavigationWindow, è possibile aprire tale finestra utilizzando il codice riportato nell'esempio che segue.

            ' 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();

Nella figura riportata di seguito viene illustrato il risultato.

finestra di dialogo

Come si può notare, NavigationWindow visualizza pulsanti Indietro e Avanti di tipo Internet Explorer che consentono agli utenti di spostarsi nel journal. L'esperienza utente è la stessa, come illustrato nella figura che segue.

Pulsanti Back e Forward in NavigationWindow

Se le pagine forniscono un supporto e un'interfaccia utente personalizzati per la navigazione nel journal, è possibile nascondere i pulsanti Indietro e Avanti visualizzati da NavigationWindow impostando il valore della proprietà ShowsNavigationUI su false.

In alternativa, è possibile utilizzare il supporto per la personalizzazione in WPF per sostituire l'UI di NavigationWindow.

Classe Frame

Sia il browser che NavigationWindow sono finestre che ospitano contenuto navigabile. In alcuni casi, il contenuto delle applicazioni non deve essere necessariamente ospitato da un'intera finestra. Al contrario, tale contenuto può essere ospitato in altro contenuto. Per inserire contenuto navigabile in altro contenuto, utilizzare la classe Frame, la quale fornisce lo stesso supporto di NavigationWindow e XBAPs.

Nell'esempio riportato di seguito viene illustrato come aggiungere Frame a Page in modo dichiarativo, utilizzando l'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>

Questo markup imposta l'attributo Source dell'elemento Frame con un URI di tipo pack per l'oggetto Page sul quale Frame deve inizialmente spostarsi. Nella figura seguente viene illustrata un'applicazione XBAP con un oggetto Page che possiede a sua volta un oggetto Frame che si è spostato tra più pagine.

Frame che ha eseguito lo spostamento tra più pagine

Frame non deve essere utilizzato soltanto all'interno del contenuto di Page. Spesso Frame viene anche ospitato all'interno del contenuto di Window.

Per impostazione predefinita, Frame utilizza un journal personalizzato soltanto in assenza di un altro journal. Se Frame fa parte di un contenuto ospitato all'interno di NavigationWindow o di un'applicazione XBAP, Frame utilizza il journal appartenente a NavigationWindow o all'applicazione XBAP. Talvolta però è necessario che Frame gestisca un journal personalizzato. Una ragione potrebbe essere la necessità di consentire la navigazione nel journal all'interno delle pagine ospitate da Frame, come illustrato nella figura che segue.

Diagramma di pagine e frame

In questo caso, è possibile configurare Frame per l'utilizzo di un journal personalizzato impostando la proprietà JournalOwnership di Frame su OwnsJournal, come illustrato nel markup che segue.

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

Nella figura seguente viene illustrato l'effetto della navigazione all'interno di un oggetto Frame che utilizza un journal personalizzato.

Frame che utilizza il proprio journal

Le voci del journal vengono visualizzate dall'UI di navigazione di Frame anziché da Internet Explorer.

NotaNota

Se Frame fa parte di un contenuto ospitato in Window, Frame utilizza un journal personalizzato e, di conseguenza, visualizza un'UI di navigazione personalizzata.

Se l'esperienza utente lo richiede, è possibile fare in modo che Frame fornisca un journal personalizzato senza visualizzare l'UI di navigazione, nascondendo l'UI mediante impostazione di NavigationUIVisibility su Hidden, come illustrato nel markup che segue.

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

Host di navigazione

Frame e NavigationWindow sono classi note come host di navigazione. Un host di navigazione è una classe in grado di spostarsi su un contenuto e visualizzarlo. A tal proposito, ogni host di navigazione utilizza NavigationService e journal personalizzati. Nella figura che segue viene illustrata la costruzione di base di un host di navigazione.

Diagrammi di spostamento

Essenzialmente, questa costruzione consente a NavigationWindow e a Frame di fornire lo stesso supporto per la navigazione fornito da un'applicazione XBAP ospitata nel browser.

Oltre a utilizzare NavigationService e un journal, gli host di navigazione implementano gli stessi membri implementati da NavigationService, come illustrato nella figura che segue.

Journal in Frame e in NavigationWindow

Ciò consente di programmare un supporto specifico per la navigazione. È bene tenere presente quanto detto nel caso in cui si desideri fornire un'UI di navigazione personalizzata per un oggetto Frame ospitato in Window. Entrambi i tipi inoltre implementano membri aggiuntivi, correlati alla navigazione, tra cui BackStack (NavigationWindow.BackStack, Frame.BackStack) e ForwardStack (NavigationWindow.ForwardStack, Frame.ForwardStack), che consentono di enumerare le voci del journal rispettivamente nello stack indietro e nello stack avanti.

Come detto in precedenza, all'interno di un'applicazione possono essere presenti più journal. Nella figura seguente viene fornito un esempio in proposito.

Più journal in un'applicazione

In questo argomento sono stati utilizzati Page e le applicazioni XBAPs di tipo pack per illustrare le varie funzionalità di navigazione di WPF. Tuttavia, un oggetto Page compilato in un'applicazione non è l'unico tipo di contenuto sul quale ci si può spostare, così come le applicazioni XBAPs di tipo pack non rappresentano l'unico modo per identificare il contenuto.

Come illustrato in questa sezione, è anche possibile spostarsi su file XAML separati, file HTML e oggetti.

Un file XAML separato è un file con le seguenti caratteristiche:

  • Contiene solo XAML e non codice.

  • Possiede una dichiarazione dello spazio dei nomi appropriata.

  • Possiede l'estensione XAML.

Si consideri ad esempio il contenuto seguente archiviato come file XAML separato, 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>

Facendo doppio clic sul file, il browser si apre e si sposta sul contenuto visualizzandolo, come illustrato nella figura che segue.

Visualizzazione del contenuto del file Person.XAML

È possibile visualizzare un file XAML separato da:

  • Un sito Web sul computer locale, Intranet o Internet.

  • Una condivisione file Universal Naming Convention (UNC).

  • Il disco locale.

Un file XAML separato può essere aggiunto all'elenco Preferiti del browser oppure può essere la pagina iniziale del browser.

NotaNota

Per ulteriori informazioni sulla pubblicazione e l'avvio di pagine XAML separate, vedere Distribuzione di un'applicazione WPF (WPF).

XAML separato comporta una limitazione, ossia consente di ospitare solo contenuto eseguibile senza rischi in attendibilità parziale. Ad esempio, Window non può essere l'elemento radice di un file XAML separato. Per ulteriori informazioni, vedere Sicurezza con attendibilità parziale in WPF.

Come previsto, è anche possibile spostarsi su file HTML. Occorre semplicemente fornire un URI che utilizza lo schema HTTP. Ad esempio, nel seguente codice XAML viene illustrato un oggetto Frame che si sposta su una pagina HTML.

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

La navigazione su HTML necessita di particolari autorizzazioni. Non è ad esempio possibile effettuare la navigazione da un'applicazione XBAP in esecuzione nella sandbox di sicurezza con attendibilità parziale dell'area Internet. Per ulteriori informazioni, vedere Sicurezza con attendibilità parziale in WPF.

Il controllo WebBrowser supporta l'hosting di documenti HTML, la navigazione e l'interoperabilità fra script e codice gestito. Per informazioni dettagliate sul controllo WebBrowser, vedere WebBrowser.

Come per Frame, la navigazione a HTML utilizzando WebBrowser richiede autorizzazioni speciali. Ad esempio, da un'applicazione parzialmente attendibile, è possibile passare solo a HTML ubicato presso il sito di origine. Per ulteriori informazioni, vedere Sicurezza con attendibilità parziale in WPF.

Per visualizzare dati archiviati come oggetti personalizzati, è possibile creare un oggetto Page con un contenuto associato a tali oggetti (vedere Cenni preliminari sull'associazione dati). Se invece si preferisce evitare di creare un'intera pagina al solo scopo di visualizzare gli oggetti, è possibile spostarsi direttamente su di essi.

Si consideri la classe Person implementata nel codice che segue.


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

Per spostarsi su di essa, chiamare il metodo NavigationWindow.Navigate, come illustrato nel codice che segue.

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

Nella figura riportata di seguito viene illustrato il risultato.

Pagina che si sposta su una classe

Da questa figura risulta evidente come non vengano visualizzati elementi utili. Infatti, il valore visualizzato è il valore restituito del metodo ToString per l'oggetto Person. Per impostazione predefinita, questo è l'unico valore utilizzabile da WPF per rappresentare l'oggetto. È possibile eseguire l'override del metodo ToString per restituire informazioni più significative, benché si ottenga comunque un valore stringa. Una tecnica che sfrutta le funzionalità di presentazione di WPF consiste nell'utilizzo di un modello di dati. È possibile implementare un modello di dati che verrà associato da WPF a un oggetto di un particolare tipo. Nel codice riportato di seguito viene illustrato un modello di dati per l'oggetto 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>

In questo caso il modello di dati viene associato al tipo Person utilizzando l'estensione di markup x:Type nell'attributo DataType. Il modello di dati associa quindi gli elementi TextBlock (vedere TextBlock) alle proprietà della classe Person. Nella figura seguente viene illustrato l'aspetto aggiornato dell'oggetto Person.

Spostamento su una classe che ha un modello di dati

Un vantaggio di questa tecnica è dato dalla coerenza: il modello di dati può infatti essere riutilizzato per visualizzare gli oggetti in modo coerente nell'intero ambito dell'applicazione.

Per ulteriori informazioni sui modelli di dati, vedere Cenni preliminari sui modelli di dati.

Sicurezza

Il supporto per la navigazione di WPF consente di spostarsi sulle applicazioni XBAPs attraverso Internet. Grazie a questo supporto, inoltre, le applicazioni possono ospitare contenuto di terze parti. Per proteggere le applicazioni e gli utenti da comportamenti dannosi, WPF fornisce diverse funzionalità di sicurezza, illustrate in Sicurezza (WPF) e Sicurezza con attendibilità parziale in WPF.

Vedere anche

Riferimenti

SetCookie

GetCookie

Concetti

Cenni preliminari sulla gestione di applicazioni

URI di tipo pack in WPF

Cenni preliminari sulla navigazione strutturata

Cenni preliminari sulle topologie di navigazione

Distribuzione di un'applicazione WPF (WPF)

Altre risorse

Argomenti sulle procedure relative alla navigazione