構造化ナビゲーションの概要

XAML ブラウザー アプリケーション (XBAP)、Frame、または NavigationWindow でホストできるコンテンツは、パック Uniform Resource Identifier (URI) で識別され、ハイパーリンクで移動できるページで構成されています。 ページの構造、およびハイパーリンクで定義される移動方法を、ナビゲーション トポロジと呼びます。 このトポロジはさまざまな種類のアプリケーションに対応しますが、特にドキュメント間を移動するアプリケーションに適しています。 このようなアプリケーションでは、互いのページの情報を必要とせずに、ユーザーはページ間を移動できます。

ただし、アプリケーションによっては、移動のタイミングを理解している必要があるページを使用します。 たとえば、組織内のすべての従業員を一覧するページ ([従業員の一覧] ページ) を使用する人事アプリケーションがあるものとします。 このページでは、ハイパーリンクをクリックすることによって、新しい従業員を追加することもできます。 クリックすると、[従業員の追加] ページに移動して新しい従業員の詳細情報を収集します。次に、それを [従業員の一覧] ページに返して、新しい従業員を作成し、一覧を更新します。 このスタイルのナビゲーションは、構造化プログラミングと呼ばれる、処理を実行して値を返すメソッドの呼び出しに似ています。 そのため、このスタイルのナビゲーションを、構造化ナビゲーションと呼びます。

Page クラスでは、構造化ナビゲーションのサポートは実装されていません。 代わりに、PageFunction<T> クラスは Page から派生し、構造化ナビゲーションに必要な基本コンストラクトで拡張されています。 このトピックでは、PageFunction<T> を使用して構造化ナビゲーションを確立する方法について説明します。

構造化ナビゲーション

構造化ナビゲーションで、あるページが別のページを呼び出す場合、以下の一部またはすべての動作が必要です。

  • 呼び出し元ページが、必要に応じてパラメーターを渡して、呼び出されたページに移動します。

  • ユーザーが呼び出し元ページの使用を終了すると、呼び出されたページは呼び出し元ページに戻ります。このとき、次の動作が行われることがあります。

    • 呼び出し元ページの終了方法 (ユーザーが [OK] または [キャンセル] をクリックしたかどうかなど) を示す状態情報を返します。

    • ユーザーから収集したデータ (新しい従業員の詳細など) を返します。

  • 呼び出し元ページが、呼び出されたページに戻ると、呼び出されたページはナビゲーション履歴から削除されて、呼び出されたページのインスタンスが他のインスタンスから分離されます。

これらの動作を次の図に示します。

Screenshot shows the flow between calling page and called page.

これらの動作は、呼び出し先ページとして PageFunction<T> を使用することにより実装できます。

PageFunction を使用した構造化ナビゲーション

このトピックでは、単一の PageFunction<T> を使用する構造化ナビゲーションの基本メカニズムを実装する方法について説明します。 このサンプルでは、PagePageFunction<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 属性を使用) と分離コード (標準のジェネリック型引数構文を使用) の両方で型引数が指定されています。

型引数として .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

呼び出し元ページで HyperlinkClick イベントを処理し、呼び出されるページをインスタンス化して、初期文字列値を渡すコードを次に示します。

<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> がインスタンス化されます。

ただし、呼び出されたページが戻る前に、呼び出し元ページが取得できるデータを返す必要があります。

タスクから呼び出し元ページにタスク結果とタスク データを返す

ユーザーが呼び出されたページの使用を終了すると (この例では、[OK] または [キャンセル] をクリックすることで表されます)、呼び出されたページは戻る必要があります。 呼び出し元ページは、呼び出されたページを使用してユーザーからデータを収集したため、呼び出し元ページには 2 種類の情報が必要です。

  1. ユーザーが呼び出されたページをキャンセルしたかどうか (この例では、[OK] と [キャンセル] のどちらをクリックしたかで表されます)。 これによって、呼び出し元ページは、ユーザーから収集したデータを処理するかどうかを判断します。

  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 が返されます。 ユーザーが [OK] をクリックすると、ユーザーによって指定された文字列値が返されます。 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 プロパティで判断されます。 既定では、RemoveFromJournaltrue に設定されるため、ページ関数は OnReturn が呼び出されると自動的に削除されます。 OnReturn が呼び出された後もページ関数をナビゲーション履歴内に残すには、RemoveFromJournalfalse に設定します。

他の種類の構造化ナビゲーション

このトピックでは、構造化ナビゲーションの呼び出しと戻りをサポートする PageFunction<T> の最も基本的な使用方法について説明します。 これに基づいて、より複雑な構造化ナビゲーションを作成できます。

たとえば、呼び出し元ページがユーザーから十分なデータを収集したり、タスクを実行するには、複数のページが必要な場合があります。 複数のページを使用する場合、これを "ウィザード" と呼びます。

また、構造化ナビゲーションに基づいて効率的な操作を実行する複雑なナビゲーション トポロジを使用するアプリケーションもあります。 詳細については、「ナビゲーション トポロジの概要」を参照してください。

関連項目