Prismを使用してサブウィンドウでRegionを使用した場合に発生したエラーと対処方法・その1
Prismを使用したWPFアプリケーションを開発していて、サブウィンドウでRegionを使用した場合に発生したエラーと対処方法
次の画面に遷移できない
現象
Regionを使用した画面遷移
ウィンドウのXAMLにRegionを設定し、コードビハインドで、IRegionManagerインターフェースのRegisterViewWithRegionメソッドを呼び出して、ユーザーコントロールとRegionを紐づける。
<Window x:Class="Regions.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" Title="Shell" Height="350" Width="525"> <Grid> <ContentControl prism:RegionManager.RegionName="ContentRegion" /> </Grid> </Window>
コードビハインド
using System.Windows; namespace Regions.Views { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA)); } } }
実行すると、ウィンドウにはユーザーコントロールの内容が表示される。
ユーザーコントロール上にあるボタンをクリックして、次の画面に遷移をしたいとする。Regionに設定されているユーザーコントロールを別のものに置き換えることで、画面遷移したように見せることが出来る。
具体的には、DIの設定時にRegisterForNavigationメソッドを使用してユーザーコントロールを登録しておき、ViewModelでIRegionManagerのRequestNavigateメソッドにRegionNameと表示したいユーザーコントロールを指定することで置き換えることができる。
App.xaml.cs(DI部分)
protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<ViewB>(); }
XAML(遷移ボタン)
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="5" > <Button Command="{Binding NavigateCommand}" CommandParameter="ViewB" Margin="5">Navigate to View B</Button> </StackPanel>
ViewModel(遷移処理)
public DelegateCommand<string> NavigateCommand { get; private set; } public MainWindowViewModel(IRegionManager regionManager) { _regionManager = regionManager; NavigateCommand = new DelegateCommand<string>(Navigate); } private void Navigate(string navigatePath) { if (navigatePath != null) _regionManager.RequestNavigate("ContentRegion", navigatePath); }
これはMainWindowでやると問題なく成功する(上記サンプルの詳細はこちらを参照)。
サブウィンドウでRegionを使用する
ある画面をサブウィンドウとして開くために、親ウィンドウから、サブウィンドウのShowメソッドもしくは、ShowDialogメソッドを呼び出した。
var subWindow = _container.Resolve<SubWindow>(); subWindow.ShowDialog();
サブウィンドウでも画面の切り替えをしたいので、サブウィンドウのXAMLにRegionを設定し、同様のコードを書いたが、実行すると次の画面に遷移できない(ユーザーコントロールが切り替わらない)。
対処方法
デバッグ実行でRegionManagerに登録されているRegionを調べてみると、サブウィンドウで指定したRegionNameが存在しない。 MainWindow(親ウィンドウ)でもRegionを設定して試してみると、MainWindowのRegionはあった。
ここから、ViewModelのDIで取得できるのは、MainWindowと関連付けられたRegionManagerであることがわかった。
サブウィンドウのRegionが、MainWindowのRegionManagerに登録できていない。登録がないため、RegionNameを指定しても画面遷移ができない。
調べてみると、サブウィンドウのXAMLで、RegionNameだけではなく、RegionManagerも指定出来ることがわかった。
ViewModelでDIした(MainWindowの)RegionManagerを、サブウィンドウのXAMLでRegionManagerに指定することで、 サブウィンドウでもMainWindowのRegionManagerを使用する事ができた。*1
<ContentControl prism:RegionManager.RegionName="SubContentRegion" prism:RegionManager.RegionManager="{Binding MainRegionManager}"/>
ViewModel
public IRegionManager MainRegionManager { get; } public DelegateCommand<string> NavigateCommand { get; private set; } public SubWindowViewModel(IRegionManager regionManager) { MainRegionManager = regionManager; NavigateCommand = new DelegateCommand<string>(Navigate); } private void Navigate(string navigatePath) { if (navigatePath != null) MainRegionManager.RequestNavigate("SubContentRegion", navigatePath); }
これでRegionNameを分けることで、サブウィンドウでもRegionを使用した画面遷移が出来るようになった。
動作環境
- .NET Core 3.1
- Prism 7.2
以上
*1:IRegionManagerインターフェースのCreateRegionManagerメソッドを呼び出すことで、新しいRegionManagerを取得する事もできる