Общие сведения о переходах

Windows Presentation Foundation (WPF) поддерживает навигацию в стиле браузера, которая может использоваться в приложениях двух типов: автономных приложениях и XAML browser applications (XBAPs). Чтобы упаковать содержимое для навигации, WPF предоставляет класс Page. Можно переходить от одного класса Page к другому декларативным способом, с использованием объекта Hyperlink, или программным способом, с использованием объекта NavigationService. Приложение WPF использует журнал, чтобы запоминать страницы, с которых был осуществлен переход, и чтобы переходить к ним обратно.

Page, Hyperlink NavigationService и журнал образуют основу для предоставляемой WPF поддержки переходов. В данном обзоре подробно анализируются эти особенности перед описанием расширенной поддержки переходов, которая включает переход к свободным файлам Extensible Application Markup Language (XAML), файлам HTML и объектам.

ПримечаниеПримечание

В этом разделе термин "браузер" относится только к браузерам, в которых можно размещать приложения WPF. В настоящее время к этим браузерам относятся Microsoft Internet Explorer и Firefox.В случае, когда специфические компоненты WPF поддерживаются только одним определенным браузером, указывается версия браузера.

В этом разделе содержатся следующие подразделы.

  • Переходы в приложениях WPF
  • Класс NavigationWindow
  • Класс фрейм
  • узлы переходов
  • Переход к содержимому, отличному от страниц XAML
  • Безопасность
  • Связанные разделы

Переходы в приложениях WPF

В этом разделе дается обзор основных возможностей перехода в WPF. Эти возможности доступны как для автономных приложений, так и для XBAPs, хотя в этом разделе они представлены в контексте XBAP.

ПримечаниеПримечание

В этом разделе не обсуждается построение и развертывание XBAPs.Дополнительные сведения о XBAPs см. в разделе Общие сведения о приложениях браузера WPF XAML.

В этом разделе объясняются и демонстрируются следующие аспекты переходов:

  • Реализация страницы

  • Настройка домашней страницы

  • Настройка заголовка, ширины и высоты основного окна

  • Переход по гиперссылке

  • Переход к фрагменту

  • Служба переходов

  • Программный переход с помощью службы переходов

  • Время существования перехода

  • Запоминание перехода в журнале

  • Время существования страницы и журнал

  • Сохранение состояния содержимого с помощью журнала переходов

  • Файлы Cookie

  • Структурная навигация

Реализация страницы

В WPF можно перейти к нескольким типам содержимого, включающего объекты .NET Framework, пользовательские объекты, значения перечисления, пользовательские элементы управления, файлы XAML и файлы HTML. Однако наиболее распространенным и удобным способом упаковки содержимого является использование Page. Более того, Page реализует особые возможности перехода в целях улучшения их внешнего вида и упрощения разработки.

С помощью Page можно декларативно реализовать доступную для перехода страницу содержимого XAML, используя разметку так, как показано на рисунке.

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

Класс Page, реализованный в разметке XAML, содержит Page в качестве корневого элемента и требует объявления пространства имен XML WPF. В элементе Page находится содержимое, к которому требуется перейти и отобразить. Для добавления содержимого задается свойство Page.Content элемента, как показано в следующем примере разметки.

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

Page.Content может содержать только один дочерний элемент; как предложено в предыдущем примере, содержимым является отдельная строка "Привет, Страница!". На практике в качестве дочернего элемента для создания и хранения нужного содержимого обычно используется элемент управления макета (см. раздел Система макета).

Дочерние элементы элемента Page считаются содержимым класса Page и, следовательно, нет необходимости использовать явное объявление Page.Content. Следующая разметка является декларативным эквивалентом предыдущего примера.

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

В этом случае Page.Content автоматически задается вместе с дочерними элементами элемента Page. Дополнительные сведения см. в разделе Модель содержимого WPF.

Класс Page (только для разметки) используется для отображения содержимого. Однако Page может также отображать элементы управления, позволяющие пользователям взаимодействовать со страницей, и может отвечать на действия пользователя, выполняя обработку событий и вызывая логику приложения. Интерактивный класс Page реализован с помощью комбинации разметки и кода программной части, как показано в следующем примере.

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

