Prism/Unity Navigation question

Topics: Prism v4 - WPF 4
Jan 5, 2013 at 7:55 PM

I have a view and corresponding view model for adding or editing a customer. If I click the Add new customer button, unity wires me up a nice shiny new CustomerView and passes in my datacontext and view model. I save my customer and now want to view another, existing customer record, from my datagrid. I have a command that accepts the selectedItem (Customer) from the datagrid and I now want to pass this in to my CustomerView as a parameter, that is declared in my Constructor for the View Model. How do I tell Unity that I now want to build my View and view model with my Client parameter and then navigate to the view?

Thanks.

Developer
Jan 7, 2013 at 1:58 PM

Hi,

Have you tried using Overrides when resolving your instances, this way Unity allows you to specify constructor parameter or parameters, which could be useful to pass the selected item.

For more information about this you could check the following MSDN article:

Also, I believe you could find the following thread interesting where a related discussion is addressed:

I hope you find this helpful,

Agustin Adami
http://blogs.southworks.net/aadami

Jan 7, 2013 at 2:37 PM

Hi Aadami

I finally got to display a saved record using the ParameterOverride as you suggest, however, if I load a customer then navigate back to main and select a different customer to view, I see the ViewModel created as expected with my newly selected customer, but view still displays first selected customer, is there a way for me to instruct Prism/Unity to create me a new viewModel each time the view is navigated to?

_unityContainer.RegisterInstance(_unityContainer.Resolve<ICustomerViewViewModel>(new ParameterOverride("customer", customer)));
_regionManager
.RegisterViewWithRegion("MainRegion", typeof(CustomerView));
_regionManager
.RequestNavigate("MainRegion", "CustomerView");

Cheers for advice.

Developer
Jan 7, 2013 at 6:20 PM

Hi,

Based on my understanding the behavior you are experiencing is caused by the fact that when you navigate to a view using the RequestNavigate method of the Prism's navigation API, the navigated view will be determined based on the existing view's type Name or FullName in the specified region, and if no candidates are found a new instance of this view will be resolved from the container. In which case if you navigate to a view type that has more than one instance registered in that region only the first candidate found will be navigated to. This may be the reason why the first selected customer is displayed in your case.

For scenarios where you need to navigate to existing views or create a new one if this doesn't exist in your region, you could benefit of the IsNavigationTarget method in the INavigationAware interface. This method will be called during navigation on all views / view models (implementing this interface) in the region that are of the same type as the requested view. However, this may require passing a parameter, for example a customer id, during the navigation request in order to identify the correct view and return true or false in the IsNavigationTarget method accordingly.

For detailed information on this approaches you could check the following chapter of the Prism documentation:

In my opinion if you are using the Prism's navigation API, you could also benefit of the INavigationAware, OnNavigatedTo method to initialize newly displayed views, as for example you could use it to pass a parameter with the selected customer id, and provide the logic to set the corresponding values to the views' view models inside this method, instead of using Overrides to resolve your types.

Instead, if you want to manually create the instance of your views by using the ParameterOverride option, I believe using the view injection approach instead of navigation (as suggested in the above related thread (ParameterOverride in WPF/PRISM/MVVM)) might be a more suitable approach to handle these views.

I hope this helps,

Agustin Adami
http://blogs.southworks.net/aadami

Jan 7, 2013 at 7:31 PM

Really appreciate your assistance Aadami.

I have tried the "view Injection" approach you mention in your post and I have created my ClientView with populated ViewModel with the following code:

var clientView = _unityContainer.Resolve<IClientView>(new ParameterOverride("client", client).OnType<ClientViewViewModel>()); 
_regionManager.Regions["MainRegion"].Add(clientView);

I can see the view added to the MainRegion if I inspect the _regionManager.Regions["MainRegion"].Views collection but the view is not shown, have I missed a step?

Thanks again for help

Jan 7, 2013 at 7:44 PM

OK, added the RequestNavigate to ClientView after adding and spot on. Thanks for the help sir, dug me out of a right hole, no doubt another one round the corner but this one I'm clear of... Thank you.

Developer
Jan 7, 2013 at 8:51 PM

Hi,

Just to add a quick note, based on my understanding, activating the view after adding it to the region should make it visible for you. You can do this by adding the following line after adding the clientView to the MainRegion:

_regionManager.Regions["MainRegion"].Activate(clientView);

In my opinion, this is better than activating it through a RequestNavigate, as in some cases it may not activate the view you just added (like explained above.)

Regards,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Jan 8, 2013 at 5:45 PM

Cheers Damien, and Aadami. Top top help.