次の方法で共有


Xamarin.Forms シェルのナビゲーション

Xamarin.Forms シェルには、設定されたナビゲーション階層に従わなくても、アプリケーション内の任意のページに移動するルートを使用する URI ベースのナビゲーション操作が用意されています。 さらに、これにより、ナビゲーション スタックのすべてのページにアクセスすることなく、後方に移動する機能も提供されます。

Shell クラスは、次のようなナビゲーション関連のプロパティを定義します。

BackButtonBehaviorCurrentItem、および CurrentState プロパティは、BindableProperty オブジェクトを基盤としています。つまり、これらのプロパティは、データ バインディングの対象になる場合があります。

ナビゲーションは、Shell クラスから、GoToAsync メソッドを呼び出すことで実行されます。 ナビゲーションが実行されるときに Navigating イベントが発生し、ナビゲーションが完了するときに Navigated イベントが発生します。

Note

シェル アプリケーション内のページ間では、Navigation プロパティを使って引き続きナビゲーションを実行できます。 詳しくは、「階層ナビゲーション」をご覧ください。

Routes

ナビゲーションは、移動先の URI を指定して、シェル アプリケーション内で実行されます。 ナビゲーション URI には、3 つの要素を含めることができます。

  • "ルート"。シェルの視覚階層の一部として存在するコンテンツへのパスを定義します。
  • "ページ"。 シェルの視覚階層に存在しないページは、シェル アプリケーション内の任意の場所からナビゲーション スタック上にプッシュできます。 たとえば、詳細ページは、シェルの視覚階層には定義されませんが、必要に応じてナビゲーション スタック上にプッシュできます。
  • 1 つまたは複数の "クエリ パラメーター"。 クエリ パラメーターは、ナビゲーション中に移動先ページに渡すことができるパラメーターです。

ナビゲーション URI に 3 つすべての要素を含めると、構造は //route/page?queryParameters にようになります。

ルートを登録する

ルートは、Route プロパティを利用して、FlyoutItemTabBarTab、および ShellContent オブジェクトに対して定義できます。

<Shell ...>
    <FlyoutItem ...
                Route="animals">
        <Tab ...
             Route="domestic">
            <ShellContent ...
                          Route="cats" />
            <ShellContent ...
                          Route="dogs" />
        </Tab>
        <ShellContent ...
                      Route="monkeys" />
        <ShellContent ...
                      Route="elephants" />  
        <ShellContent ...
                      Route="bears" />
    </FlyoutItem>
    <ShellContent ...
                  Route="about" />                  
    ...
</Shell>

Note

シェルの階層内にあるすべての項目には、関連付けられているルートがあります。 ルートを設定しない場合は、実行時に 1 つのルートが生成されます。 ただし、異なるアプリケーション セッションにわたって、生成されたルートに一貫性があるという保証はありません。

上の例では、プログラムによるナビゲーションに使用できる次のルート階層を作成します。

animals
  domestic
    cats
    dogs
  monkeys
  elephants
  bears
about

dogs ルートの ShellContent オブジェクトに移動するには、絶対ルート URI は //animals/domestic/dogs になります。 同様に、about ルートの ShellContent オブジェクトに移動するには、絶対ルート URI は //about になります。

警告

ルートの重複が検出された場合、アプリケーションの起動時に ArgumentException がスローされます。 この例外は、階層内の同じレベルにある 2 つ以上のルートが 1 つのルート名を共有している場合にもスローされます。

詳細ページ ルートの登録

Shell サブクラス コンストラクター内、またはルートが呼び出される前に実行される他の任意の場所には、シェルの視覚階層に表されない任意の詳細ページへの追加のルートを、明示的に登録できます。 それには Routing.RegisterRoute メソッドを使います。

Routing.RegisterRoute("monkeydetails", typeof(MonkeyDetailPage));
Routing.RegisterRoute("beardetails", typeof(BearDetailPage));
Routing.RegisterRoute("catdetails", typeof(CatDetailPage));
Routing.RegisterRoute("dogdetails", typeof(DogDetailPage));
Routing.RegisterRoute("elephantdetails", typeof(ElephantDetailPage));

