跳到主要内容

8.8 PrismStudy 实战与验收

学习目标​

  • 把容器、命令、Region、对话框和模块放进同一个应用。
  • 观察页面复用、草稿确认和事件退订的实际边界。
  • 用已有 ASP.NET Core API 练习异步迁移。

示例结构与原理​

完整源码在本地 examples/PrismStudy,运行清单见其中的 README.md。这是独立应用,使用 .NET 10 WPF、Prism.DryIoc 9.0.537 和本地内存。重启恢复数据,首次运行专注对象关系。Prism 9 的社区/商业许可及适用条件见 官网。

PrismStudy/
PrismStudy.csproj
App.xaml / App.xaml.cs
Views/ Shell、TasksView、SettingsView、ConfirmationDialog
ViewModels/ 对应的四个 ViewModel
Models/ TodoItem.cs
Services/ ITaskStore.cs、MemoryTaskStore.cs
Events/ TaskAddedEvent.cs
Modules/ TasksModule.cs

App 是组合入口,Prism 容器解析 Shell;模块注册页面。下面是模块 RegisterTypes 的方法体片段,完整类已在源码中:

Modules/TasksModule.cs:注册片段
containerRegistry.RegisterForNavigation<TasksView, TasksViewModel>("Tasks");
containerRegistry.RegisterForNavigation<SettingsView, SettingsViewModel>("Settings");

Shell 的 ContentControl 提供 MainRegion,Loaded 完成后首次导航到 Tasks。模块初始化时不导航,因为窗口尚未显示。导航期间禁用两个导航命令,回调展示成功、取消或异常。

从后端经验看,容器仍负责组装依赖,但桌面页面没有 HTTP 请求结束后的自动作用域。内存服务单例存活到应用结束,设置 ViewModel 由 Region 保留;导航到别的页面只是改变激活状态,不能据此判断对象已经销毁。

任务输入、选择和状态由 TasksViewModel 保存。标题去空格后限 1~120 个字符,按钮禁用和执行守卫同时检查;删除只接受确认结果 Yes。新增后发布标题,Shell 用 LastEvent 和 AddedCount 展示消息,每次新增只计一次。

设置页用 KeepAlive=true 和 IsNavigationTarget=true 保留、复用实例。保存更新已保存值;未保存时离开弹出确认,Yes 还原已保存值再继续,No 或 X 保留草稿并阻止导航。回调只调用一次,VisitCount 帮助观察成功进入次数。详见 导航生命周期。

Prism 9 导航结果看 Success、Cancelled、Exception,对话框结果仍看 Result。9.0.537 的 WPF Region 在离开确认返回 false 时可能不设置 Cancelled;本例按成功、异常、无异常未继续依次判断,正确显示用户取消。确认窗口由服务创建,关闭监听器也由服务初始化;ViewModel 调用 RequestClose.Invoke 即可。两类回调不能混用,排查时先确认操作属于导航还是对话框。

运行步骤​

在 Windows 安装 .NET 10 SDK,确认 SDK 列表有 10.x,再从仓库根目录运行:

dotnet --list-sdks
dotnet restore examples/PrismStudy/PrismStudy.csproj
dotnet build examples/PrismStudy/PrismStudy.csproj
dotnet run --project examples/PrismStudy/PrismStudy.csproj

交付环境没有 SDK,未编译或运行此 WPF 示例。源码检查不能代替桌面验收;请把自己实际看到的结果记录下来。

练习与验收​

操作预期结果
空白、121 字符、正常标题前两者新增禁用,正常标题可新增
新增带首尾空格的标题列表去空格,次数加 1,最近消息更新
删除时取消或 X,再确认先保留,确认后移除,未选中时禁用
修改设置后离开并取消停留设置页,草稿仍在,状态显示取消
再离开并确认,返回设置已恢复保存值,脏标记消失
保存新值,多次往返页面新值保留,访问计数递增,消息不重复
关闭主窗口显式退订,进程退出,重启恢复初始值

EventAggregator 首次在 UI 线程创建,订阅使用 UIThread。Shell 只在构造时订阅,Closed 时调用 Dispose 退订;Region 保留页面并不负责释放所有资源,弱引用也不代替清理。复习 事件聚合。

下一步接入 TaskDesk API​

继续沿用 原 API 契约,无需再创建 API。参考本地 examples/TaskDesk/TaskDesk.Client/Services 的 HTTP 服务,把同步 ITaskStore 改为异步接口,保留 JSON DTO 并转换成页面模型;逐步迁移查询、新增、删除。

为命令增加忙碌状态、取消 token、异常提示与 finally 恢复,避免 .Result 阻塞 UI。页面离开时取消页面所属请求,窗口关闭时等待活动操作结束。写请求被取消后先刷新确认服务端结果,成功新增后才发布事件。HttpClient 由 Prism 的组合入口注册并明确寿命,参阅 异步线程,不要另外创建第二套容器。

常见问题​

页面为空? 核对 MainRegion、导航注册名和 Loaded 时机。绑定不生效? 检查显式 ViewModel 配对或 Shell 的 AutoWire,查看绑定错误。对话框编译报错? 本例使用 Prism.Dialogs 和 DialogCloseListener 属性;Region 使用 Prism.Navigation.Regions,旧教程的命名和 RequestClose 事件需要按版本调整。

官方资料​