Inspired by this answer, I created a general purpose Shell (Prism, WPF) like this:
<Window x:Class="VRMDataLogger.UI.Shell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" Title="My App" Height="450" Width="800">
<Grid>
<ContentControl prism:RegionManager.RegionManager="{Binding RegionManager}" prism:RegionManager.RegionName="MainShellRegion" />
</Grid>
</Window>
public partial class Shell : Window
{
public Shell(IRegionManager regionManager, Type contentType)
{
RegionManager = regionManager;
InitializeComponent();
RegionManager.RegisterViewWithRegion("MainShellRegion", contentType);
}
public IRegionManager RegionManager { get; }
}
The initial shell gets created in App.CreateShell()
:
protected override Window CreateShell()
{
return new Shell(Container.Resolve<IRegionManager>(), typeof(StartScreen));
}
This works fine and the correct view is shown in that initial shell.
I then try to create a second Shell from StartScreenViewModel
which shows a different view:
var shell = new Shell(RegionManager.CreateRegionManager(), typeof(MainScreen));
shell.Show();
This opens a new window, but it shows the same view like the first window (StartScreen
) instead of MainScreen
. What am I doing wrong here?
So I was thinking about getting rid of the region stuff too. But I think what I'll lose by doing so is the nice feature of dependency injection into my view models
Not at all. In fact, you get more control over how your view models are created.
When going view-first, your view model is typically created by the ViewModelLocator
upon navigation and then passed NavigationParameters
, if any.
If you create your view model manually and bind the view via data templating, you have full control over the creation of the view model. The simplest option is to inject a factory for the view models (like Func<MainScreenViewModel>
) and you get full dependency injection from the container.
internal class StartScreenViewModel
{
public StartScreenViewModel( Func<MainScreenViewModel> mainScreenViewModelFactory )
{
GoToMainScreenCommand = new DelegateCommand( () => new Shell( mainScreenViewModelFactory() ).Show() );
}
public DelegateCommand GoToMainScreenCommand { get; }
}
Of course, you can use a more sophisticated, hand-crafted factory if need be (see this answer).