Чтобы разрешить совместную работу файла разметки и файла кода программной части, требуется следующая конфигурация:

  • В разметке элемент Page должен включать атрибут x:Class. При построении приложения существование x:Class в файле разметки приводит к тому, что Microsoft build engine (MSBuild) создает класс partial, который является производным от Page и имя которого определяется атрибутом x:Class. Для этого требуется добавить объявление пространства имен XML в схему XAML (xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"). Созданный класс partial реализует InitializeComponent, который вызывается для регистрации событий и задания свойств, реализованных в разметке.

  • В коде программной части класс должен быть классом partial с тем же именем, которое определено атрибутом x:Class в разметке, и он должен быть производным от Page. Это позволяет связать файл кода программной части с классом partial, созданным для файла разметки при построении приложения (см. раздел Построение приложения WPF).

  • В коде программной части класс Page должен реализовать конструктор, вызывающий метод InitializeComponent. Метод InitializeComponent реализуется классом partial, созданным файлом разметки, для регистрации событий и задания свойств, определенных в разметке.

ПримечаниеПримечание

Когда в проект добавляется новый класс Page с помощью Microsoft Visual Studio, Page реализуется с помощью разметки и кода программной части и включает необходимую конфигурацию для создания связи между файлами разметки и файлами кода программной части.

После получения класса Page к нему можно перейти. Чтобы указать первый объект Page, к которому переходит приложение, необходимо настроить домашнюю страницу Page.

Настройка домашней страницы

Для XBAPs требуется определенная инфраструктура приложений, размещенных в браузере. В WPF класс Application является частью определения приложения, которое устанавливает необходимую инфраструктуру приложений (см. раздел Общие сведения об управлении приложением).

Определение приложения обычно реализуется с помощью разметки и кода программной части, причем файл разметки настраивается как элемент ApplicationDefinition системы MSBuild. Ниже приводится определение приложения для 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 { }
}

XBAP может использовать определение приложения, чтобы указать начальный объект Page, представляющий собой Page, автоматически загружаемую при запуске XBAP. Для этого задайте свойство StartupUri со значением uniform resource identifier (URI) для нужной Page.

ПримечаниеПримечание

В большинстве случаев Page либо компилируется в приложение, либо развертывается вместе с ним.В этих случаях URI, определяющий Page, является URI типа "pack", который представляет собой URI, соответствующий схеме pack.URIs типа "pack" обсуждаются далее в разделе URI типа "pack" в WPF. Для перехода к содержимому можно также использовать схему HTTP, которая рассматривается далее.

Можно задать StartupUri декларативно в разметке, как показано в следующем примере.

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

В этом примере атрибут StartupUri задается с относительным URI типа "pack", определяющим HomePage.xaml. При запуске XBAP автоматически осуществляется переход и отображение HomePage.xaml. Это продемонстрировано на приведенном ниже рисунке, который показывает приложение XBAP, запущенное с веб-сервера.

XBAP-страница

ПримечаниеПримечание

Дополнительные сведения о разработке и развертывании XBAPs см. в разделах Общие сведения о приложениях браузера WPF XAML и Развертывание приложений WPF.

Настройка заголовка, ширины и высоты основного окна

В предыдущем примере можно заметить, что заголовком как браузера, так и панели вкладок является URI для XBAP. Заголовок не только длинный, но также не является ни привлекательным, ни информативным. По этой причине Page предлагает способ для изменения заголовка с помощью задания свойства WindowTitle. Более того, можно настроить ширину и высоту окна браузера, задав свойства WindowWidth и WindowHeight соответственно.

Свойства WindowTitle,WindowWidth и WindowHeight могут быть заданы декларативно в разметке, как показано в следующем примере.

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

Результат показан на следующем рисунке.

Название окна, высота, ширина

Переход по гиперссылке

Обычно XBAP состоит из нескольких страниц. Самый простой способ перехода от одной страницы к другой заключается в использовании объекта Hyperlink. Можно декларативно добавить Hyperlink в Page, используя элемент Hyperlink, показанный в следующем примере разметки.

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

Для элемента Hyperlink необходимо следующее:

  • URI типа "pack" из Page для перехода, заданный атрибутом NavigateUri.

  • Содержимое, которое пользователь может щелкнуть для инициации перехода, например текст и изображения (содержимое, которое может содержать элемент Hyperlink, см. в разделе Hyperlink).

На следующем рисунке показано XBAP с объектом Page, содержащим Hyperlink.

Страница с гиперссылкой

Как и следовало ожидать, если щелкнуть Hyperlink, вызывается XBAP для перехода к объекту Page, определяемому атрибутом NavigateUri. Кроме того, XBAP добавляет вход для предыдущего объекта Page в список последних страниц в Internet Explorer. Это показано на следующем рисунке.

Кнопки “Дальше” и “Назад”

Помимо поддержки перехода от одной Page к другой, Hyperlink также поддерживает переход к фрагменту.

Переход к фрагменту

Переход к фрагменту — это переход к фрагменту содержимого в текущей Page или другой Page. В WPF фрагмент содержимого представляет собой данные, содержащиеся в именованном элементе. Именованный элемент — это элемент с набором атрибутов Name. В следующей разметке показан именованный элемент TextBlock, включающий фрагмент содержимого.

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

Для перехода по Hyperlink к фрагменту содержимого атрибут NavigateUri должен включать следующее:

  • URI из Page с фрагментом содержимого для перехода.

  • Символ "#".

  • Имя элемента в объекте Page, включающего фрагмент содержимого.

Фрагмент URI имеет следующий формат.

URI_страницы#имя_элемента

Ниже показан пример Hyperlink, настроенной на переход к фрагменту содержимого.

<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>
ПримечаниеПримечание

Этот раздел описывает реализацию переходов фрагмента по умолчанию в приложение WPF.WPF также позволяет реализовать собственную схему переходов фрагмента, которая отчасти требует обработки события NavigationService.FragmentNavigation.