この例では、Shell サブクラスに定義されていない詳細ページを、ルートとして登録します。 これらの詳細ページには、URI ベースのナビゲーションを使用して、アプリケーション内の任意の場所から移動できます。 このようなページのルートは、"グローバル ルート" と呼ばれます。

警告

Routing.RegisterRoute メソッドが 2 つ以上の異なる型に同じルートを登録しようとすると、ArgumentException がスローされます。

または、必要に応じて、別のルート階層にページを登録できます。

Routing.RegisterRoute("monkeys/details", typeof(MonkeyDetailPage));
Routing.RegisterRoute("bears/details", typeof(BearDetailPage));
Routing.RegisterRoute("cats/details", typeof(CatDetailPage));
Routing.RegisterRoute("dogs/details", typeof(DogDetailPage));
Routing.RegisterRoute("elephants/details", typeof(ElephantDetailPage));

この例では、monkeys ルートのページから detailsルートに移動すると MonkeyDetailPage が表示される、コンテキストに応じたページ ナビゲーションを実現しています。 同様に、elephants ルートのページから details ルートに移動すると ElephantDetailPage が表示されます。 詳細については、「コンテキストに応じたナビゲーション」を参照してください。

Note

Routing.RegisterRoute メソッドを使ってルートが登録されたページは、必要に応じて、Routing.UnRegisterRoute メソッドを使って登録解除できます。

ナビゲーションを実行する

ナビゲーションを実行するには、最初に Shell サブクラスへの参照を取得する必要があります。 この参照は、App.Current.MainPage プロパティを Shell オブジェクトにキャストするか、または Shell.Current プロパティを経由して取得できます。 その後、Shell オブジェクト上の GoToAsync メソッドを呼び出すことで、ナビゲーションを実行できます。 このメソッドでは ShellNavigationState へ移動して、ナビゲーションのアニメーションが終わったら完了する Task を返します。 ShellNavigationState オブジェクトは、string または Uri から、GoToAsync メソッドによって構成され、string または Uri 引数に設定された Location プロパティを備えています。

重要

シェルの視覚階層のルートに移動する場合、ナビゲーション スタックは作成されません。 しかし、シェルの視覚階層にはないページに移動する場合は、ナビゲーション スタックが作成されます。

Shell オブジェクトの現在のナビゲーションの状態は、Shell.Current.CurrentState プロパティ経由で取得できます。Location プロパティに、表示されるルートの URI が含まれます。

絶対ルート

有効な絶対 URI を GoToAsync メソッドへの引数として指定することで、ナビゲーションを実行できます。

await Shell.Current.GoToAsync("//animals/monkeys");

この例では、ShellContent オブジェクトに対して定義されたルートを使って、monkeys ルートのページへ移動します。 monkeys ルートを表している ShellContent オブジェクトは FlyoutItem オブジェクトの子であり、そのルートは animals になっています。

相対ルート

有効な相対 URI を GoToAsync メソッドへの引数として指定することで、ナビゲーションを実行することもできます。 ルーティング システムでは、ShellContent オブジェクトの URI との一致を試みます。 そのため、アプリケーション内のすべてのルートが一意の場合は、相対 URI として一意のルート名を指定するだけで、ナビゲーションを実行できます。

次の相対ルート形式がサポートされます。

書式 説明
route 現在の位置から上位方向に、指定されたルートを求めてルート階層が検索されます。 一致するページがナビゲーション スタックにプッシュされます。
/route 現在の位置から下位方向に、指定されたルートを求めてルート階層が検索されます。 一致するページがナビゲーション スタックにプッシュされます。
//route 現在の位置から上位方向に、指定されたルートを求めてルート階層が検索されます。 一致するページによって、ナビゲーション スタックが置き換えられます。
///route 現在の位置から下位方向に、指定されたルートを求めてルート階層が検索されます。 一致するページによって、ナビゲーション スタックが置き換えられます。

次の例では、monkeydetails ルートのページに移動します。

await Shell.Current.GoToAsync("monkeydetails");

この例では、一致するページが見つかるまで、monkeyDetails ルートが階層の上位方向に検索されます。 該当するページが見つかったら、ナビゲーション スタックにプッシュされます。

コンテキストに応じたナビゲーション

