maui-shell-navigation について
.NET MAUI Shell のナビゲーション設計を扱う技能です。ページのオンデマンド生成、クエリを使ったデータ受け渡し、非同期の遷移ガード、ルートや遷移で起きやすい問題を説明します。
主な機能
- 01ContentTemplate によるページのオンデマンド生成
- 02IQueryAttributable によるデータ受け渡し
- 03ShellNavigationQueryParameters による複雑なオブジェクトの受け渡し
- 04非同期チェックによる遷移の保留
- 05一意なルート登録と遷移の await
活用シーン
- 01Shell 起動時に生成されるページを減らす
- 02遷移先に識別子やオブジェクトを渡す
- 03未保存の変更がある場合に離脱前の確認を行う
- 04ルート不一致や遷移の競合を調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ davidortinau/ maui-skills --skill maui-shell-navigationインストール後、Claude Code で/maui-shell-navigationを入力して読み込まれたか確認します。
同梱ファイルreferences/shell-navigation-api.md
詳細
.NET MAUI Shell ナビゲーション
重要な決定事項
ContentTemplate — 常に使用する
ページを必要に応じて作成するため、常に DataTemplate とともに ContentTemplate を使用してください。
Content を直接使用すると、Shell の初期化中にすべてのページが作成され、起動時間が長くなります。
<ShellContent ContentTemplate="{DataTemplate views:HomePage}" />
<ShellContent>
<views:HomePage />
</ShellContent>
データの受け渡し — QueryProperty より IQueryAttributable を優先する
IQueryAttributable を使うと、すべてのパラメーターを一度の呼び出しで取得でき、ViewModel でも使用できます。
public class AnimalDetailsViewModel : ObservableObject, IQueryAttributable
{
public void ApplyQueryAttributes(IDictionary<string, object> query)
{
if (query.TryGetValue("id", out var id))
AnimalId = id.ToString();
}
}
複雑なオブジェクトには、シリアル化を避けるため ShellNavigationQueryParameters を使用してください。
var parameters = new ShellNavigationQueryParameters
{
{ "animal", selectedAnimal }
};
await Shell.Current.GoToAsync("animaldetails", parameters);
ナビゲーションの制御 — 非同期デファーラルパターン
非同期のチェック(例:「未保存の変更を保存しますか?」)には GetDeferral() を使用してください。
protected override async void OnNavigating(ShellNavigatingEventArgs args)
{
base.OnNavigating(args);
if (hasUnsavedChanges && args.Source == ShellNavigationSource.Pop)
{
var deferral = args.GetDeferral();
bool discard = await ShowConfirmationDialog();
if (!discard)
args.Cancel();
deferral.Complete();
}
}
よくある落とし穴
-
ルート名の重複 —
Routing.RegisterRouteは、すでに登録済みのルート名、またはビジュアル階層のルートと一致するルート名に対してArgumentExceptionをスローします。 アプリ全体で、すべてのルート名を一意にする必要があります。 -
相対ルートには登録が必要 —
somepageがRouting.RegisterRouteで登録されていない限り、GoToAsync("somepage")は呼び出せません。ビジュアル階層のページには、代わりに絶対//ルートを使用します。 -
ページは必要に応じて作成される —
ContentTemplateを使用する場合、ページのコンストラクターが実行されるのは、初めてナビゲーションしたときだけです。起動時にページが存在すると思い込まないでください。 -
Tab.Stack は読み取り専用 — ナビゲーションスタックを直接操作することはできません。ナビゲーションの変更にはすべて
GoToAsyncを使用してください。 -
GoToAsync は非同期 — 必ず await する — ナビゲーションをファイア・アンド・フォーゲットで実行すると、競合状態が発生し、エラーが通知されずに失敗することがあります。
// ❌ Fire-and-forget — race conditions Shell.Current.GoToAsync("details"); // ✅ Always await await Shell.Current.GoToAsync("details"); -
ルート階層が重要 — 絶対ルートは、ビジュアル階層を通る完全なパス(
//FlyoutItem/Tab/ShellContent)と一致する必要があります。パスが間違っていると、例外ではなく何も起こらない状態になります。