Reputation: 8941
I have a WPF Application that i try to move to Prism step by step. The current step is RegionManager and NavigationService / Composite UI.
I did implement a own RegionManager and NavigationService to deal with the details, now i try to replace the own implementation with the Prism RegionManager (because it contains some functionality that would be nice) here is the problem i try to solve:
I have a TabControl which is able to display multiple contents that do not have anything to do with each other (like a browser). The TabControl has a Template set which creates a new Region for each Content to display (so i have a NavigationService and a Journey for each TabItem)
<userInterface:TabControlHelper.Template>
<DataTemplate DataType="{x:Type viewModels:ContentViewModel}">
<ContentControl x:Name="DataContextProxy">
<ContentControl prism:RegionManager.RegionName="{Binding ElementName=DataContextProxy, Path=DataContext.(viewModels:ContentViewModel.Id)}"
prism:RegionManager.RegionManager="{Binding RelativeSource={RelativeSource AncestorType=views:ContentOverview}, Path=DataContext.RegionManager}"
Background="{StaticResource BackgroundBrush}"
DataContext="{x:Null}" />
</ContentControl>
</DataTemplate>
</userInterface:TabControlHelper.Template>
now when the TabControl.SelectedItem
is changed to a new Content I navigate to the HomeView Using the following code:
regionManager.Regions[this.SelectedContent.Id].RequestNavigate("HomeView");
The navigation works fine, just the ViewModel creation does not:
In my own implementation i handled the AutoWireViewModel
AttachedProperty inside the Navigation. So everytime i navigated to a View i checked if it has set AutoWireViewModel
to true, and if I created a ViewModel where I was able to Inject the correct Content using the Name of the Region (which is the Content.Id)
Here is where i am Stuck. The HomeViewModel
needs to have access to the current Content it should display. I know it is possible to inject the Content via the NavigationContext
, but the HomeViewModel
should actually not care where the IContent
instance comes from, it just depends on it (it is not optional so i would prefer passing it in via constructor). And the HomeView
is just one of a lot Views that need to know the current Content, which means if I push the Content into the ViewModel via NavigationParameters
I do either need the code that takes the Content every time, or I do need some ugly base class that takes care of taking the NavigationParameter
and validating it contains an instance of IContent (which for me seems like "action at a distance").
How can I alter Prism Navigation and AutoWireViewModel to automatically resolve the correct instance of IContent? It should use something like this:
IContent targetContent = Container.Resolve<IContentManager>.Contents[this.RegionThatDidInvokeTheNavigation.Name]
Or is there a better approach to achieve the desired behaviour?
Upvotes: 1
Views: 1451
Reputation: 10863
I've had a similar problem, and I would have liked if prism slightly modified its RegionNavigationService to give us an option to influence viewmodel creation (see https://github.com/PrismLibrary/Prism/issues/367).
If you don't like to implement INavigationAware
on your viewmodel (which implies that you're left in an uninitalized state until the navigation actually happens), you could modify RegionNavigationService.ExecuteNavigation
like this:
[...update journal...]
// Create and set the view model based on the navigation context
var viewAsDependencyObject = view as DependencyObject;
if (viewAsDependencyObject != null)
{
var createViewModelOnNavigateTo = ViewModelLocator.GetCreateViewModelOnNavigateTo( viewAsDependencyObject );
if (createViewModelOnNavigateTo)
ViewModelLocator.Bind( view, _viewModelProvider.CreateViewModel( viewAsDependencyObject, navigationContext ) );
}
[...inform view...]
_viewModelProvider
is a service that creates viewmodels from the NavigationContext
, CreateViewModelOnNavigate
is an attached property similar to AutoWireViewModel
.
Upvotes: 2