相対ルートでは、コンテキストに応じたナビゲーションが可能です。 たとえば、次のようなルート階層を検討します。

monkeys
  details
bears
  details

monkeys ルートに登録したページが表示されているときに、details ルートに移動すると、monkeys/details ルートに登録したページが表示されます。 同様に、bears ルートに登録したページが表示されているときに、details ルートに移動すると、bears/details ルートに登録したページが表示されます。 この例でのルートの登録方法については、「ページのルートを登録する」をご覧ください。

後方ナビゲーション

".." を GoToAsync メソッドへの引数として指定することで、後方ナビゲーションを実行できます。

await Shell.Current.GoToAsync("..");

".." を使用した後方ナビゲーションは、ルートと組み合わせることもできます。

await Shell.Current.GoToAsync("../route");

この例では、後方ナビゲーションが実行されてから、指定したルートへ移動します。

重要

後方ナビゲーション後に指定したルートに移動するには、指定したルートに移動するように、後方ナビゲーションによってルート階層の現在の場所に移動する必要があります。

同様に、後方に複数回移動してから、指定したルートに移動することもできます。

await Shell.Current.GoToAsync("../../route");

この例では、後方ナビゲーションが 2 回実行されてから、指定したルートに移動します。

さらに、後方に移動する場合は、クエリのプロパティを介してデータを渡すこともできます。

await Shell.Current.GoToAsync($"..?parameterToPassBack={parameterValueToPassBack}");

この例では、後方ナビゲーションが実行されてから、クエリ パラメーターの値が前のページのクエリ パラメーターに渡されます。

Note

クエリ パラメーターは、任意の後方ナビゲーション要求に追加することができます。

移動時にデータを渡す方法の詳細については、「データを渡す」を参照してください。

無効なルート

次のルート形式は無効です。

形式 説明
//page または ///page 現在、グローバル ルートをナビゲーション スタック上の唯一のページにはできません。 そのため、グローバル ルートへの絶対ルーティングはサポートされていません。

これらのルート形式を使用すると、Exception がスローされます。

警告

存在しないルートへのナビゲーションを試行すると、ArgumentException 例外がスローされます。

ナビゲーションをデバッグする

一部の Shell クラスは、クラスまたはフィールドがデバッガーによって表示される方法を指定する DebuggerDisplayAttribute によって修飾されています。 これにより、ナビゲーション要求に関連付けられたデータを表示して、ナビゲーション要求をデバッグできます。 たとえば、次のスクリーンショットには、Shell.Current オブジェクトの CurrentItem および CurrentState プロパティが表示されています。

デバッガーのスクリーンショット

この例では、FlyoutItem 型の CurrentItem プロパティによって、FlyoutItem オブジェクトのタイトルとルートを表示します。 同様に、ShellNavigationState 型の CurrentState プロパティによって、シェル アプリケーション内で表示されるルートの URI を表示します。

Tab クラスでは、Tab 内の現在のナビゲーション スタックを表す IReadOnlyList<Page> 型の Stack プロパティを定義します。 また、クラスでは、オーバーライドできる次のようなナビゲーション メソッドを提供しています。

  • GetNavigationStack: 現在のナビゲーション スタックを示す IReadOnlyList<Page> を返します。
  • OnInsertPageBefore: INavigation.InsertPageBefore が呼び出されたときに、呼び出されます。
  • OnPopAsync: Task<Page> を返し、INavigation.PopAsync が呼び出されたときに、呼び出されます。
  • OnPopToRootAsync: Task を返し、INavigation.OnPopToRootAsync が呼び出されたときに、呼び出されます。
  • OnPushAsync: Task を返し、INavigation.PushAsync が呼び出されたときに、呼び出されます。
  • OnRemovePage: INavigation.RemovePage が呼び出されたときに、呼び出されます。

OnRemovePage メソッドをオーバーライドする方法を次の例に示します。

public class MyTab : Tab
{
    protected override void OnRemovePage(Page page)
    {
        base.OnRemovePage(page);

        // Custom logic
    }
}

この例では、MyTab オブジェクトは、Tab オブジェクト内ではなく、シェルのビジュアル階層内で使用されます。

