サイト運営者は15年からPrism 4を使用し、昨年(2020年😊)にはPrism 8を使ってオープンソースプロジェクトも行っています。今日はPrism Regionの1つの問題について共有します。
問題の説明
一般的なクライアントプロジェクトの標準的な操作フローは以下の通りです:ログインウィンドウを表示 → アカウント認証成功 → ログインウィンドウを閉じる → メインウィンドウを表示 → メインウィンドウで作業を実行。
標準的なログインフロー

上の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)
{
// ここでは多くのコードを省略
region.RequestNavigate(menuItem.Key);
// ここでは多くのコードを省略
}
実際の実行時にナビゲーションが機能していないことが判明しました。元の操作では、ログイン成功後に直接新しいメインウィンドウが表示され、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)を登録し、シェルビュー内に1つのリージョンを設定し、そのリージョン内でナビゲーションによって2つのユーザーコントロールを切り替えます。結果的に問題はなく、メインウィンドウ内のリージョンは正常に使用できますが、ログイン画面とメイン画面のタイトルバーなどが通常異なるため、この方法は手間がかかり推奨できません。
問題3に類似した説明:Prism MVVMアプリケーション ログイン後にメインウィンドウを切り替える実装
アプリケーションシナリオ
Prism7を使用してWPFプログラムを開発し、コーディングはMVVM形式を採用しています。プログラム起動時にまずログイン画面が表示され、認証後、プログラムのレイアウトメインウィンドウに遷移します。
設計思想
WPFプログラムのフレームワークを構築後、プログラム内に1つのShell.xamlを配置します。これはパフォーマーの唯一のステージのようなものです。ログインフォーム(以下LoginView)とプログラムレイアウトのメインフォーム(以下MainView)をそれぞれIRegionManagerで管理し、必要に応じて適切なタイミングで順にパフォーマンスを行います。すべての操作は各ViewModel(略称VM)のコードで実行されます。
1. プログラム起動後、ShellはVMを介してRegionManagerのAddメソッドを使用してLoginViewをアクティブにします(注:サイト運営者の補足説明=ログイン認証成功後、LoginViewを破棄し、再度AddメソッドでMainViewをアクティブにします)
サイト運営者が採用した解決策
Baiduでは適切な解決策はほとんど見つかりませんでした。この問題は数日間悩ませました(毎晩2〜3時間取り組みましたが、普段の仕事ではWPFを扱っていません)。
幸いにも科学的方法(VPN)があり、YouTubeのAdding a Prism Login Screenで1つの回答を見つけました。

解決策のコードは非常にシンプルで、app.xaml.csに以下のコードを追加します。シェルの初期化(InitializeShell、shellはCreateShell()で登録されたメインウィンドウを指す)の前に、まずログインウィンドウを表示し、認証成功後にシェルを初期化します(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のサイトにコメントをお願いします。