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

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

前言

上一篇讲了 Region 和模块化,导航(RequestNavigate)是往区域里切换视图最完整的方式。但"切换视图"只是导航最浅的用法。真实的导航还涉及:传参、生命周期回调、离开确认、回退。本文把这些一次性讲透。

版本说明:本文基于 Prism 9.x 。导航相关类型在 Prism.Navigation.RegionsIRegionManagerNavigationContextIRegionAware 等)和 Prism.NavigationNavigationParameters)。

一、导航传参: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 提供 CanGoBackCanGoForwardGoBack()GoForward()

五、导航回调与结果:NavigationResult

RequestNavigate 有带回调的重载,可以在导航完成后拿到结果:

csharp 复制代码
_regionManager.RequestNavigate("ContentRegion", nameof(DetailView),
    result =>
    {
        if (result.Exception != null)
        {
            // 导航失败处理
            MessageBox.Show($"导航失败:{result.Exception.Message}");
        }
    },
    parameters);

NavigationResultPrism.Navigation 命名空间下,含 SuccessExceptionContext 等信息。

六、导航参数用强类型封装

直接传魔法字符串 "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)。

相关推荐
冯汉栩1 小时前
Swift Control DashLineView(虚线)
开发语言·ios·swift
覆东流1 小时前
4.Java运算符与表达式
java·开发语言·后端
SomeB1oody2 小时前
【RustyML入门】5.1. 回归指标
开发语言·后端·机器学习·rust·教程
龙虾PRO2 小时前
2026 DeepSeek Harness 部署完整教程:npx 一键启动至 Python SDK 全流程接入
开发语言·python
我是苏苏2 小时前
C#基础:不写for循环的五种方式
数据结构·算法·c#
小新讲网安4 小时前
WiFi安全攻防实战:WPA3新协议与传统破解技术全解析
开发语言·网络·安全·php·漏洞·nmap·漏洞检测
必须会一定会10 小时前
Agent Plugins 1.0实战:plugin.json、skills、mcp.json目录结构与迁移
开发语言·人工智能·ai编程
St_rive10 小时前
Page Object设计模式
java·开发语言·设计模式
wp123_110 小时前
硬件元器件笔记|IPX8 防水 Type‑C 母座安费诺 124018802112A 与 TONEVEE TY48086‑24A 分析
c语言·开发语言·笔记