Важное примечаниеВажно

Можно перейти к фрагменту свободных страниц XAML (файлы XAML только для разметки с Page в качестве корневого элемента), если только страницы можно просмотреть с помощью HTTP.

Однако свободная страница XAML может поддерживать переходы на свои собственные фрагменты.

Служба переходов

Тогда как Hyperlink позволяет пользователю инициировать переход к конкретной Page, работа по поиску и загрузке страницы выполняется с помощью класса NavigationService. По существу NavigationService предоставляет возможность обработки запроса перехода со стороны кода клиента, например Hyperlink. Кроме того, NavigationService реализует поддержку более высокого уровня для отслеживания запроса перехода и влияния на него.

Если щелкнуть Hyperlink WPF, вызывается NavigationService.Navigate для обнаружения и загрузки Page в указанном URI типа "pack". Загруженная Page преобразуется в дерево объектов, корневой объект которого является экземпляром загруженной Page. Ссылка на корневой объект Page сохраняется в свойстве NavigationService.Content. Пакет URI для содержимого, к которому был осуществлен переход, сохраняется в свойстве NavigationService.Source, тогда как NavigationService.CurrentSource сохраняет пакет URI для последней посещенной страницы.

ПримечаниеПримечание

Приложение WPF может иметь несколько активных NavigationService.Дополнительные сведения см. далее в разделе узлы переходов.

Программный переход с помощью службы переходов

Не требуется знать о NavigationService, если переход реализован декларативно в разметке с помощью Hyperlink, поскольку Hyperlink использует NavigationService с вашей стороны. Это значит, что пока прямой или непрямой родительский объект элемента Hyperlink является узлом перехода (см. раздел узлы переходов), Hyperlink сможет найти и использовать службу переходов этого узла для обработки запроса перехода.

Однако бывают ситуации, когда необходимо использовать NavigationService напрямую, например:

  • Если необходимо создать экземпляр Page с использованием конструктора, отличного от конструктора по умолчанию.

  • Если требуется задать свойства в объекте Page перед переходом к нему.

  • Если объект Page, к которому необходимо перейти, можно определить только во время выполнения.

В таких случаях необходимо написать код для программной инициации перехода посредством вызова метода Navigate объекта NavigationService. Для этого требуется получить ссылку на NavigationService.

Получение ссылки на службу переходов

В силу причин, описанных в разделе узлы переходов, приложение WPF может иметь несколько NavigationService. Это означает, что в коде необходимо предусмотреть способ поиска службы NavigationService, которая обычно представляет собой службу NavigationService, приводящую к текущей Page. Ссылку на службу NavigationService можно получить, вызвав метод NavigationService.GetNavigationService типа static. Чтобы получить службу NavigationService, осуществляющую переход к конкретной Page, передайте ссылку в объект Page в качестве аргумента метода GetNavigationService. В следующем фрагменте кода показано, как получить NavigationService для текущей Page.

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

Page реализует свойство NavigationService, чтобы быстро найти NavigationService для Page. Это показано в следующем примере.

' 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;
ПримечаниеПримечание

Page может получить ссылку на соответствующую NavigationService, только когда Page вызывает событие Loaded.

Программный переход к объекту страницы

В следующем примере показано, как с помощью NavigationService осуществить программный переход к Page. Программные переходы необходимы, поскольку экземпляр Page, к которому осуществляется переход, можно создать только с помощью одного конструктора, отличного от конструктора по умолчанию. Объект Page с нестандартным конструктором показан в следующей разметке и коде.

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

Объект Page, осуществляющий переход к Page с конструктором, отличным от используемого по умолчанию, показан в следующей разметке и коде.

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

Если щелкнуть объект Hyperlink на странице Page, запускается переход путем создания экземпляра страницы Page, на которую необходимо перейти, с использованием конструктора, отличного от заданного по умолчанию, и с вызовом метода NavigationService.Navigate. Метод Navigate принимает ссылку на объект, к которому осуществит переход объект NavigationService, скорее чем пакет URI.

Программный переход с URI типа "pack"

Если необходимо создать URI типа "pack" программным образом (например, когда URI типа "pack" определяется только во время выполнения), можно использовать метод NavigationService.Navigate. Это показано в следующем примере.

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

Обновление текущей страницы

Page не загружается, если содержит URI типа "pack", совпадающий с URI типа "pack", который хранится в свойстве NavigationService.Source. Чтобы вынудить WPF повторно загрузить текущую страницу, можно вызвать метод NavigationService.Refresh, как показано в следующем примере.

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

Время существования перехода

