Поделиться через


Обзор структурированной навигации

Содержимое, которое может размещаться приложением браузера XAML (XBAP), или FrameNavigationWindow состоит из страниц, которые можно определить по универсальным идентификаторам ресурсов пакета (URI) и переходу по гиперссылкам. Структура страниц и способов, с помощью которых они могут перемещаться, как определено гиперссылками, называется топологией навигации. Такая топология подходит для различных типов приложений, особенно для навигации по документам. Для таких приложений пользователь может переходить с одной страницы на другую страницу без необходимости знать что-либо о другом.

Однако другие типы приложений имеют страницы, которые должны знать, когда они были перемещены между ними. Например, рассмотрим приложение для управления персоналом с одной страницей для перечисления всех сотрудников в организации — страницы "Список сотрудников". Эта страница также может позволить пользователям добавлять нового сотрудника, щелкнув гиперссылку. После нажатия страницы перейдите на страницу "Добавить сотрудника", чтобы собрать сведения о новом сотруднике и вернуть их на страницу "Список сотрудников", чтобы создать нового сотрудника и обновить список. Этот стиль навигации аналогичен вызову метода для выполнения некоторой обработки и возврата значения, которое называется структурированным программированием. Таким образом, этот стиль навигации называется структурированной навигацией.

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

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

Если одна страница вызывает другую страницу в структурированной навигации, требуются некоторые из следующих действий:

  • Вызывающая страница переходит на вызываемую страницу, при необходимости передавая параметры, необходимые вызываемой странице.

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

    • Возвращая сведения о состоянии, описывающие завершение вызывающей страницы (например, нажатие кнопки "ОК" или кнопки "Отмена").

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

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

Эти поведения показаны на следующем рисунке:

Снимок экрана показывает поток между вызывающей страницей и вызываемой страницей.

Реализовать эти действия можно через вызов страницы PageFunction<T>.

Структурированная навигация с помощью PageFunction

В этом разделе показано, как реализовать базовую механику структурированной навигации с одним PageFunction<T>. В этом примере Page вызывает PageFunction<T> для получения значения String от пользователя и его возвращения.

Создание страницы вызова

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

<Page 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="StructuredNavigationSample.CallingPage"
    WindowTitle="Calling Page" 
    WindowWidth="250" WindowHeight="150">
</Page>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CallingPage : Page
    {
        public CallingPage()
        {
            InitializeComponent();
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CallingPage
    Inherits Page
    Public Sub New()
        Me.InitializeComponent()
}
End Sub
    }
}
End Class

End Namespace

Создание функции страницы для вызова

Так как вызывающая страница может использовать вызываемую страницу для сбора и возврата данных от пользователя, PageFunction<T> реализуется как универсальный класс, аргумент типа которого указывает тип значения, возвращаемого вызываемой страницей. В следующем коде показана начальная реализация вызываемой страницы с использованием PageFunction<T>, который возвращает String.

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

namespace StructuredNavigationSample
{
    public partial class CalledPageFunction : PageFunction<String>
    {
        public CalledPageFunction()
        {
            InitializeComponent();
        }
Imports System.Windows
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CalledPageFunction
    Inherits PageFunction(Of String)
    Public Sub New()
        Me.InitializeComponent()
    End Sub
    }
}
End Class

End Namespace

Объявление PageFunction<T> похоже на объявление Page, но с добавлением аргументов типа. Как видно из примера кода, аргументы типа указываются как в разметке XAML с использованием атрибута x:TypeArguments, так и в коде за XAML, используя стандартный синтаксис для аргументов универсального типа.

Не нужно использовать только классы .NET Framework в качестве аргументов типа. PageFunction<T> Можно вызвать для сбора данных, относящихся к домену, которые абстрагируются как пользовательский тип. В следующем коде показано, как использовать пользовательский тип в качестве аргумента типа для PageFunction<T>объекта.

namespace SDKSample
{
    public class CustomType
    {
Public Class CustomType
    }
}
End Class
<PageFunction
    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.CustomTypePageFunction"
    x:TypeArguments="local:CustomType">
</PageFunction>
using System.Windows.Navigation;

namespace SDKSample
{
    public partial class CustomTypePageFunction : PageFunction<CustomType>
    {
Partial Public Class CustomTypePageFunction
    Inherits System.Windows.Navigation.PageFunction(Of CustomType)
    }
}
End Class

Аргументы типа для PageFunction<T> обеспечивают основу для взаимодействия между вызывающей страницей и вызываемой страницей, что обсуждается в последующих разделах.

Как вы увидите, тип, который определяется объявлением PageFunction<T>, выполняет важную функцию в возврате данных из PageFunction<T> на вызывающую страницу.

