WPF PrismフレームワークのRegionが機能しない?

WPF PrismフレームワークのRegionが機能しない?

一般的なクライアントプロジェクトの標準的な操作フローは次のとおりです:ログインウィンドウを表示 → アカウント認証成功 → ログインウィンドウを閉じる → メインウィンドウを表示 → メインウィンドウで作業する。

最終更新 2021/01/07 10:53
沙漠尽头的狼
読了目安 3 分
カテゴリ
WPF
テーマ
WPF MVVMフレームワーク Prismシリーズ
タグ
.NET WPF Prism Region

サイト運営者は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>();
}

この問題に遭遇した人をインターネットで見つけました:

  1. WPF Prismフレームワークで先にログインウィンドウを表示し、その後メインウィンドウを開く(CSDNの議論スレッド、元のリンクはメンテナンスされていません)

議論スレッドは非常に盛況でしたが、求める回答は得られませんでした。

  1. prism – リージョンマネージャーがカスタムポップアップウィンドウ内でリージョンを見つけられない

この記事では手動でリージョンマネージャーを再登録する解決策を示していますが、サイト運営者は採用しませんでした。

RegionManager.SetRegionName( theNameOfTheContentControlInsideThePopup, WellKnownRegionNames.DataFeedRegion );
RegionManager.SetRegionManager( theNameOfTheContentControlInsideThePopup, theRegionManagerInstanceFromUnity );
  1. Prism MVVMアプリケーション ログイン後にメインウィンドウを切り替える実装

このコードでは、ログインフォームとメインフォームをユーザーコントロールとして扱い、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つの回答を見つけました。

Adding a Prism Login Screen

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

さらに探索

関連読書

その他の記事