内容
Prism.WpfでDialogServiceから呼び出したDialogの中にRegionを加えてRequestNavigateしたけれども、
ちょっと手を加えないと遷移しなかったため、その方法について記載します。
環境
- Prism.Unity Version="8.1.97"
- 試したサンプル
結論
DialogServiceを継承したクラスを用意して(ソース)
protected virtual void ConfigureDialogWindowContent(string dialogName, IDialogWindow window, IDialogParameters parameters)
をオーバーライドして
protected override void ConfigureDialogWindowContent(string dialogName, IDialogWindow window, IDialogParameters parameters)
{
var rm = _regionManager.CreateRegionManager();
RegionManager.SetRegionManager(window as Window, rm);
RegionManager.UpdateRegions();
parameters.Add("rm", rm);
base.ConfigureDialogWindowContent(dialogName, window, parameters);
}
こんな感じでRegionManagerを新規に作成し、Dialogとして表示されるWindowに割り当てます。
ViewModelにRegionManagerを伝えるためにIDialogParametersにインスタンスを追加します。
ViewModel側でRegionManagerを受け取ってRequestNavigateします。(ソース)
public void OnDialogOpened(IDialogParameters parameters)
{
if (parameters.TryGetValue<IRegionManager>("rm", out IRegionManager rm))
CustomDialogARegionManager = rm;
if (parameters.TryGetValue<string>("ViewName", out string v))
CustomDialogARegionManager.RequestNavigate("CustomDialogARegion", v);
else
CustomDialogARegionManager.RequestNavigate("CustomDialogARegion", "CustomDialogAAView");
}
Region間でのRequestNavigateはIRegionNavigationServiceを使用すれば意識する必要がなくなります。(参考)
発端
<ContentControl prism:RegionManager.RegionName="MyRegion" prism:RegionManager.RegionManager="{Binding MyRegionManager}" />
こんな感じでRegionManager添付プロパティを指定すれば出来ると思って実装したのですが出来ませんでした。
調べてみるといくつか言及している質問がありました。
- RegionManager unable to find region inside of module
- Cannot find Region in RegionManager (using PRISM)
- WPF, Prism v2, Region in a modal dialog, add region in code behind
いくつか抜粋してグーグル翻訳してみると
- 問題は、リージョンがビジュアルツリーでRegionManagerのアタッチされたプロパティを検索し、そのマネージャーに登録することです。メインウィンドウでは問題ありませんが、子ウィンドウではこれは発生しません。
- プレゼンタークラスのコンストラクターにリージョンマネージャーを登録する必要がありました。 そうすれば、新しいウィンドウのリージョンでグローバルリージョンマネージャーを見つけることができます。
- DialogServiceによって作成されたダイアログを含むサブウィンドウに自動的に継承されることはありません。したがって、ダイアログでリージョンを使用する場合は、リージョンマネージャーを手動でアタッチする必要があります。
等々。
メイン画面ではPrismさんが良い感じにアタッチしてくれてるみたいなのですが、新規に作成したWindowに関しては自分でアタッチしないといけないみたいです。
修正案
- Dialogで表示させるViewで個々にアタッチする実装を行う
- 一律Dialogに新規のRegionManagerをアタッチする実装を行う
- DialogではRegionを使用しない
- etc
とりあえず2.の方向で検討し、上記のような実装になりました。
デメリットですが、IDialogParametersを経由してRegionManagerの受け渡しを行うため、
それのキー(今回だと"rm")が予約語的になってしまうところです。
開発者間でわかっていれば問題ないことですが暗黙知になりそうです。
最後に
Prism.Wpfの7から8の変化として
- Bootstrapperの復活
- Dialog用のカスタムウィンドウを使い分けられるようになった
- Region初期表示用のメソッド(RegisterViewWithRegion)が使いやすくなった
等がありました。他にもあると思います。