Shell クラスでは、プログラムによるナビゲーションまたはユーザー操作のどちらかに起因して、ナビゲーションが実行されるときに発生する Navigating イベントを定義しています。 Navigating イベントに伴う ShellNavigatingEventArgs オブジェクトでは、次のプロパティを提供しています。

プロパティ タイプ 説明
Current ShellNavigationState 現在のページの URI。
Source ShellNavigationSource 発生したナビゲーションの種類。
Target ShellNavigationState ナビゲーションの発信先を表す URI。
CanCancel bool ナビゲーションをキャンセルできるかどうかを示す値。
Cancelled bool ナビゲーションがキャンセルされたかどうかを示す値。

さらに、ShellNavigatingEventArgs クラスには、ナビゲーションを取り消すために使用できる Cancel メソッドと、ナビゲーションを完了するために使用できる ShellNavigatingDeferral トークンを返す GetDeferral メソッドが用意されています。 ナビゲーションの遅延の詳細については、「ナビゲーションの遅延」を参照してください。

また、Shell クラスでは、ナビゲーションが完了したときに発生する Navigated イベントも定義しています。 Navigated イベントに伴う ShellNavigatedEventArgs オブジェクトでは、次のプロパティを提供しています。

プロパティ タイプ 説明
Current ShellNavigationState 現在のページの URI。
Previous ShellNavigationState 前のページの URI。
Source ShellNavigationSource 発生したナビゲーションの種類。

重要

Navigating イベントが発生すると、OnNavigating メソッドが呼び出されます。 同様に、Navigated イベントが発生すると、OnNavigated メソッドが呼び出されます。 どちらのメソッドも、Shell サブクラスでオーバーライドして、ナビゲーション要求をインターセプトすることができます。

ShellNavigatedEventArgs および ShellNavigatingEventArgs クラスの両方に、ShellNavigationSource 型の Source プロパティがあります。 この列挙体では、次の値を提供しています。

  • Unknown
  • Push
  • Pop
  • PopToRoot
  • Insert
  • Remove
  • ShellItemChanged
  • ShellSectionChanged
  • ShellContentChanged

そのため、ナビゲーションを OnNavigating オーバーライドでインターセプトでき、アクションをナビゲーション ソースに基づいて実行できます。 たとえば、次のコードでは、ページ上のデータが未保存の場合に、前に戻るナビゲーションをキャンセルする方法を示しています。

protected override void OnNavigating(ShellNavigatingEventArgs args)
{
    base.OnNavigating(args);

    // Cancel any back navigation.
    if (args.Source == ShellNavigationSource.Pop)
    {
        args.Cancel();
    }
// }

シェルのナビゲーションは、インターセプトされ、ユーザーの選択に基づいて完了またはキャンセルされます。 これを実現するには、Shell サブクラス内の OnNavigating メソッドをオーバーライドし、ShellNavigatingEventArgs オブジェクト上の GetDeferral メソッドを呼び出します。 このメソッドからは、Complete メソッドを含む ShellNavigatingDeferral トークンが返され、ナビゲーション要求を完了するために使用できます。

public MyShell : Shell
{
    // ...
    protected override async void OnNavigating(ShellNavigatingEventArgs args)
    {
        base.OnNavigating(args);

        ShellNavigatingDeferral token = args.GetDeferral();

        var result = await DisplayActionSheet("Navigate?", "Cancel", "Yes", "No");
        if (result != "Yes")
        {
            args.Cancel();
        }
        token.Complete();
    }    
}

この例では、ナビゲーション要求を完了またはキャンセルするユーザーを招待するアクション シートが表示されます。 ShellNavigatingEventArgs オブジェクト上の Cancel メソッドを呼び出すと、ナビゲーションは取り消されます。 ShellNavigatingEventArgs オブジェクト上の GetDeferral メソッドによって取得された ShellNavigatingDeferral トークン上で Complete メソッドを呼び出すことで、ナビゲーションは完了します。

警告

保留中のナビゲーション遅延があるときにユーザーが移動しようとすると、GoToAsync メソッドから InvalidOperationException がスローされます。

データを渡す

データは、URI ベースのプログラムによるナビゲーションを実行するときに、クエリ パラメーターとして渡すことができます。 これは、ルートの後に ? を追加し、その後にクエリ パラメーター ID、=、値の順に指定することで実現されます。 たとえば、ユーザーが ElephantsPage上の象を選択した場合に、サンプル アプリケーションでは次のコードが実行されます。

async void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    string elephantName = (e.CurrentSelection.FirstOrDefault() as Animal).Name;
    await Shell.Current.GoToAsync($"elephantdetails?name={elephantName}");
}