Как вы уже видели, существует множество способов инициации перехода. Когда переход инициирован и находится в процессе выполнения, можно отследить его и повлиять на него с помощью следующих событий, реализованных в NavigationService:

  • Navigating. Появляется, когда запрошен новый переход. Может использоваться для отмены перехода.

  • NavigationProgress. Появляется периодически во время загрузки, предоставляя сведения о ходе выполнения перехода.

  • Navigated. Появляется, когда страница найдена и загружена.

  • NavigationStopped. Появляется, когда переход остановлен (посредством вызова метода StopLoading) или когда поступил запрос нового перехода во время выполнения текущего перехода.

  • NavigationFailed. Появляется при появлении ошибки во время перехода к запрошенному содержимому.

  • LoadCompleted. Появляется, когда содержимое, к которому был осуществлен переход, загружено и проанализировано, и начинается его отрисовка.

  • FragmentNavigation. Появляется в начале перехода к фрагменту содержимого, который происходит:

    • Немедленно, если нужный фрагмент находится в текущем содержимом.

    • После загрузки исходного содержимого, если нужный фрагмент находится в другом содержимом.

События перехода вызываются в порядке, который показан на следующем рисунке.

Таблица потока навигации страницы

Обычно объект Page не связан с этими событиями. Более вероятно, что приложение связано с ними, поэтому эти события также вызываются классом Application:

Каждый раз, когда NavigationService создает событие, класс Application создает соответствующее событие. Frame и NavigationWindow предлагают одни и те же события для обнаружения переходов в соответствующих областях.

В некоторых случаях объект Page может быть заинтересован в этих событиях. Например, Page может обработать событие NavigationService.Navigating, чтобы определить необходимость отмены перехода с текущей страницы. Это показано в следующем примере.

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

Если регистрируется обработчик с событием перехода из Page, как это сделано в предыдущем примере, то необходимо также отменить регистрацию обработчика событий. Если этого не сделать, могут возникнуть побочные эффекты в отношении того, как WPF запоминает переходы Page с помощью журнала.

Запоминание перехода в журнале

WPF использует два стека для запоминания страниц, с которых был осуществлен переход: стек "Назад" и стек "Вперед". При переходе с текущей Page на новую Page или вперед на существующую Page текущая Page добавляется в стек "Назад". При переходе с текущей Page обратно на предыдущую Page текущая Page добавляется в стек "Вперед". Стек "Назад", стек "Вперед" и функциональные возможности для управления ими в совокупности называются журналом. Каждый элемент стеков "Вперед" и "Назад" является экземпляром класса JournalEntry и называется записью журнала.

Перемещение по журналу в браузере Internet Explorer

На понятийном уровне журнал функционирует подобно кнопкам Вперед и Назад в Internet Explorer. Это показано на следующем рисунке.

Кнопки “Дальше” и “Назад”

Для XBAPs, размещенных в Internet Explorer, WPF осуществляет интеграцию журнала в UI перехода для приложения Internet Explorer. Это позволяет пользователям перемещаться по страницам в XBAP с помощью кнопок Назад, Вперед и Последние страницы в браузере Internet Explorer. Журнал не интегрирован в Microsoft Internet Explorer 6 так же, как это сделано для Internet Explorer 7 или Internet Explorer 8. Вместо этого WPF отображает заменяющий UI перехода.

Важное примечаниеВажно

В Internet Explorer при переходе со страницы и обратно в XBAP в журнале сохраняются только те страницы, которые не поддерживались в активном состоянии.Обсуждение поддержки страниц в активном состоянии см. далее в разделе Время существования страницы и журнал.

По умолчанию текст для каждой Page, находящейся в списке Последние страницы приложения Internet Explorer, представляет собой URI для Page. В большинстве случаев это не особенно важно для пользователя. К счастью, можно изменить текст, используя следующие параметры:

  1. Значение вложенного атрибута JournalEntry.Name.

  2. Значение атрибута Page.Title.

  3. Значение атрибута Page.WindowTitle и URI для текущего объекта Page.

  4. URI для текущего объекта Page. (Значение по умолчанию)

Порядок, в котором перечислены параметры, совпадает с порядком приоритета для поиска текста. Например, если задан атрибут JournalEntry.Name, то другие значения игнорируются.

В следующем примере для изменения текста, который отображается в записи журнала, используется атрибут Page.Title.

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


...


    }
}

Перемещение по журналу с помощью WPF

Хотя пользователь может перемещаться по журналу с помощью кнопок Назад, Вперед и Последние страницы в Internet Explorer, для перемещения по журналу можно также использовать декларативные и программные механизмы, предоставленные WPF. Одна из причин для этого — предоставление UIs пользовательских переходов в нужных страницах.

Можно декларативно добавить поддержку журнального перехода с помощью команд перехода, предоставляемых NavigationCommands. В следующем примере показано, как использовать команды перехода 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>

Можно программно перемещаться по журналу с помощью одного из следующих членов класса NavigationService:

Журналом можно также управлять программным образом, как описано в разделе Сохранение состояния содержимого с помощью журнала переходов далее.

Время существования страницы и журнал

Рассмотрим XBAP с несколькими страницами, содержащий большое количество рисунков, анимаций и медиафайлов. Объем памяти для подобных страниц может быть довольно большим, особенно если используются видеоматериалы и звуковые файлы. Исходя из того, что в журнале "запоминаются" посещенные страницы, приложение XBAP может быстро расходовать значительный объем памяти.

