Prism區域異常問題分析(導航失效?)


前文

本篇文章主要討論在WPF當中使用Prism區域導航的失效的問題, 在其它的博客當中也出現了多次討論這個問題以及對應的解決方法,
例如重寫OnInitialized方法等等。我認為這都不是解決問題的根源, 既然如此, 下面我們將來分析Prism的IRegionManager的具體流程。

Prism初始化過程

首先, 我們分析一下下面的代碼, 用於創建應用程序的主頁

       protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

那么, 在這個MainWindow當中, 如果我們定於以下一個區域, 則可以使用IRegionManager進行導航操作, 如下所示:

<ContentControl Grid.Row="1" prism:RegionManager.RegionName="ShowRegion" />

現在問題就來了, 一旦我們把這個窗口的實例銷毀, 自己重新創建一個MainWindow的時候, 你會發現你無法進行導航了, 這個時候就是大家理解的那個問題, 是Region失效了?
並不是, 為了解決這個問題, 我們需要了解Prism框架本身做了什么動作, 查看源代碼之后, 發現以下初始化代碼:

           var shell = CreateShell();  
            if (shell != null)
            {
                MvvmHelpers.AutowireViewModel(shell);
                RegionManager.SetRegionManager(shell, _containerExtension.Resolve<IRegionManager>());
                RegionManager.UpdateRegions();
                InitializeShell(shell);
            }

了解到, 從一開始獲取到MainWindow之后, 陸續進行了上下文綁定, 設置IRegionManager實例以及更新區域的操作。

在這里, 我們至少了解了幾個東西。

  • MainWindow的DataContext初始化的時機
  • MainWindow窗口當中IRegionManager的初始化過程
  • 區域刷新的動作

完成了這些動作之后, 最終ShowDialog展示了首頁, 於是,我們可以在這里愉快的使用IRegionManager進行導航操作。

分析結果

如果想要實現在某個窗口當中進行導航, 除了定義區域之外, 你還需要做的就是給窗口設置IRegionManager的實例以及刷新區域, 核心就是這兩行代碼:

 RegionManager.SetRegionManager(shell, _containerExtension.Resolve<IRegionManager>());
 RegionManager.UpdateRegions();

既然我們了解到這個之后, 還有一個問題也順其自然的解決了, 在Prism當中使用彈窗服務不能導航的問題, 因為在Prism框架提供的IDialogService中並沒有實現
設置IRegionManager以及刷新區域, 這就是問題的根源, 所以我們必須手動的去修改實現達到支持導航的功能。

彈窗中實現導航

示例: 以下代碼, 展示了如何在彈窗當中設置區域以及刷新區域的問題。

            var provider = ContainerLocator.Container.Resolve<IContainerProvider>();
            var regionManager = ContainerLocator.Container.Resolve<IRegionManager>();
            var win = provider.Resolve<object>("ShowWindow");
            if (win is Window view)
            {
                RegionManager.SetRegionManager(view, regionManager);
                RegionManager.UpdateRegions();

                view.ShowDialog();
            }

當然, 你完全可以自行實現IDialogService接口覆蓋Prism提供的內部實現, 以達到彈窗支持導航的行為, 例如:

   public interface IMyDialogService : IDialogService
    {

    }

    public class MyDialogService : DialogService, IMyDialogService
    {
        public MyDialogService(IContainerExtension containerExtension)
            : base(containerExtension)
        {
        }

        public new void ShowDialog(string name, IDialogParameters parameters, Action<IDialogResult> callback)
        {
            //...
        }
    }

注意

如果在彈窗服務當中設置區域, 在窗口再次打開的同時會提示區域名稱已注冊的問題, 則你需要在關閉前移除原有的所有區域名即可。

 regionManager.Regions.Remove("ShowRegion");

總結

對於任何窗口, 我們都可以使用IRegionManager進行導航操作, 在第一次框架初始化的時候, 只不過是Prism內部幫我們處理了區域的設置以及刷新行為。
而如何我們想在其它地方使用區域導航, 則需要手動設置區域以及刷新區域即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM