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)。

相关推荐
xiancai_xianyu1 小时前
想把数据模型一次建完美再上AI?会一直卡在建模里
开发语言·人工智能·php·数据模型·语义层·本体建模·企业知识网络
(Charon)1 小时前
【C++】网络缓冲区设计(二):Ring Buffer环形缓冲区、head/tail与跨界读写
开发语言·c++
Java后端的Ai之路2 小时前
LangChain Deep Agents 从入门到企业实战
开发语言·人工智能·python·langchain·deepagents
海盗12342 小时前
微软技术周报 2026-08-31~09-07:GPT-6 Astra 登陆 Foundry、M365 全球认证故障复盘、C# 15 封闭层级
gpt·microsoft·c#
会飞的拖把2 小时前
Python文件操作详解:从文件读写到os、shutil模块实战
开发语言·python
RS迷途小书童2 小时前
Python 解析大疆无人机 SRT 字幕日志
开发语言·python·无人机
点心的游戏开发世界2 小时前
GDScript 入门笔记(十六):文件读写与数据持久化
开发语言·笔记·游戏引擎·godot
会飞的拖把2 小时前
Python序列详解:列表、元组、字符串的通用操作(超详细版)
开发语言·windows·python
reasonsummer3 小时前
【办公类-115-01】20260906育儿知识(家园小报)批量制作(2026年9月-2027年6月)
开发语言·数据库·c#
君顾13 小时前
智慧场馆解决方案小程序系统实战:从架构设计到上线指南
java·开发语言·智慧场馆