Поэтому в журнале по умолчанию сохраняются метаданные Page в каждой записи, а не ссылки на объект Page. При переходе к записи журнала соответствующие метаданные Page используются для создания нового экземпляра указанного объекта Page. В итоге время существования каждого объекта Page, к которому осуществляется переход, определяется, как показано на следующем рисунке.

Время существования страницы

Хотя при использовании поведения журнала по умолчанию можно сэкономить потребление памяти, производительность визуализации каждой страницы может уменьшиться; повторное создание экземпляров Page может занимать много времени, особенно при наличии объемного содержимого. Если требуется сохранить экземпляр Page в журнале, можно сделать это двумя способами. Во-первых, можно осуществить программный переход к объекту Page посредством вызова метода NavigationService.Navigate.

Во-вторых, можно установить, чтобы WPF сохранял экземпляр объекта Page в журнале, задавая для свойства KeepAlive значение true (по умолчанию — false). Можно задать KeepAlive декларативно в разметке, как показано в следующем примере.

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

Время существования объекта Page, который поддерживается в активном состоянии, немного отличается от объекта, активность которого не поддерживается. При первом переходе к объекту Page, который поддерживается в активном состоянии, создается экземпляр страницы, как и для объекта Page, активное состояние которого не поддерживается. Однако, поскольку экземпляр объекта Page сохраняется в журнале, его экземпляр не требуется создавать повторно до тех пор, пока он остается в журнале. Следовательно, если Page имеет логику инициализации, которая должна вызываться при каждом переходе к объекту Page, следует переместить ее из конструктора в обработчик для события Loaded. Как показано на следующем рисунке, события Loaded и Unloaded по-прежнему вызываются при каждом переходе к объекту Page и от него соответственно.

При генерации событий загрузки и выгрузки

Когда Page не поддерживается в активном состоянии, не следует выполнять следующие действия:

  • Сохранять ссылку на объект или любую его часть.

  • Регистрировать обработчики событий с событиями, которые не реализованы в объекте.

В случае выполнения любого из этих действий будут созданы ссылки, которые вынудят объект Page оставаться в памяти даже после его удаления из журнала.

В общем случае следует предпочесть поведение Page по умолчанию, при котором активность Page не поддерживается. Однако при этом существуют реализации состояния, которые описаны в следующем разделе.

Сохранение состояния содержимого с помощью журнала переходов

Если Page не поддерживается в активном состоянии, но имеет элементы управления, принимающие данные от пользователя, то что же происходит с данными, когда пользователь переходит с объекта Page и возвращается к нему? С точки зрения пользователя следует ожидать появления ранее введенных данных. К сожалению, поскольку новый экземпляр класса Page создается при каждом переходе, элементы управления, собирающие данные, инициализируются заново и информация теряется.

К счастью, журнал обеспечивает запоминание данных в объекте Page при переходах, включая данные элементов управления. В частности, запись журнала для каждого объекта Page действует как временный контейнер для соответствующего состояния Page. На следующих этапах описывается схема осуществления поддержки при переходе со страницы Page:

  1. Запись для текущей страницы Page добавляется в журнал.

  2. Состояние страницы Page сохраняется в записи журнала для этой страницы, которая добавляется в стек "Назад".

  3. Выполняется переход к новой Page.

При возврате к Page с использованием журнала выполняются следующие действия:

  1. Создается экземпляр Page (самая верхняя запись журнала в стеке "Назад").

  2. Восстанавливается состояние Page, которое было сохранено в записи журнала для Page.

  3. Выполняется обратный переход к Page.

WPF автоматически использует эту поддержку, когда в объекте Page имеются следующие элементы управления:

Если в объекте Page используются эти элементы управления, то введенные в них данные запоминаются при выполнении переходов Page, как показано на примере элемента управления Favorite Color в ListBox (см. следующий рисунок).

Страница с элементами управления, помнящими состояние

Когда Page содержит элементы управления, не упомянутые в предыдущем списке, или когда состояние сохраняется в пользовательских объектах, необходимо написать код для сохранения в журнале состояния страницы при переходах Page.

Если требуется запомнить небольшие части состояния страницы при переходах Page, то можно использовать свойства зависимостей (см. раздел DependencyProperty), настроенные с флагом метаданных FrameworkPropertyMetadata.Journal.

Если состояние, которое требуется запомнить при переходах Page, состоит из нескольких фрагментов данных, то может оказаться, что проще (с меньшим объемом кода) выполнить инкапсуляцию состояния в отдельный класс и реализацию интерфейса IProvideCustomContentState.

Если требуется осуществить переход по различным состояниям одной Page, не переходя с самой Page, можно использовать IProvideCustomContentState и NavigationService.AddBackEntry.

Другой способ, при котором приложения WPF могут сохранять данные — это использование файлов cookie, которые создаются, обновляются и удаляются с помощью методов SetCookie и GetCookie. Файлы cookie, которые создаются в WPF — это те же cookie, которые используются в других типах веб-приложений; файлы cookie представляют собой произвольные фрагменты данных, которые сохраняются приложением на клиентском компьютере во время сеанса приложения или на протяжении нескольких сеансов приложения. Данные файлов cookie обычно представлены в форме пары "имя=значение" в следующем формате.