このコード サンプルでは、CollectionView 内の現在選択されているゾウを取得し、elephantName をクエリ パラメーターとして渡して elephantdetails ルートに移動します。

ナビゲーション データを受信するには、次の 2 つの方法があります。

  1. 移動先ページを表すクラスまたはページの BindingContext に対応するクラスを、各クエリ パラメーターの QueryPropertyAttribute で修飾できます。 詳細については、「クエリ プロパティ属性を使用してナビゲーション データを処理する」を参照してください。
  2. 移動先のページを表すクラス、またはページの BindingContext のクラスを使用すると、IQueryAttributable インターフェイスを実装できます。 詳細については、「単一のメソッドを使用してナビゲーションデータを処理する」を参照してください。

クエリ プロパティ属性を使用してナビゲーション データを処理する

ナビゲーション データは、受信クラスを各クエリ パラメーターの QueryPropertyAttribute で装飾すると受信することができます。

[QueryProperty(nameof(Name), "name")]
public partial class ElephantDetailPage : ContentPage
{
    public string Name
    {
        set
        {
            LoadAnimal(value);
        }
    }
    ...

    void LoadAnimal(string name)
    {
        try
        {
            Animal animal = ElephantData.Elephants.FirstOrDefault(a => a.Name == name);
            BindingContext = animal;
        }
        catch (Exception)
        {
            Console.WriteLine("Failed to load animal.");
        }
    }    
}

QueryPropertyAttribute の最初の引数には、データを受信するプロパティの名前を指定し、2 番目の引数にはクエリ パラメータ― ID を指定します。そのため、上の例にある QueryPropertyAttributeでは、GoToAsync メソッドの呼び出しにおいて URI から nameクエリ パラメータ―に渡されたデータを Name プロパティが受信するように、指定しています。 Name プロパティ セッターにより、LoadAnimal メソッドが呼び出されて nameAnimal オブジェクトが取得され、それがページの BindingContext として設定されます。

Note

QueryPropertyAttribute を介して受信したクエリ パラメーター値は、自動的に URL デコードされます。

単一のメソッドを使用してナビゲーション データを処理する

ナビゲーション データは、受信クラスに IQueryAttributable インターフェイスを実装すると受信することができます。 IQueryAttributable インターフェイスを使用して、実装するクラスで ApplyQueryAttributes メソッドを実装する必要があることを指定します。 このメソッドには、ナビゲーション中に渡されたデータを含む IDictionary<string, string> 型の query 引数があります。 ディクショナリ内の各キーはクエリ パラメーター ID であり、その値はクエリ パラメーター値です。 この方法を使用する利点は、1 つのメソッドを使用してナビゲーション データを処理できることです。これは、全体として処理が必要なナビゲーション データの複数の項目がある場合に便利です。

次の例は、IQueryAttributable インターフェイスを実装するビュー モデル クラスを示しています。

public class MonkeyDetailViewModel : IQueryAttributable, INotifyPropertyChanged
{
    public Animal Monkey { get; private set; }

    public void ApplyQueryAttributes(IDictionary<string, string> query)
    {
        // The query parameter requires URL decoding.
        string name = HttpUtility.UrlDecode(query["name"]);
        LoadAnimal(name);
    }

    void LoadAnimal(string name)
    {
        try
        {
            Monkey = MonkeyData.Monkeys.FirstOrDefault(a => a.Name == name);
            OnPropertyChanged("Monkey");
        }
        catch (Exception)
        {
            Console.WriteLine("Failed to load animal.");
        }
    }
    ...
}

この例では、ApplyQueryAttributes メソッドを使用して、GoToAsync メソッド呼び出しの URI から name クエリ パラメーターの値を取得します。 次に、LoadAnimal メソッドを呼び出して、Animal オブジェクトを取得します。このオブジェクトは、データ バインド先の Monkey プロパティの値として設定されます。

