quadroid
quadroid

Reputation: 8941

Pass Parameter into ViewModel constructor dependent on navigation region?

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 AutoWireViewModelAttachedProperty inside the Navigation. So everytime i navigated to a View i checked if it has set AutoWireViewModelto 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

Answers (1)

Haukinger
Haukinger

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

Related Questions