Имя=Значение

При передаче данных в метод SetCookie вместе с Uri расположения, для которого должны быть заданы файлы cookie, файл cookie создается в оперативной памяти и будет доступен только в течение текущего сеанса приложения. Этот тип файла cookie называют файлом cookie сеанса.

Чтобы сохранить файл cookie на протяжении нескольких сеансов приложения, необходимо добавить в файл cookie дату окончания срока действия, используя следующий формат.

ИМЯ=ЗНАЧЕНИЕ; expires=DAY, DD-MMM-YYYY HH:MM:SS GMT

Файл cookie с датой окончания срока действия хранится в текущей папке временных файлов Интернета для установки Windows, пока не истечет срок действия cookie. Такой файл cookie называется постоянным файлом cookie, поскольку он продолжает существовать на протяжении нескольких сеансов приложения.

Чтобы получить и файл cookie сеанса, и постоянный файл cookie, вызовите метод GetCookie, передавая Uri расположения, где был задан файл cookie с помощью метода SetCookie.

Ниже перечислены некоторые способы, с помощью которых файлы cookie поддерживаются в WPF.

  • Автономные приложения WPF и XBAPs могут создавать файлы cookie и управлять ими.

  • Доступ к файлам cookie, созданным XBAP, можно получить из браузера.

  • XBAPs из одного домена могут создавать и совместно использовать файлы cookie.

  • Страницы XBAPs и HTML из одного домена могут создавать и совместно использовать файлы cookie.

  • Файлы cookie отправляются, когда XBAPs и свободные страницы XAML выполняют веб-запросы.

  • Как XBAPs верхнего уровня, так и XBAPs, помещенные в IFRAMES, могут получить доступ к файлам cookie.

  • Поддержка куки-файлов в WPF одинакова для всех поддерживаемых браузеров.

  • В Internet Explorer политика P3P, которая относятся к куки-файлам, соблюдается системой WPF, особенно по отношению к XBAPs Майкрософт и сторонних поставщиков.

Структурная навигация

Если требуется передать данные из одного объекта Page в другой, можно передать данные в качестве аргументов не используемого по умолчанию конструктора класса Page. Обратите внимание, что если используется этот способ, то необходимо поддерживать Page в активном состоянии; если же нет, то при следующем переходе к Page WPF повторно создаст экземпляр Page с помощью конструктора по умолчанию.

Page может также реализовать свойства, задаваемые данными, которые необходимо передать. Однако все усложняется, когда объекту Page необходимо передать данные обратно в объект Page, из которого выполнен переход. Проблема в том, что изначально переходы не поддерживают механизмы, гарантирующие, что объект Page осуществит возврат после перехода из него. По существу, переходы не поддерживают семантику вызова/возврата. Чтобы решить эту проблему, WPF предоставляет класс PageFunction<T>, с помощью которого можно обеспечить возврат Page в прогнозируемом и структурированном виде. Дополнительные сведения см. в разделе Общие сведения о структурной навигации.

Класс NavigationWindow

К этому моменту мы рассмотрели целый ряд служб переходов, которые с наибольшей вероятностью будут использоваться для построения приложений с содержимым, допускающим переходы. Эти службы обсуждались в контексте XBAPs, хотя они не ограничиваются XBAPs. Современные операционные системы и приложения Windows используют опыт работы современных пользователей с браузерами для включения навигации в стиле браузера в автономные приложения. Вот наиболее распространенные примеры.

  • Тезаурус: переход по вариантам слов.

  • Обозреватель файлов: переход по файлам и папкам.

  • Мастеры: разбиение сложной задачи на несколько страниц, которые имеют переходы между собой. В качестве примера можно привести мастер компонентов Windows, который обрабатывает добавление и удаление свойств Windows.

Чтобы совершать переходы в стиле браузера в автономных приложениях, можно использовать класс NavigationWindow. Объект NavigationWindow является производным от объекта Window и расширяет его такой же поддержкой навигации, которую предоставляют приложения XBAPs. Объект NavigationWindow можно использовать как главное окно автономного приложения либо как дополнительное окно, например диалоговое окно.

Для реализации объекта NavigationWindow, как с классами самого верхнего уровня в WPF (объекты Window, Page и т.д.) используйте комбинацию разметки и программного кода. Это показано в следующем примере.

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

С помощью этого кода создается объект NavigationWindow, осуществляющий автоматический переход к Page (HomePage.XAML), когда открывается NavigationWindow. Если NavigationWindow является главным окном приложения, можно использовать атрибут StartupUri для его запуска. Это показано в следующем примере разметки.

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

На следующем рисунке показан объект NavigationWindow в качестве главного окна автономного приложения.

Главное окно

Как видно из рисунка, NavigationWindow имеет заголовок, даже если он не задан в коде реализации NavigationWindow из предыдущего примера. Заголовок задается с помощью свойства WindowTitle, как показано в следующем коде.

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


