結構化巡覽概觀
可由 XAML 瀏覽器應用程式 (XBAP)、Frame 或 NavigationWindow 所裝載的內容是由頁面所組成,而頁面可以透過 Pack 統一資源識別項 (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 的宣告。 如您在程式碼範例中所見,使用 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
下列程式碼顯示可處理 Hyperlink 之 Click 事件的呼叫端頁面,以具現化被呼叫端頁面,並對其傳遞初始字串值。
<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
您不需要將參數傳遞給呼叫的頁面。 您反而可以執行下列作業︰
從呼叫端頁面︰
使用無參數建構函式來具現化被呼叫 PageFunction<T>。
將參數儲存至 Properties。
導覽至被呼叫的 PageFunction<T>。
從被呼叫的 PageFunction<T>:
- 擷取並使用 Properties 中所儲存的參數。
但是,您很快就會發現,您還是需要使用程式碼來具現化並巡覽至呼叫的頁面,才能收集呼叫的頁面所傳回的資料。 基於此原因,PageFunction<T> 需要保持運作;否則,下次導覽至 PageFunction<T> 時,WPF 會使用無參數建構函式來具現化 PageFunction<T>。
但在呼叫的頁面傳回之前,它需要傳回呼叫端頁面可擷取的資料。
將工作的工作結果和工作資料傳回給呼叫端頁面
使用者用完呼叫的頁面時,如本例所示,按 [確定] 或 [取消] 按鈕,必須傳回呼叫的頁面。 因為呼叫端頁面使用了被呼叫頁面來收集使用者資料,所以呼叫端頁面需要兩種類型的資訊︰
使用者是否取消了呼叫的頁面 (本例中為按下 [確定] 按鈕或 [取消] 按鈕)。 這可讓呼叫端頁面決定是否要處理呼叫端頁面收集的使用者資料。
使用者提供的資料。
若要傳回資訊,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> 的最基本用法,可支援呼叫/傳回結構化導覽。 此基礎讓您能夠建立更複雜的結構化巡覽類型。
例如,呼叫端頁面有時候需要多個頁面來收集足夠的使用者資料,或執行工作。 使用多個頁面稱之為「精靈」。
在其他情況下,應用程式可能會令相依於結構化巡覽的複雜巡覽拓撲有效運作。 如需詳細資訊,請參閱巡覽拓撲概觀。