Общие сведения о структурной навигации
Содержимое, которое может быть размещено приложением обозревателя XAML browser application (XBAP), объектом Frame или NavigationWindow, состоит из страниц, которые могут определяться uniform resource identifiers (URIs) пакета и просматриваться с помощью гиперссылок. Структура страниц и способы, с помощью которых их можно просмотреть с помощью гиперссылок, называется топологией навигации. Такая топология подходит для различных типов приложений, особенно тех, которые осуществляют навигацию по документам. Для таких приложений пользователю необязательно знать что-либо о других страницах при перемещении с одной страницы на другую.
Однако другие типы приложений содержат страницы, которые должны быть известны при перемещении между ними. Например, рассмотрим приложение управления персоналом, имеющее одну страницу со списком всех сотрудников организации — страница «Список сотрудников». Эта страница могла бы также разрешить пользователям добавлять нового сотрудника, щелкнув гиперссылку. После щелчка выполняется переход на страницу «Добавить сотрудника», чтобы собрать сведения о новом сотруднике, и возврат к странице «Список сотрудников», чтобы добавить нового сотрудника и обновить список. Этот стиль перехода аналогичен вызову метода для выполнения обработки и возврата значения, что называется структурным программированием. Такой стиль перехода называется структурная навигация.
Класс Page не реализует поддержку структурной навигации. Вместо этого, класс PageFunction<T> производится из класса Page и расширяет его с помощью основных конструкций, необходимых для структурированных переходов. В этом разделе показано, как установить структурную навигацию, используя объект PageFunction<T>.
В этом разделе содержатся следующие подразделы.
- Структурная навигация
- Структурная навигация с помощью PageFunction
- Другие типы структурной навигации
- Связанные разделы
Структурная навигация
Когда одна страница вызывает другую страницу в структурной навигации, требуются некоторые или все из следующих условий:
Вызывающая страница которая переходит к вызванной странице, при необходимости, передает ей необходимые параметры.
Вызванная страница, когда пользователь завершил ее вызов, возвращает вызывающей странице, при необходимости:
Возвращение сведений о состоянии, описывающие, как была завершена вызывающая страница (например, какую кнопку нажал пользователь: «ОК» или «Отмена»).
Возвращение данных, которые были собраны от пользователя (например, сведения о новом сотруднике).
Когда вызывающая страница возвращается к вызванной странице, вызванная страницы удаляется из истории переходов для изоляции одного экземпляра вызванной страницы от другого.
Это поведение показано на следующем рисунке.
Для реализации этого поведения можно использовать объект PageFunction<T> в качестве вызванной страницы.
Структурная навигация с помощью PageFunction
В этом разделе показано, как реализовать основной механизм структурной навигации с помощью одного объекта PageFunction<T>. В этом примере объект Page вызывает объект PageFunction<T>, чтобы получить значение String от пользователя и вернуть его.
Создание вызывающей страницы
Страница, которая вызывает PageFunction<T>, может быть Page или PageFunction<T>. В данном примере, это Page, как показано в следующем коде.
<Page
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
x:Class="StructuredNavigationSample.CallingPage"
WindowTitle="Calling Page"
WindowWidth="250" WindowHeight="150">
...
</Page>
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler, Visibility
Imports System.Windows.Controls ' Page
Imports System.Windows.Navigation ' ReturnEventArgs
Namespace StructuredNavigationSample
Public Class CallingPage
Inherits Page
Public Sub New()
Me.InitializeComponent()
...
End Sub
...
End Class
End Namespace
using System.Windows; // RoutedEventArgs, RoutedEventHandler, Visibility
using System.Windows.Controls; // Page
using System.Windows.Navigation; // ReturnEventArgs
namespace StructuredNavigationSample
{
public partial class CallingPage : Page
{
public CallingPage()
{
InitializeComponent();
...
}
...
}
}
Создание функции страницы для вызова
Поскольку вызывающая страница может использовать вызванную страницу для сбора и возврата данных от пользователя, объект PageFunction<T> реализован как базовый класс, тип аргумента которого определяет тип значения, которое вернет вызванная страница. Следующий код показывает начальную реализацию вызванной страницы, используя объект PageFunction<T>, который возвращает String.
<PageFunction
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="StructuredNavigationSample.CalledPageFunction"
x:TypeArguments="sys:String"
Title="Page Function"
WindowWidth="250" WindowHeight="150">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Data -->
<Label Grid.Column="0" Grid.Row="0">DataItem1:</Label>
<TextBox Grid.Column="1" Grid.Row="0" Name="dataItem1TextBox"></TextBox>
<!-- Accept/Cancel buttons -->
<TextBlock Grid.Column="1" Grid.Row="1" HorizontalAlignment="Right">
<Button Name="okButton" IsDefault="True" MinWidth="50">OK</Button>
<Button Name="cancelButton" IsCancel="True" MinWidth="50">Cancel</Button>
</TextBlock>
</Grid>
</PageFunction>
Imports System ' String
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler
Imports System.Windows.Navigation ' PageFunction
Namespace StructuredNavigationSample
Public Class CalledPageFunction
Inherits PageFunction(Of String)
Public Sub New()
Me.InitializeComponent()
End Sub
...
End Class
End Namespace
using System; // String
using System.Windows; // RoutedEventArgs, RoutedEventHandler
using System.Windows.Navigation; // PageFunction
namespace StructuredNavigationSample
{
public partial class CalledPageFunction : PageFunction<String>
{
public CalledPageFunction()
{
InitializeComponent();
}
...
}
}
Объявление объекта PageFunction<T> похоже на объявление объекта Page с добавлением аргументов типа. Как видно из примера кода, аргументы типа указаны в обеих метках XAML, с помощью атрибута x:TypeArguments, и фоновом коде, с помощью стандартного синтаксиса аргумента универсального типа.
Нет необходимости использовать только классы .NET Framework в качестве аргументов типа. Объект PageFunction<T> может быть вызван для сбора данных отдельного домена, которые абстрагированы как пользовательский типа. В следующем коде показано использование пользовательского типа в качестве аргумента типа для объекта PageFunction<T>.
Public Class CustomType
...
End Class
namespace SDKSample
{
public class CustomType
{
...
}
}
<PageFunction
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.CustomTypePageFunction"
x:TypeArguments="local:CustomType">
...
</PageFunction>
Partial Public Class CustomTypePageFunction
Inherits System.Windows.Navigation.PageFunction(Of CustomType)
using System.Windows.Navigation; // PageFunction
namespace SDKSample
{
public partial class CustomTypePageFunction : PageFunction<CustomType>
{
Аргументы типа для объекта PageFunction<T> обеспечивают основу для связи между вызывающей и вызываемой страницами, которая рассматривается в следующих разделах.
Как можно видеть дальше, тип, который определен с помощью объявления объекта PageFunction<T>, играет важную роль в возвращении данных из объекта PageFunction<T> в вызывающую страницу.
Вызов PageFunction и передача параметров
Чтобы вызвать страницу, вызывающая страница должна создать экземпляр вызванной страницы и перейти к ней с помощью метода Navigate. Это позволяет вызывающей странице передать исходные данные вызванной странице, такие как значения по умолчанию данных, собранных вызываемой страницей.
В следующем коде демонстрируется вызываемая страница с конструктором, не заданным по умолчанию и принимающим параметры из вызывающей страницы.
Imports System ' String
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler
Imports System.Windows.Navigation ' PageFunction
Namespace StructuredNavigationSample
Public Class CalledPageFunction
Inherits PageFunction(Of String)
...
Public Sub New(ByVal initialDataItem1Value As String)
Me.InitializeComponent()
...
' Set initial value
Me.dataItem1TextBox.Text = initialDataItem1Value
End Sub
...
End Class
End Namespace
using System; // String
using System.Windows; // RoutedEventArgs, RoutedEventHandler
using System.Windows.Navigation; // PageFunction
namespace StructuredNavigationSample
{
public partial class CalledPageFunction : PageFunction<String>
{
...
public CalledPageFunction(string initialDataItem1Value)
{
InitializeComponent();
...
// Set initial value
this.dataItem1TextBox.Text = initialDataItem1Value;
}
...
}
}
В следующем коде показана вызывающая страница, обрабатывающая событие Click объекта Hyperlink, предназначенного для создания экземпляра вызываемой страницы и передачи ей исходного строкового значения.
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler, Visibility
Imports System.Windows.Controls ' Page
Imports System.Windows.Navigation ' ReturnEventArgs
Namespace StructuredNavigationSample
Public Class CallingPage
Inherits Page
Public Sub New()
Me.InitializeComponent()
AddHandler Me.pageFunctionHyperlink.Click, New RoutedEventHandler(AddressOf Me.pageFunctionHyperlink_Click)
End Sub
Private Sub pageFunctionHyperlink_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
...
End Sub
...
End Class
End Namespace
using System.Windows; // RoutedEventArgs, RoutedEventHandler, Visibility
using System.Windows.Controls; // Page
using System.Windows.Navigation; // ReturnEventArgs
namespace StructuredNavigationSample
{
public partial class CallingPage : Page
{
public CallingPage()
{
InitializeComponent();
this.pageFunctionHyperlink.Click += new RoutedEventHandler(pageFunctionHyperlink_Click);
}
void pageFunctionHyperlink_Click(object sender, RoutedEventArgs e)
{
// Instantiate and navigate to page function
CalledPageFunction CalledPageFunction = new CalledPageFunction("Initial Data Item Value");
...
}
...
}
}
<Hyperlink Name="pageFunctionHyperlink">Call Page Function</Hyperlink>
Не требуется передача параметров вызываемой странице. Вместо этого, можно выполнить следующие действия.
Их вызывающей страницы:
Создайте экземпляр вызываемого объекта PageFunction<T> с помощью конструктора по умолчанию.
Сохраните параметры в свойстве Properties.
Перейдите к вызываемому объекту PageFunction<T>.
Из вызываемого объекта PageFunction<T>:
- Извлеките и используйте параметры, хранящиеся в свойстве Properties.
Но, как будет сразу видно, по-прежнему нужно использовать код для создания экземпляра и перехода к вызываемой странице для сбора возвращаемых ею данных. По этой причине, объект PageFunction<T> должен поддерживаться активным; в противном случае, при следующем переходе к объекту PageFunction<T> WPF создает экземпляр PageFunction<T> с помощью конструктора по умолчанию.
Перед тем как вызванная страница может вернуться, она должно возвратить данные, которые могут быть получены вызывающей страницей.
Возвращение результатов и данных задачи из задачи в вызывающую страницу
Когда пользователь завершил работу с вызванной страницей — в этом примере нажатием кнопки «ОК» или «Отмена» — вызванная страница должна вернуться. Поскольку вызывающая страница использует вызванную страницу для сбора данных от пользователя, вызывающая страница требует два типа данных:
Отменил ли пользователь вызванную страницу (в этом примере — с помощью нажатия кнопки «ОК» или «Отмена»). Это позволяет вызывающей странице определить, требуется ли обработка данных, собранных вызванной страницей от пользователя.
Данные, которые были предоставлены пользователем.
Для возврата данных объект PageFunction<T> реализует метод OnReturn. Следующий код иллюстрирует, как его вызвать.
Imports System ' String
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler
Imports System.Windows.Navigation ' PageFunction
Namespace StructuredNavigationSample
Public Class CalledPageFunction
Inherits PageFunction(Of String)
...
Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Accept when Ok button is clicked
Me.OnReturn(New ReturnEventArgs(Of String)(Me.dataItem1TextBox.Text))
End Sub
Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Cancel
Me.OnReturn(Nothing)
End Sub
End Class
End Namespace
using System; // String
using System.Windows; // RoutedEventArgs, RoutedEventHandler
using System.Windows.Navigation; // PageFunction
namespace StructuredNavigationSample
{
public partial class CalledPageFunction : PageFunction<String>
{
...
void okButton_Click(object sender, RoutedEventArgs e)
{
// Accept when Ok button is clicked
OnReturn(new ReturnEventArgs<string>(this.dataItem1TextBox.Text));
}
void cancelButton_Click(object sender, RoutedEventArgs e)
{
// Cancel
OnReturn(null);
}
}
}
В этом примере, если пользователь нажимает кнопку «Отмена», вызывающей странице возвращается значение null. Если вместо этого пользователь нажмет кнопку "ОК", возвратится строковое значение, предоставленное пользователем. Объект OnReturn представляет собой защищенный (protected) виртуальный (virtual) метод, который можно вызвать для возвращения данных пользователя на вызывающую страницу. Данные необходимо упаковать в экземпляре универсального типа ReturnEventArgs<T>, тип аргумента которого указывает тип значения, возвращающего свойство Result. Таким образом, при объявлении объекта PageFunction<T> с определенным аргументом типа, пользователь заявляет, что объект PageFunction<T> вернет экземпляр типа, который определен аргументом типа. В этом примере, аргумент типа и, следовательно, возвращенное значение является объектом String типа.
При вызове метода OnReturn вызывающей странице требуется способ получения возвращенного значения PageFunction<T>. По этой причине, PageFunction<T> реализует событие Return для вызывающей страницы для обработки. При вызове метода OnReturn вызывается событие Return, поэтому вызывающая страница может зарегистрировать событие Return для получения уведомления.
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler, Visibility
Imports System.Windows.Controls ' Page
Imports System.Windows.Navigation ' ReturnEventArgs
Namespace StructuredNavigationSample
Public Class CallingPage
Inherits Page
...
Private Sub pageFunctionHyperlink_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Instantiate and navigate to page function
Dim calledPageFunction As New CalledPageFunction("Initial Data Item Value")
AddHandler calledPageFunction.Return, New ReturnEventHandler(Of String)(AddressOf Me.calledPageFunction_Return)
MyBase.NavigationService.Navigate(calledPageFunction)
End Sub
Private Sub calledPageFunction_Return(ByVal sender As Object, ByVal e As ReturnEventArgs(Of String))
Me.pageFunctionResultsTextBlock.Visibility = Windows.Visibility.Visible
' Display result
Me.pageFunctionResultsTextBlock.Text = IIf((Not e Is Nothing), "Accepted", "Canceled")
' If page function returned, display result and data
If (Not e Is Nothing) Then
Me.pageFunctionResultsTextBlock.Text = (Me.pageFunctionResultsTextBlock.Text & ChrW(10) & e.Result)
End If
End Sub
End Class
End Namespace
using System.Windows; // RoutedEventArgs, RoutedEventHandler, Visibility
using System.Windows.Controls; // Page
using System.Windows.Navigation; // ReturnEventArgs
namespace StructuredNavigationSample
{
public partial class CallingPage : Page
{
...
void pageFunctionHyperlink_Click(object sender, RoutedEventArgs e)
{
// Instantiate and navigate to page function
CalledPageFunction CalledPageFunction = new CalledPageFunction("Initial Data Item Value");
CalledPageFunction.Return += pageFunction_Return;
this.NavigationService.Navigate(CalledPageFunction);
}
void pageFunction_Return(object sender, ReturnEventArgs<string> e)
{
this.pageFunctionResultsTextBlock.Visibility = Visibility.Visible;
// Display result
this.pageFunctionResultsTextBlock.Text = (e != null ? "Accepted" : "Canceled");
// If page function returned, display result and data
if (e != null)
{
this.pageFunctionResultsTextBlock.Text += "\n" + e.Result;
}
}
}
}
Удаление страниц задачи при ее завершении
Когда вызванная страница возвращается, и пользователь не отменил ее, вызывающая страница будет обрабатывать данные, предоставленные пользователем, и также данные, возвращенные вызванной страницей. Получение данных таким образом обычно является изолированным действием; при возвращении вызванной страны вызывающая страница должна создать новую страницу и перейти к ней, чтобы получить больше данных.
Однако если вызванная страница не удалена из журнала, пользователь может вернуться к предыдущему экземпляру вызывающей страницы. Сохранен ли объект PageFunction<T> в журнале, определяется свойством RemoveFromJournal. По умолчанию функция страницы автоматически удаляется при вызове метода OnReturn, так как для свойства RemoveFromJournal установлено значение true. Чтобы сохранить функцию страницы в истории переходов после вызова метода OnReturn, задайте для свойства RemoveFromJournal значение false.
Другие типы структурной навигации
В этом разделе показано большинство основных способов использования объекта PageFunction<T> для поддержки вызова/возврата структурной навигации. Эта база обеспечивает возможность создания более сложных типов структурных переходов.
Например, иногда вызывающей странице требуется несколько страниц для сбора достаточных данных от пользователя или для выполнения задачи. Использование нескольких страниц называется «мастером».
В других случаях, приложения для эффективной работы могут иметь сложные топологии переходов, зависящие от структурной навигации. Дополнительные сведения см. в разделе Общие сведения о топологии переходов.