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

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

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

Примечание.

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

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

Примечание.

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

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

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

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

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

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

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

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

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

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

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

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

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

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.HomePage">
  Hello, from the XBAP HomePage!
</Page>
using System.Windows.Controls;

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

Imports System.Windows.Controls

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

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

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

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

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

Примечание.

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

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

Настройка начальной страницы

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

Определение приложения обычно реализуется с помощью разметки и кода программной части, причем файл разметки настраивается как элемент MSBuildApplicationDefinition. Ниже приводится определение приложения для XBAP.

<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App" />
using System.Windows;

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

Imports System.Windows

Namespace SDKSample
    Partial Public Class App
        Inherits Application
    End Class
End Namespace

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

Примечание.

В большинстве случаев Page либо компилируется в приложение, либо развертывается вместе с ним. В таких случаях универсальный код ресурса (URI), идентифицирующий пакет Page, является универсальным кодом ресурса (URI), который соответствует схеме пакета. Универсальные коды ресурса пакетов подробно рассматриваются в разделе Универсальные коды ресурса пакетов в WPF. Для перехода к содержимому можно также использовать схему HTTP, которая рассматривается далее.

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

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

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

XBAP page

Примечание.

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

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

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

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

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

Результат показан на примере ниже.

Window title, height, width

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

<Page
  xmlns="http://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 необходимо следующее.

  • Универсальный код ресурса пакета Page, к которой нужно перейти, в том виде, в котором он задан атрибутом NavigateUri.

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

На следующем рисунке показан XBAP с элементом Page, который имеет Hyperlink.

Page with Hyperlink

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

Back and Forward buttons

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

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

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

<Page
    xmlns="http://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 должен включать следующее.

  • Универсальный код ресурса Page с фрагментом содержимого, к которому требуется перейти.

  • Символ "#".

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

Универсальный код ресурса фрагмента имеет следующий формат:

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

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

<Page
  xmlns="http://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 с заданным универсальным кодом ресурса пакета. Скачанная Page преобразуется в дерево объектов, корневой объект которого является экземпляром скачанной страницы Page. Ссылка на корневой объект Page хранится в свойстве NavigationService.Content. Универсальный код ресурса пакета для содержимого, к которому осуществлялся переход, хранится в свойстве NavigationService.Source, а NavigationService.CurrentSource хранит универсальный код ресурса пакета последней страницы, на которую осуществлялся переход.

Примечание.

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

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

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

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

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

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

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

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

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

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

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

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

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

Примечание.

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

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

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

<Page
    x:Class="SDKSample.PageWithNonDefaultConstructor"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="PageWithNonDefaultConstructor">
  
  <!-- Content goes here -->
  
</Page>
using System.Windows.Controls;

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

            this.Content = message;
        }
    }
}

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

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

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

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

</Page>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

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

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

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

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

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

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.NSUriNavigationPage">
  <Hyperlink Click="hyperlink_Click">Navigate to Page by Pack URI</Hyperlink>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

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

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

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

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

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.NSRefreshNavigationPage">
 <Hyperlink Click="hyperlink_Click">Refresh this page</Hyperlink>
</Page>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

namespace SDKSample
{
    public partial class NSRefreshNavigationPage : Page
    {

Namespace SDKSample
    Partial Public Class NSRefreshNavigationPage
        Inherits Page
        void hyperlink_Click(object sender, RoutedEventArgs e)
        {
            // Force WPF to download this page again
            this.NavigationService.Refresh();
        }
    }
}
        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

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

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

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

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

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

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

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

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

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

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

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

Page navigation flow chart

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

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

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

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.CancelNavigationPage">
  <Button Click="button_Click">Navigate to Another Page</Button>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

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

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

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

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

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

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

Back and Forward buttons

Для XBAP, размещенных в Internet Explorer, WPF интегрирует журнал в пользовательский интерфейс навигации Internet Explorer. Это позволяет пользователям перемещаться по страницам в XBAP с помощью кнопок Назад, Вперед и Последние страницы в Internet Explorer.

Важно!

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

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

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

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

  3. Значение атрибута Page.WindowTitle и универсальный код ресурса (URI) для текущей Page.

  4. Универсальный код ресурса (URI) для текущей Page. (по умолчанию)

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

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

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

namespace SDKSample
{
    public partial class PageWithTitle : Page
    {

Namespace SDKSample
    Partial Public Class PageWithTitle
        Inherits Page
    }
}
    End Class
End Namespace

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

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

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://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 lifetime

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

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

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://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 и с нее соответственно.

When the Loaded and Unloaded events are raised

Когда объект 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 и с нее, как видно из примера с любимым цветомListBox на следующем рисунке.

Page with controls that remember state

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

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

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

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

Файлы cookie

Другой способ сохранения данных приложениями 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 (сеанса и постоянных) нужно вызвать метод GetCookie и передать Uri расположения, в котором с помощью метода SetCookie был задан файл cookie.

Ниже перечислены некоторые способы поддержки файлов cookie в WPF.

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

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

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

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

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

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

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

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

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

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

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

Класс NavigationWindow

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

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

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

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

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

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

<NavigationWindow
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.MainWindow" 
    Source="HomePage.xaml"/>
using System.Windows.Navigation;

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

Namespace SDKSample
    Partial Public Class MainWindow
        Inherits NavigationWindow
        Public Sub New()
            InitializeComponent()
        End Sub
    End Class
End Namespace

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

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

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

A main window

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

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

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

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

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

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

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

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

A dialog box

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

Back and Forward buttons in a NavigationWindow

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

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

Класс Frame

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

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

<Page 
  xmlns="http://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 пакета для Page, на которую Frame должен осуществить переход. На следующем изображении показан XBAP со страницей Page с Frame, который осуществлял переход между несколькими страницами.

A frame that has navigated between multiple pages

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

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

Frame and Page diagram

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

<Page 
  xmlns="http://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, использующему собственный журнал.

A frame that uses its own journal

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

Примечание.

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

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

<Page 
  xmlns="http://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 и журнал. На следующем рисунке показана основная структура узла переходов.

Navigator diagrams

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

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

A journal in a Frame and in a NavigationWindow

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

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

Multiple journals within one application

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

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

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

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

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

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

Например, рассмотрим следующее содержимое, сохраненное как свободный файл XAML — Person.xaml.

<!-- Person.xaml -->
<TextBlock xmlns="http://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>

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

Display of the content in the Person.XAML file

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

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

  • общая папка UNC (Universal Naming Convention);

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

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

Примечание.

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

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

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

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

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

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

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

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

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

using System.Windows.Media;

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

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

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

<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

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

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

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

A page that navigates to a class

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

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

  <Application.Resources>

    <!-- Data Template for the Person Class -->
    <DataTemplate DataType="{x:Type local:Person}">
      <TextBlock xmlns="http://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 (см. раздел Person) к свойствам класса TextBlock. На следующем изображении показан обновленный внешний вид объекта Person.

Navigating to a class that has a data template

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

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

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

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

См. также