关于 maui-shell-navigation
面向 .NET MAUI Shell 导航的技能,介绍按需创建页面、通过查询传递数据、异步导航拦截,以及常见路由和导航问题。
主要功能
- 01使用 ContentTemplate 按需创建页面
- 02通过 IQueryAttributable 传递数据
- 03使用 ShellNavigationQueryParameters 传递复杂对象
- 04以异步检查延迟导航
- 05注册唯一路由并等待导航完成
适用场景
- 01减少 Shell 启动时创建的页面
- 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
始终将 ContentTemplate 与 DataTemplate 搭配使用,以便按需创建页面。
直接使用 Content 会在 Shell 初始化时创建所有页面,拖慢启动速度。
<ShellContent ContentTemplate="{DataTemplate views:HomePage}" />
<ShellContent>
<views:HomePage />
</ShellContent>
传递数据 — 优先使用 IQueryAttributable,而不是 QueryProperty
IQueryAttributable 可一次性获取所有参数,并且适用于视图模型:
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。 整个应用中的每个路由都必须唯一。 -
相对路由需要注册 — 除非通过
Routing.RegisterRoute注册了somepage,否则不能调用GoToAsync("somepage")。 可视层次结构中的页面则使用绝对//路由。 -
页面按需创建 — 使用
ContentTemplate时,页面构造函数仅在首次导航时运行。不要假设页面在启动时就已存在。 -
Tab.Stack 只读 — 不能直接操作导航堆栈;所有导航更改都应使用
GoToAsync。 -
GoToAsync 是异步方法 — 始终等待它完成 — 即发即弃式导航会导致竞态条件,也可能静默失败:
// ❌ Fire-and-forget — race conditions Shell.Current.GoToAsync("details"); // ✅ Always await await Shell.Current.GoToAsync("details"); -
路由层次结构很重要 — 绝对路由必须匹配可视层次结构中的完整路径(
//FlyoutItem/Tab/ShellContent)。路径错误会导致静默无操作,而不会抛出异常。