站長 15 年開始使用 Prism 4,去年(2020 年 😊)也使用 Prism 8 做開源專案,今天分享處理 Prism Region 的一個問題。
問題描述
一般用戶端專案常規操作流程是:彈出登入視窗 => 帳號驗證成功 => 關閉登入視窗 => 彈出主視窗 => 在主視窗作業。
常規登入流程

像上面的 gif 圖主表單,左側是一棵樹,右側是 TabControl,使用 Prism 模組中注入檢視程式碼:
public class ModuleOfLogModule : IModule
{
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<MainTabItemView, MainTabItemViewModel>(KEY_OF_CURRENT_MODULE);
}
}
主工程 TabControl 為模組檢視顯示區域:
<TabControl
prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainTabRegion}"
/>
點擊左側選單樹時,動態導航模組檢視:
private void RaiseSelectedItemHandler(CustomMenuItem menuItem)
{
// 此處省略 N 多程式碼
region.RequestNavigate(menuItem.Key);
// 此處省略 N 多程式碼
}
實際運行時發現導航沒有起作用,原來的操作是登入成功,直接 New 的主表單彈出,app.xaml.cs 中註冊的登入表單檢視:
protected override Window CreateShell()
{
return Container.Resolve<LoginView>();
}
百度到也有人遇到這個問題:
- WPF Prism 框架下先登入表單再開啟主表單(CSDN 討論帖,原連結已不再維護)
討論區很火,沒看到想要的結果。
這篇給出的答案是手動再註冊區域管理器,站長沒有採用。
RegionManager.SetRegionName( theNameOfTheContentControlInsideThePopup, WellKnownRegionNames.DataFeedRegion );
RegionManager.SetRegionManager( theNameOfTheContentControlInsideThePopup, theRegionManagerInstanceFromUnity );
這個程式碼是將登入與主表單作為使用者控制項,app.xaml.cs 中註冊 shellview,shellview 中設定一個區域,兩個使用者控制項透過導航在這個區域切換,效果是沒問題,主表單內的區域能正常使用,但自訂的登入介面和主介面,一般標題列什麼的都不一樣,這種做法比較麻煩,不推薦使用。
看問題 3 類似的描述:Prism MVVM 應用 登入後切換主表單實現
應用場景
使用 Prism7 開發 WPF 程式,編碼採用 MVVM 形式。當程式啟動時,首先進入一個登入介面,進行登入認證,認證成功後轉入程式佈局主視窗。
設計思路
WPF 程式框架搭建後,程式中存一個 Shell.xaml,相當於表演者的唯一舞台。登入表單(以下簡稱 LoginView)和程式佈局主表單(以下簡稱 MainView),分別利用 IRegionManager 進行管理,根據需要在不同時機相繼出場表演。所有操作均由各自 ViewModel(簡稱 VM)程式碼完成。
1.當程式啟動後,Shell 透過 VM,使用 RegionManager 的 Add 方法激活 LoginView,(註:站長補充描述=登入驗證成功,登出 LoginView,再透過 Add 方法激活 MainView)
站長採用的解決方案
百度基本上沒有找到比較合適的方案了,這個問題糾結了我幾天(每天晚上搞 2、3 個小時,站長平時工作已經不做 WPF 了)。
還好我有翻牆的方法,在 YouTube 上 Adding a Prism Login Screen 找到一個答案。

解決方案的程式碼很簡單,在 app.xaml.cs 中添加如下程式碼,在初始化 shell 之前(InitializeShell,shell 指 CreateShell() 註冊的主表單),先彈出登入視窗,驗證成功再初始化 shell(base.InitializeShell(shell)):
protected override void InitializeShell(Window shell)
{
LoginView loginView = new LoginView();
if (loginView.ShowDialog() == true)
{
var shellVM = shell.DataContext as MainWindowViewModel;
shellVM.InitData();
base.InitializeShell(shell);
}
else
{
Application.Current.Shutdown(-1);
}
}
文末探討
其實該解決方案還是有問題的,在呼叫 InitializeShell(Window shell) 之前,站長偵錯發現模組檢視已經執行了初始化,按照道理來說應該是登入成功後模組才執行初始化的,更多思考留給你,有什麼建議歡迎到 Dotnet9 網站留言。