重要

IQueryAttributable インターフェイスを介して受信したクエリ パラメータ値ーは、自動的に URL デコードされません。

複数のクエリ パラメーターを渡して処理する

複数のクエリ パラメーターを & と接続することで、これらのパラメーターを渡すことができます。 たとえば、次のコードでは 2 つのデータ項目が渡されます。

async void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    string elephantName = (e.CurrentSelection.FirstOrDefault() as Animal).Name;
    string elephantLocation = (e.CurrentSelection.FirstOrDefault() as Animal).Location;
    await Shell.Current.GoToAsync($"elephantdetails?name={elephantName}&location={elephantLocation}");
}

このコード サンプルでは、CollectionView 内の現在選択されているゾウを取得し、elephantName および elephantLocation をクエリ パラメーターとして渡して elephantdetails ルートに移動します。

データの複数の項目を受信するために、移動先ページを表すクラスまたはページの BindingContext に対応するクラスを、各クエリ パラメーターの QueryPropertyAttribute で修飾することができます。

[QueryProperty(nameof(Name), "name")]
[QueryProperty(nameof(Location), "location")]
public partial class ElephantDetailPage : ContentPage
{
    public string Name
    {
        set
        {
            // Custom logic
        }
    }

    public string Location
    {
        set
        {
            // Custom logic
        }
    }
    ...    
}

この例では、クラスは各クエリ パラメーターの QueryPropertyAttribute によって修飾されています。 最初の QueryPropertyAttribute では、name クエリ パラメーターに渡されたデータを Name プロパティが受信するように指定しており、2 番目の QueryPropertyAttribute では、location クエリ パラメーターに渡されたデータを Location プロパティが受信するように指定しています。 どちらの場合も、クエリ パラメーターの値は、GoToAsync メソッド呼び出しの URI で指定されます。

または、移動先のページを表すクラスまたはページの BindingContext のクラスに IQueryAttributable インターフェイスを実装することで、1 つのメソッドでナビゲーション データを処理することもできます。

public class ElephantDetailViewModel : IQueryAttributable, INotifyPropertyChanged
{
    public Animal Elephant { get; private set; }

    public void ApplyQueryAttributes(IDictionary<string, string> query)
    {
        string name = HttpUtility.UrlDecode(query["name"]);
        string location = HttpUtility.UrlDecode(query["location"]);
        ...        
    }
    ...
}

この例では、ApplyQueryAttributes メソッドを使用して、GoToAsync メソッド呼び出しの URI から name および location のクエリ パラメーターの値を取得します。

[戻る] ボタンの動作

戻るボタンの外観と動作は、BackButtonBehavior 添付プロパティを BackButtonBehavior オブジェクトに設定することによって再定義できます。 BackButtonBehavior クラスには、次のプロパティが定義されています。

  • Command: ICommand 型、戻るボタンが押されたときに実行されます。
  • CommandParameter: object 型、Command に渡されるパラメーター。
  • IconOverride: ImageSource 型、戻るボタンに使用されるアイコンです。
  • boolean 型の IsEnabled は、戻るボタンが有効かどうかを示します。 既定値は true です。
  • TextOverride: string 型、戻るボタンに使用されるテキスト。

これらのプロパティはすべて、BindableProperty オブジェクトを基盤としています。つまり、プロパティはデータ バインディングの対象にすることができます。

次のコードは、戻るボタンの外観と動作を再定義する例を示しています。

<ContentPage ...>    
    <Shell.BackButtonBehavior>
        <BackButtonBehavior Command="{Binding BackCommand}"
                            IconOverride="back.png" />   
    </Shell.BackButtonBehavior>
    ...
</ContentPage>

同等の C# コードを次に示します。

Shell.SetBackButtonBehavior(this, new BackButtonBehavior
{
    Command = new Command(() =>
    {
        ...
    }),
    IconOverride = "back.png"
});

Command プロパティは、戻るボタンが押されたときに実行されるように ICommand に設定され、IconOverride プロパティは、戻るボタンに使用されるアイコンに設定されます。

iOS および Android 上でシェルの戻るボタン アイコンをオーバーライドするスクリーンショット