...


</Page>

Задание свойств WindowWidth и WindowHeight также влияет на NavigationWindow.

Обычно вы реализуете собственный объект NavigationWindow, когда необходимо изменить его поведение или внешний вид. Если вы этого не сделали, воспользуйтесь командой быстрого вызова. Если задать URI типа "pack" для Page в качестве StartupUri в автономном приложении, то Application автоматически создает NavigationWindow для помещения Page. В следующем примере разметки показано, как это сделать.

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

Если требуется, чтобы дополнительное окно приложения, например диалоговое окно, представляло собой NavigationWindow, то для его открытия можно использовать код следующего примера.

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

На следующем рисунке показан результат.

Диалоговое окно

Как видим, NavigationWindow отображает кнопки Назад и Вперед в стиле Internet Explorer, с помощью которых пользователи могут перемещаться по журналу. Эти кнопки предоставляют пользователям те же возможности, что показаны на следующем рисунке.

Кнопки “Дальше” и “Назад” в NavigationWindow

Если страницы предоставляют собственную поддержку перемещения по журналу и пользовательский интерфейс, то можно скрыть кнопки Назад и Вперед, отображаемые объектом NavigationWindow, задав для свойства ShowsNavigationUI значение false.

Кроме того, можно использовать поддержку настройки в WPF для замены UI самого объекта NavigationWindow.

Класс фрейм

И браузер, и NavigationWindow представляют собой окна, предоставляющие содержимое с возможностью переходов. В некоторых случаях приложения имеют содержимое, которое не обязательно должно размещаться в целом окне. Такое содержимое помещается внутрь другого содержимого. С помощью класса Frame можно вставить содержимое, по которому можно переходить, в другое содержимое. Класс Frame предоставляет такую же поддержку, что и NavigationWindow и приложения XBAPs.

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

Эта разметка задает атрибут Source элемента Frame с помощью URI типа "pack" для объекта Page, в который Frame должен перейти сначала. На следующем рисунке показано XBAP с Page, где имеется Frame, осуществляющий переходы между несколькими страницами.

Фрейм, осуществивший переход по нескольким страницам

Не обязательно использовать Frame только внутри содержимого Page. Можно также поместить Frame внутрь содержимого Window.

По умолчанию Frame использует собственный журнал только при отсутствии другого журнала. Если Frame является частью содержимого, которое размещено внутри класса NavigationWindow или приложения XBAP, то элемент управления Frame использует журнал, который принадлежит классу NavigationWindow или приложению XBAP. Однако иногда требуется, чтобы элемент управления Frame вел свой собственный журнал. Одной из причин для этого является необходимость разрешения переходов в журнале по страницам, которые размещены объектом Frame. Это показано на следующем рисунке.

Схема фрейма и страницы

В этом случае можно настроить Frame на использование собственного журнала путем задания для свойства JournalOwnership объекта Frame значения OwnsJournal. Это показано в следующем примере разметки.

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

На следующем рисунке показано влияние перехода к Frame, где используется собственный журнал.

Фрейм с собственным журналом

Обратите внимание, что записи журнала отображаются с помощью UI навигации в элементе управления Frame, а не с помощью Internet Explorer.

ПримечаниеПримечание

Если Frame является частью содержимого, помещенного в Window, то Frame использует собственный журнал и, следовательно, отображает собственный UI перехода.

Если вам требуется, чтобы Frame предоставил собственный журнал без отображения UI перехода, то можно скрыть UI перехода, задав для свойства NavigationUIVisibility значение Hidden. Это показано в следующем примере разметки.

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

узлы переходов

Frame и NavigationWindow являются классами, которые называются узлами переходов. узел переходов — это класс, который может осуществить переход к содержимому и отобразить его. Для этого в каждом узле переходов используется собственная служба NavigationService и журнал. Основная структура узла переходов показана на следующем рисунке.

Схемы перехода

По существу, это позволяет NavigationWindow и Frame обеспечить такую же поддержку переходов, какую XBAP предоставляет при размещении в браузере.

Помимо использования NavigationService и журнала, узлы переходов реализуют те же члены, что и NavigationService. Это показано на следующем рисунке.

Журнал во фрейме и в NavigationWindow

Это позволяет программировать поддержку переходов непосредственно с ними. Это можно использовать, если необходимо обеспечить UI навигации для элемента управления Frame, размещенного в Window. Кроме того, оба типа реализуют дополнительные, связанные с навигацией члены, включая BackStack (NavigationWindow.BackStack, Frame.BackStack) и ForwardStack (NavigationWindow.ForwardStack, Frame.ForwardStack), которые позволяют перебирать записи журнала в стеке "Назад" и стеке "Вперед" соответственно.

Как упоминалось ранее, в приложении может существовать более одного журнала. На следующем рисунке показан пример, когда это может произойти.

Несколько журналов в одном приложении

Переход к содержимому, отличному от страниц XAML

