I'm using PRISM 4 Navigation API with Unity in WPF. I have a tree-view that initiates a RequestNavigate passing in the selected tree node's ID (GUID).
_regionManager.RequestNavigate(RegionNames.DetailRegion,
ViewNames.SiteView + "?ID=" + site.ID);
In my module, I have registered the view/view-model like so:
_container.RegisterType<SiteDetailsViewModel>();
_container.RegisterType<object, SiteDetailsView>(ViewNames.SiteView);
When I select different nodes from the tree view, the DetailsRegion displays the SiteDetailsView as expected, but when I like to navigate back to the same node, a new view/view-model is created.
I tried to break at IsNavigationTarget(NavigationContext navigationContext)
but this method appears to never be called.
Where have i gone wrong? Thanks in advance.
The problem was in such a place that I never expected... Debugging the Navigation API lead me to the
RegionNavigationContentLoader
When i stepped further down the code, I noticed a call to:
I noticed that the naming here is key to matching the view to the view-model.
In my example, the name for each part was:
When I inadvertently made the following change:
Everthing worked.
Conclusion
I tested this out by changing my view to:
and still using the same view name to register with the container and navigation:
This seems to work also. So it seems the name of the View-Model is intrinsically linked to the view name used to navigate to that view.
NOTE
This is only when you're using IoC and Unity with the PRISM 4 Navigation API. This doesn't seem to happen when using MEF.
Further Investigation
I am also aware that some guides have told us to use the
typeof(MyView).FullName
when registering the view with the Container...I personally think this is a mistake. By using the view's full name, you are creating a depending between the view and any one who wishes to navigate to that view...
The registration of the View and the ViewModel is the problem. To have only one view you have to use a different lifetime manager. Without specifying a lifetime manager the
TransientLifetimeManager
is used which always returns a new instance on resolve. To have only one single instance you have to use theContainerControlledLifetimeManager
or theHierarchicalLifetimeManager
: