View navigation and composition questions

Topics: Prism v4 - WPF 4
Jul 1, 2011 at 10:38 PM

So apparently I'm really misunderstanding something regarding view navigation and, perhaps, composition as related to Prism applications. Let's say that I have defined a simple Shell. That Shell has two Regions; one for a Ribbon control (with, of course, a RegionAdapter) and another for what we'll call the "client area". Let's also assume that I have two Modules. Module A and Module B each have two jobs. Module A provides users CRUD for AFoo entities and Module B provides users CRUD for BBar entities.

Okay, so for each entity (AFoo, BBar, etc), our respective Module provides a View and corresponding ViewModel for CRUD and for each of those we have a RibbonTab and some sort of user control to display in the client area. In other words, Module A has an AFooCreateClientAreaView, AFooCreateRibbonTabView, AFooReadClientAreaView, AFooReadRibbonTabView, AFooUpdateClientAreaView, AFooUpdateRibbonTabView, AFooDeleteClientAreaView, AFooDeleteRibbonTabView and each of these has their own respective ViewModel.

Whew... even I had to re-read that mess. Basically, there's a Shell that displays a Ribbon and a big ol' empty client area. Each Module will display a combination of ClientArea and RibbonTab view.

So, let's assume that each module initializes and registers each view with the container as so:

 

// Get the Unity container...
var container = ServiceLocator.Current.GetInstance<IUnityContainer>();

// Register the view types with the container...
container.RegisterType(typeof(Object), AFooCreateClientAreaView, "AFooCreateClientAreaView");

container.RegisterType(typeof(Object), AFooCreateRibbonTabView, "AFooCreateRibbonTabView");

container.RegisterType(typeof(Object), AFooReadClientAreaView, "AFooReadClientAreaView");

container.RegisterType(typeof(Object), AFooReadRibbonTabView, "AFooReadRibbonTabView");

// etc...

 

Oh, it should be noted that the intent is that only one combination of Views is shown at one time. In fact, each View implements IRegionMemberLifetime and sets KeepAlive() to false. Now, when the user navigates, we're doing something like this...

 

// Uri built somewhere up here...

// Ask the region manager to navigate the view...
this.regionManager.RequestNavigate("AFooCreateClientAreaView", uri);
this.regionManager.RequestNavigate("AFooCreateRibbonTabView", uri);

 

Hmmm... this is starting to feel weird. The client area View and the RibbonTab view should always be presented together. They don't have context independent of one another.

Now let's say we want to implement something as simple as a dialog asking the user for confirmation if they attempt to navigate away from a View where the Model has changed. No problem, we'll just implement IConfirmNavigationRequest.

Wait, there's definitely something wrong. If I implement IConfirmNavigationRequest on the View in the client area, what happens if we've already mistakenly navigated away from the RibbonTab view? Suddenly the app is in an invalid state because we're showing the wrong RibbonTab for the ClientArea. This wouldn't have happened if there was some way to treat them as a unit, but how?

Should one ViewModel be responsible for a RequestNavigate call to the other? Feels weird and outside the ViewModel's responsibility.

Should one ViewModel subscribe to it's partner's event? That obviously won't work since they're not instantiated until the RequestNavigate call.

Should there be some sort of supervising controller or presenter? Maybe something more like Screen Conductor?

I'm at a loss and while I've looked at countless examples, I'm having trouble piecing it together and it really feels like I'm fighting Prism to get something done which tells me I'm probably not taking the right approach. Can anyone lay it down for me?

Developer
Jul 4, 2011 at 7:32 PM

Hi,

There are several possiblilities you could follow to fulfill your requirement on the scenario you've described. I'll point out some of them I have thought about, based on my understanding of your scenario:

  • You could have a separate service, whose responsiblility will be of coordinating the navigation state of your different views. Therefore, when confirming the navigation request, you should ask that service whether you should or shouldn't navigate away.
  • Another possiblity would be to extend the Prism navigation mechanisms to support this scenario. You might find the RegionNavigationService class and IConfirmNavigationRequest interface useful for this. You should take into account that the benefits of following this approach might not necessarily compensate for the additional effort involved.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi

Jul 5, 2011 at 3:51 PM

Thanks, Guido. I currently have a service that performs navigation and a (currently) somewhat clumsy method to deal with confirmation. It seems reasonable to continue down that path and refine my implementation, but before I invested more time I wanted some confirmation that I wasn't wasting my time. Thanks for the feedback!