Вызов PageFunction и передача параметров

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

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

using System;
using System.Windows;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CalledPageFunction : PageFunction<String>
    {
Imports System.Windows
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CalledPageFunction
    Inherits PageFunction(Of String)
public CalledPageFunction(string initialDataItem1Value)
{
    InitializeComponent();

Public Sub New(ByVal initialDataItem1Value As String)
    Me.InitializeComponent()
    // Set initial value
    this.dataItem1TextBox.Text = initialDataItem1Value;
}
    ' Set initial value
    Me.dataItem1TextBox.Text = initialDataItem1Value
End Sub
    }
}
End Class

End Namespace

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

<Hyperlink Name="pageFunctionHyperlink">Call Page Function</Hyperlink>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

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");
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Navigation

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

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

  • На странице вызова:

    1. Создайте экземпляр вызова PageFunction<T> с помощью конструктора без параметров.

    2. Сохраните параметры в Properties.

    3. Перейдите к вызываемой PageFunction<T>.

  • Из вызываемого:PageFunction<T>

    • Получение и использование параметров, хранящихся в Properties.

Но, как вы увидите вскоре, вам по-прежнему потребуется использовать код для создания экземпляра и перехода на вызываемую страницу для сбора данных, возвращаемых вызываемой страницей. По этой причине PageFunction<T> должно оставаться активным; в противном случае, при следующем переходе к PageFunction<T>, WPF инициализирует PageFunction<T> с помощью конструктора без параметров.

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

Возврат результатов задачи и данных задачи из задачи на вызывающую страницу

Когда пользователь завершит работу с вызываемой страницей, что в этом примере обозначается нажатием кнопок "ОК" или "Отмена", вызываемая страница должна закрыться. Так как вызываемая страница использовала вызываемую страницу для сбора данных от пользователя, для вызываемой страницы требуется два типа информации:

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

  2. Данные, предоставленные пользователем.

PageFunction<T> реализует метод OnReturn для возврата сведений. В следующем коде показано, как его вызвать.

using System;
using System.Windows;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CalledPageFunction : PageFunction<String>
    {
Imports System.Windows
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CalledPageFunction
    Inherits PageFunction(Of 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);
        }
    }
}
    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

В этом примере, если пользователь нажимает кнопку "Отмена", значение null возвращается на вызывающую страницу. Если вместо этого нажимается кнопка "ОК", возвращается строковое значение, предоставленное пользователем. OnReturn protected virtual— это метод, который вызывается для возврата данных на вызывающую страницу. Данные необходимо упаковать в экземпляр универсального ReturnEventArgs<T> типа, аргумент типа которого указывает тип возвращаемого значения Result . Таким образом, когда вы объявляете PageFunction<T> с определенным аргументом типа, вы указываете, что PageFunction<T> вернет экземпляр типа, который задан этим аргументом. В этом примере аргумент типа и, следовательно, возвращаемое значение имеет тип String.

При вызове OnReturn на вызывающей странице требуется некоторый способ получения возвращаемого значения PageFunction<T>. По этой причине PageFunction<T> реализует Return событие для вызова страниц для обработки. Когда вызывается OnReturn, поднимается Return, поэтому вызывающая страница может зарегистрироваться в Return для получения уведомления.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

namespace StructuredNavigationSample
{
    public partial class CallingPage : Page
    {
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Navigation

Namespace StructuredNavigationSample

Public Class CallingPage
    Inherits 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;
            }
        }
    }
}
    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

Удаление страниц задач при завершении задачи

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

Однако если из журнала не удалена вызываемая страница, пользователь сможет вернуться к предыдущему экземпляру вызывающей страницы. Определяется ли, сохраняется ли PageFunction<T> в журнале, зависит от свойства RemoveFromJournal. По умолчанию функция страницы автоматически удаляется, когда вызывается OnReturn, поскольку RemoveFromJournal имеет значение true. Чтобы сохранить страницу в журнале навигации после вызова OnReturn, установите RemoveFromJournal в значение false.

Другие типы структурированной навигации

В этом разделе показано наиболее простое использование PageFunction<T> для поддержки структурированной навигации вызова и возврата. Эта основа предоставляет возможность создавать более сложные типы структурированной навигации.

Для примера, иногда инициирующей странице требуются несколько страниц для сбора достаточного объема данных от пользователя или выполнения задачи. Использование нескольких страниц называется «пошаговым помощником».

В других случаях приложения могут иметь сложные топологии навигации, которые зависят от структурированной навигации для эффективной работы. Дополнительные сведения см. в разделе "Обзор топологий навигации".

См. также