В этом разделе на примере Page и XBAPs типа "pack" демонстрировались различные возможности переходов в WPF. Однако Page, скомпилированный в приложение, не является единственным типом содержимого, к которому можно осуществить переход, и XBAPs типа "pack" не является единственным способом определения содержимого.

Как показано в этом разделе, можно также осуществлять переходы к свободным файлам XAML, файлам HTML и объектам.

Переход к свободным файлам XAML

Свободный файл XAML — это файл со следующими характеристиками:

  • Содержит только XAML (то есть не код).

  • Имеет объявление соответствующего пространства имен.

  • Имя файла имеет расширение XAML.

Например, рассмотрим следующее содержимое, сохраненное как свободный файл XAML — 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>

Если дважды щелкнуть файл, браузер откроется, выполнит переход к содержимому и отобразит его. Это показано на следующем рисунке.

Отображение содержимого в файле Person.XAML

Свободный файл XAML можно отобразить из одного из следующих источников:

  • Веб-узел на локальном компьютере, в интрасети или Интернете.

  • Общая папка Universal Naming Convention (UNC).

  • Локальный диск.

Свободный файл XAML можно добавить в избранные ссылки браузера или сделать домашней страницей браузера.

ПримечаниеПримечание

Дополнительные сведения о публикации и запуске свободных страниц XAML см. в разделе Развертывание приложений WPF.

Единственным ограничением в отношении свободных файлов XAML является возможность размещения только такого содержимого, которое безопасно для запуска в режиме частичного доверия. Например, Window не может быть корневым элементом свободного файла XAML. Дополнительные сведения см. в разделе Безопасность частичного доверия в WPF.

Переход по HTML-файлам с помощью элемента управления Frame

Как и следовало ожидать, возможен также переход к HTML. Необходимо просто предоставить URI, в котором используется схема HTTP. Например, следующий XAML показывает Frame, осуществляющий переход на страницу HTML.

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

Для перехода к HTML требуются специальные разрешения. Например, нельзя перейти из приложения XBAP, запущенного в песочнице с частичным доверием в зоне Интернета. Дополнительные сведения см. в разделе Безопасность частичного доверия в WPF.

Переход по HTML-файлам с помощью элемента управления WebBrowser

Элемент управления WebBrowser поддерживает размещение документов HTML, навигацию и взаимодействие скриптов/управляемого кода. Подробные сведения об элементе управления WebBrowser см. в разделе WebBrowser.

Как и в случае с элементом управления Frame, для перехода по страницам HTML с помощью элемента управления WebBrowser требуются особые разрешения. Например, из приложения с частичным доверием можно перейти только на страницу HTML, расположенную на исходном веб-узле. Дополнительные сведения см. в разделе Безопасность частичного доверия в WPF.

Переход к пользовательским объектам

Если имеются данные, сохраненные в качестве пользовательских объектов, то одним из способов отображения этих данных является создание Page с содержимым, привязанным к таким объектам (см. раздел Общие сведения о связывании данных). Если не требуется создание всей страницы только для отображения объектов, то можно перейти непосредственно к ним.

Рассмотрим класс Person, реализованный в следующем коде.


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

Для перехода к нему вызовите метод NavigationWindow.Navigate, как показано в следующем коде.

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

На следующем рисунке показан результат.

Страница, осуществляющая переход в класс

Из этого рисунка можно видеть, что ничего полезного не отобразилось. В действительности отображаемое значение является возвращаемым значением метода ToString для объекта Person; по умолчанию это единственное значение, которое WPF может использовать для представления объекта. Можно переопределить метод ToString для возврата более значимой информации, хотя она будет по-прежнему строковым значением. Одним из способов, который позволяет воспользоваться преимуществами возможностей представления WPF, является использование шаблона данных. Можно реализовать шаблон данных, который WPF свяжет с объектом определенного типа. В следующем коде показан шаблон данных для объекта 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>

В данном случае шаблон данных связан с типом Person с помощью расширения разметки x:Type в атрибуте DataType. Затем шаблон данных осуществляет привязку элементов TextBlock (см. раздел TextBlock) к свойствам класса Person. На следующем рисунке показан обновленный внешний вид объекта Person.

Переход к классу с шаблоном данных

Преимуществом этого способа является связность, которая обеспечивается возможностью повторного использования шаблона данных для согласованного отображения объектов в любом месте приложения.

Дополнительные сведения о шаблонах данных см. в разделе Общие сведения о шаблонах данных.

Безопасность

Поддержка переходов в WPF позволяет XBAPs осуществлять переходы через Интернет, а также позволяет приложениям размещать стороннее содержимое. Для защиты приложений и пользователей от опасных изменений WPF предоставляет разнообразные средства безопасности, описанные в разделах Безопасность (WPF) и Безопасность частичного доверия в WPF.

См. также

Ссылки

SetCookie

GetCookie

Основные понятия

Общие сведения об управлении приложением

URI типа "pack" в WPF

Общие сведения о структурной навигации

Общие сведения о топологии переходов

Развертывание приложений WPF

Другие ресурсы

Разделы руководства, посвященные переходу