记录一次Prism报错

前提:我的WPF程序在进入主程序之前显示登录界面
此时不想登录,点击退出的时候报错了
报错提示

An exception occurred while initializing module 'ShellModule'. 
    - The exception message was: An exception has occurred while trying to add a view to region 'AsideRegion'. 
    - The most likely causing exception was was: 'Prism.Ioc.ContainerResolutionException: An unexpected error occurred while resolving 'Kstopa.Lx.EAP.Shell.Views.AsideMenuView'

源代码

 [Module(ModuleName = "ShellModule", OnDemand =true)]
 public class ShellModule : IModule
 {
     public void OnInitialized(IContainerProvider containerProvider)
     {
         var regionManager = containerProvider.Resolve<IRegionManager>();        
         regionManager.RegisterViewWithRegion(RegionNames.AsideRegion, typeof(AsideMenuView));      
         regionManager.RegisterViewWithRegion(RegionNames.ContentRegion, typeof(HomeView)); 
     }
}

当程序关闭时,我写了

 private void ExcuteLogOut()
 {
     Application.Current.Shutdown();
 }

为什么代码会报错:
在上面的代码中,错误是在 ShellModule 的 OnInitialized 方法中发生的,这是因为在 LoginWindow 显示对话框并返回 false(表示用户取消登录)时,调用了 Application.Current.Shutdown();。在应用程序关闭的过程中,如果还有未完成的操作,如模块初始化中的视图注册,就可能会抛出异常。具体来说,ContainerResolutionException 表明在尝试解析 AsideMenuView 类型时出错,可能是因为在关闭应用程序时,依赖注入容器正在尝试创建或查找该视图的实例,但由于应用程序正在关闭,某些资源可能已经不可用。
解决方案1、将代码写在主程序的构造器

 public MainWindowViewModel(IUserService userService, IContainerProvider provider) : base(provider)
 {
       RegionManager.RegisterViewWithRegion(RegionNames.AsideRegion, typeof(AsideMenuView)); 
       RegionManager.RegisterViewWithRegion(RegionNames.ContentRegion, typeof(HomeView)); 
 }

改成写在 MainWindowViewModel 的构造器为什么不报错:
当你将视图注册的逻辑移动到 MainWindowViewModel 的构造函数中时,注册发生在 MainWindow 已经显示之后。这意味着视图注册是在应用程序的主要窗口和其依赖项都已正确初始化之后进行的。由于 MainWindow 是应用程序的主窗口,其视图模型的构造函数会在窗口加载后不久被调用,此时应用程序的生命周期尚未进入关闭阶段,因此不会遇到在模块初始化时尝试注册视图时发生的问题。
解决方案2、改成 RequestNavigate

 [Module(ModuleName = "ShellModule", OnDemand =true)]
 public class ShellModule : IModule
 {
     public void OnInitialized(IContainerProvider containerProvider)
     {
         var regionManager = containerProvider.Resolve<IRegionManager>();
         regionManager.RequestNavigate(RegionNames.ContentRegion, "HomeView");
         regionManager.RequestNavigate(RegionNames.AsideRegion, "AsideMenuView");
     }
}

使用 RequestNavigate 方法代替 RegisterViewWithRegion 时,导航请求是按需进行的。这意味着视图的创建和添加到区域是延迟的,直到用户实际导航到该视图。当你在 ShellModule 的 OnInitialized 方法中使用 RequestNavigate 时,你不是在注册视图类型,而是在请求 Prism 容器导航到特定的视图。这种方式下,视图的创建和添加是在用户与应用程序交互(如点击登录窗口的取消按钮)之后进行的,因此不会引起在应用程序关闭时尝试访问正在关闭的资源的问题。

综上所述,更改后的两种方法都避免了在应用程序关闭时尝试执行初始化或注册操作,这是导致原始错误的根本原因。将视图注册逻辑移至 MainWindowViewModel 或使用 RequestNavigate 都是在应用程序的生命周期中更安全的时间点执行相关操作,从而避免了异常的发生。
解决方案3、修改退出程序的方法
原本的退出为

 private void ExcuteLogOut()
 {
     Application.Current.Shutdown();
 }

3-1、传递参数Window

 private void ExcuteLogOut(Window win)
 {
     win.Close();
 }

3-2、即使不传递参数,查找此时显示的界面,去退出

 private void ExcuteLogOut()
 {
    var activeWindow = Application.Current.Windows.OfType<Window>().SingleOrDefault(w => w.IsActive);
activeWindow?.Close();
 }

3-3、强制退出

 private void ExcuteLogOut()
 {
     Environment.Exit(0);
 }
posted @ 2024-04-22 21:27  孤沉  阅读(142)  评论(0编辑  收藏  举报