構造化ナビゲーションの概要
XAML browser application (XBAP) がホストするコンテンツ、Frame、または NavigationWindow は、pack uniform resource identifiers (URIs) で識別され、ハイパーリンクに移動するページで構成されています。 ページの構造、およびハイパーリンクで定義される移動方法を、ナビゲーション トポロジと呼びます。 このトポロジはさまざまな種類のアプリケーションに対応しますが、特にドキュメント間を移動するアプリケーションに適しています。 このようなアプリケーションでは、互いのページの情報を必要とせずに、ユーザーはページ間を移動できます。
ただし、アプリケーションによっては、移動のタイミングを理解している必要があるページを使用します。 たとえば、組織内のすべての従業員を一覧するページ ([従業員の一覧] ページ) を使用する人事アプリケーションがあるものとします。 このページでは、ハイパーリンクをクリックすることによって、新しい従業員を追加することもできます。 クリックすると、[従業員の追加] ページに移動して新しい従業員の詳細情報を収集し、それを [従業員の一覧] ページに返して、新しい従業員を作成し、一覧を更新します。 このスタイルのナビゲーションは、構造化プログラミングと呼ばれる、処理を実行して値を返すメソッドの呼び出しに似ています。 そのため、このスタイルのナビゲーションを、構造化ナビゲーションと呼びます。
Page クラスは、構造化ナビゲーションのサポートを実装していません。 代わりに、Page から PageFunction<T> クラスが派生し、構造化ナビゲーションで必要な基本コンストラクトで拡張されています。 このトピックでは、PageFunction<T> を使用して構造化ナビゲーションを確立する方法について説明します。
このトピックは、次のセクションで構成されています。
- 構造化ナビゲーション
- PageFunction を使用した構造化ナビゲーション
- 他の種類の構造化ナビゲーション
- 関連トピック
構造化ナビゲーション
構造化ナビゲーションで、あるページが別のページを呼び出す場合、以下の一部またはすべての動作が必要です。
呼び出し元ページが、必要に応じてパラメーターを渡して、呼び出されたページに移動します。
呼び出し元ページの使用が終了すると、呼び出されたページは呼び出し元ページに戻ります。このとき、次の動作が行われることがあります。
呼び出し元ページの終了方法 (ユーザーが [OK] または [キャンセル] をクリックしたかどうかなど) を示す状態情報を返します。
ユーザーから収集したデータ (新しい従業員の詳細など) を返します。
呼び出し元ページが、呼び出されたページに戻ると、呼び出されたページはナビゲーション履歴から削除されて、呼び出されたページのインスタンスが他のインスタンスから分離されます。
これらの動作を次の図に示します。
これらの動作は、呼び出されたページとして 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;
}
...
}
}
呼び出し元ページが、Hyperlink の Click イベントを処理することによって呼び出し対象のページをインスタンス化し、このページに初期の文字列値を渡すコードを次に示します。
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> をインスタンス化します。
ただし、呼び出されたページが戻る前に、呼び出し元ページが取得できるデータを返す必要があります。
タスクから呼び出し元ページにタスク結果とタスク データを返す
ユーザーが呼び出されたページの使用を終了すると (この例では、[OK] または [キャンセル] をクリックすることで表されます)、呼び出されたページは戻る必要があります。 呼び出し元ページは、呼び出されたページを使用してユーザーからデータを収集するため、呼び出し元ページには 2 種類の情報が必要です。
ユーザーが呼び出されたページをキャンセルしたかどうか (この例では、[OK] と [キャンセル] のどちらをクリックしたかで表されます)。 これによって、呼び出し元ページは、ユーザーから収集したデータを処理するかどうかを判断します。
ユーザーが提供したデータ。
情報を返すために、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 が返されます。 ユーザーが [OK] をクリックすると、ユーザーによって指定された文字列値が返されます。 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 プロパティで判断されます。 既定では、RemoveFromJournal が true に設定されるため、ページ関数は OnReturn が呼び出されたときに自動的に削除されます。 OnReturn が呼び出された後にページ関数をナビゲーション履歴内に残すには、RemoveFromJournal を false に設定します。
他の種類の構造化ナビゲーション
このトピックでは、構造化ナビゲーションの呼び出しと戻りをサポートする PageFunction<T> の最も基本的な使用方法について説明しています。 これに基づいて、より複雑な構造化ナビゲーションを作成できます。
たとえば、ページを呼び出してユーザーから多くのデータを収集したり、タスクを実行するのに、複数のページが必要な場合があります。 複数のページを使用する場合、これを "ウィザード" と呼びます。
また、構造化ナビゲーションに基づいて効率的な処理を行う複雑なナビゲーション トポロジを使用するアプリケーションもあります。 詳細については、「ナビゲーション トポロジの概要」を参照してください。