C# WPF Prism 进阶(三):导航(Navigation)深入
前言
上一篇讲了 Region 和模块化,导航(RequestNavigate)是往区域里切换视图最完整的方式。但"切换视图"只是导航最浅的用法。真实的导航还涉及:传参、生命周期回调、离开确认、回退。本文把这些一次性讲透。
版本说明:本文基于 Prism 9.x 。导航相关类型在
Prism.Navigation.Regions(IRegionManager、NavigationContext、IRegionAware等)和Prism.Navigation(NavigationParameters)。
一、导航传参:NavigationParameters
1.1 传参
csharp
var parameters = new NavigationParameters
{
{ "id", 42 },
{ "name", "张三" }
};
_regionManager.RequestNavigate("ContentRegion", nameof(DetailView), parameters);
1.2 接收参数
接收方 ViewModel 实现 IRegionAware(Prism 9;旧版为 INavigationAware),在 OnNavigatedTo 里取参数:
csharp
using Prism.Navigation.Regions;
public class DetailViewModel : BindableBase, IRegionAware
{
public void OnNavigatedTo(NavigationContext navigationContext)
{
if (navigationContext.Parameters.ContainsKey("id"))
{
Id = navigationContext.Parameters.GetValue<int>("id");
}
}
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
public void OnNavigatedFrom(NavigationContext navigationContext) { }
}
二、生命周期回调:IRegionAware 三兄弟
IRegionAware 定义了三个方法,对应导航的三个阶段:
OnNavigatedTo(NavigationContext):导航到本页时调用,适合初始化、取参数。IsNavigationTarget(NavigationContext):是否复用已有实例 。返回true时,如果该 ViewModel 已经存在,Prism 会复用而不是新建。OnNavigatedFrom(NavigationContext):离开本页时调用,适合清理资源、保存状态。
一个常见的坑:默认生成的 ViewModel 每次导航都会新建实例。如果你想在导航间保持状态 (比如列表页记住滚动位置),就实现 IsNavigationTarget 返回 true:
csharp
public bool IsNavigationTarget(NavigationContext navigationContext) => true; // 复用实例
三、离开确认:IConfirmNavigationRequest
编辑页面"未保存就离开要提醒",用 IConfirmNavigationRequest:
csharp
using Prism.Navigation.Regions;
public class EditorViewModel : BindableBase, IConfirmNavigationRequest
{
public void ConfirmNavigationRequest(NavigationContext navigationContext,
Action<bool> continuationCallback)
{
// 询问用户是否离开
bool canLeave = MessageBox.Show("有未保存的修改,确定离开吗?",
"提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes;
// true 允许导航,false 取消
continuationCallback(canLeave);
}
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
public void OnNavigatedFrom(NavigationContext navigationContext) { }
public void OnNavigatedTo(NavigationContext navigationContext) { }
}
四、导航日志与回退:Journal
Prism 会为每个区域维护导航历史(Journal),可以前进后退:
csharp
using Prism.Navigation.Regions;
public class DetailViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
public DetailViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
}
private void GoBack()
{
var region = _regionManager.Regions["ContentRegion"];
var journal = region.NavigationService.Journal; // IRegionNavigationJournal
if (journal.CanGoBack)
{
journal.GoBack();
}
}
}
IRegionNavigationJournal 提供 CanGoBack、CanGoForward、GoBack()、GoForward()。
五、导航回调与结果:NavigationResult
RequestNavigate 有带回调的重载,可以在导航完成后拿到结果:
csharp
_regionManager.RequestNavigate("ContentRegion", nameof(DetailView),
result =>
{
if (result.Exception != null)
{
// 导航失败处理
MessageBox.Show($"导航失败:{result.Exception.Message}");
}
},
parameters);
NavigationResult 在 Prism.Navigation 命名空间下,含 Success、Exception、Context 等信息。
六、导航参数用强类型封装
直接传魔法字符串 "id"、"name" 容易出错,推荐用一个常量类或扩展方法统一管理:
csharp
public static class NavigationKeys
{
public const string Id = "id";
public const string Name = "name";
}
七、总结
NavigationParameters负责传参,接收方在OnNavigatedTo里用GetValue<T>()取值。IRegionAware的三个方法管理导航生命周期;IsNavigationTarget返回true可复用实例。IConfirmNavigationRequest实现"离开前确认",continuationCallback决定是否放行。IRegionNavigationJournal提供前进/回退,RequestNavigate回调可拿NavigationResult处理失败。
下一篇《事件聚合与对话框》讲模块间松耦合通信(IEventAggregator)和 MVVM 弹窗(IDialogService)。