C# WPF Prism 进阶(三):导航(Navigation)深入

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 定义了三个方法,对应导航的三个阶段:

  1. OnNavigatedTo(NavigationContext):导航到本页时调用,适合初始化、取参数。
  2. IsNavigationTarget(NavigationContext):是否复用已有实例 。返回 true 时,如果该 ViewModel 已经存在,Prism 会复用而不是新建。
  3. 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";
}

七、总结

  1. NavigationParameters 负责传参,接收方在 OnNavigatedTo 里用 GetValue<T>() 取值。
  2. IRegionAware 的三个方法管理导航生命周期;IsNavigationTarget 返回 true 可复用实例。
  3. IConfirmNavigationRequest 实现"离开前确认",continuationCallback 决定是否放行。
  4. IRegionNavigationJournal 提供前进/回退,RequestNavigate 回调可拿 NavigationResult 处理失败。

下一篇《事件聚合与对话框》讲模块间松耦合通信(IEventAggregator)和 MVVM 弹窗(IDialogService)。

相关推荐
xys_6784 分钟前
JavaEE通关手册:初识Java
java·开发语言
ShineWinsu1 小时前
对于Qt:QTableWidget常见属性以及QTableWidgetItem类的解析
开发语言·c++·qt·gui·客户端·表格·qtablewidget
ShineWinsu2 小时前
对于Qt:QListWidget常见属性以及QListWidgetItem类的解析
开发语言·c++·qt·客户端·列表·qlistwidget·qlistwidgetitem
吴名氏.3 小时前
Java转AI Agent教程(第十二周)检索与切分
java·开发语言·人工智能·ai·ai agent
公子小六3 小时前
基于.NET的Windows窗体编程之WinForms数据持久化(1)
windows·microsoft·c#·.net·winforms
瑞雪兆丰年兮3 小时前
JavaWeb-day10-SpringBootWeb案例
java·开发语言·javaweb·web
Elastic 中国社区官方博客3 小时前
更少的位数,相同的召回率:DiskBBQ 更保守的自动校准扫描
大数据·运维·开发语言·人工智能·elasticsearch·搜索引擎
三雷科技4 小时前
第6章第4节:自定义分词器
开发语言·c#
Adellle4 小时前
设计模式指南 (Java 版) ㊁
java·开发语言·设计模式
Delightrs5 小时前
Rust LeetCode238 算法题解
开发语言·算法·rust