views:

238

answers:

1

I'm using Prism for navigation in my Wpf application. I have a few modules, and each of them is registering themselves in a main menu through common commands sent using the IoC container in the bootstrapper. The menu entries are bound to common commands for navigation - which will open the correct view in some Region. All is based on recommendations I've found through the Prism site.

My problem now is that I have a module where there is a condition stating if i want to open ViewA or ViewB in the main region. Example: Let's say I have a customer module - and then a "Customer" menu item which will open the customer module in the main view. And there is a condition: If I have an active customer I want to open the CustomerDetailsView when clicking the menu item, else I want to open the CustomersAdminView.

What is the recommended approach to solving this? I see a few options, but I think all of them sound a bit hacky. Now I'm working on creating what would be a MasterCustomerView in the example above. This view will then check the condition and open the UserControl giving either Details of Admin inside. I'm not all satisfied with this solution though - Would it be a legitim approach? Any better?

+1  A: 

In the menu systems I've built around Prism, I've provided an overload for modules registering views that allows them to pass a delegate, rather than the Type of the view. In this delegate I can pass relevant information to the delegate so that it can decide how to create its view.

This is a bit complicated, but I can give you a few relevant bits of examples.

public interface IMenuRegistry
{
     void RegisterMenuItem(string title, 
                           Func<RelevantInformation, Object> executeFunction, 
                           Func<RelevantInformation, bool> canExecuteFunction);

     void RegisterMenuItem(string title, Type viewType);
}

Notice here I have a type that is passed in "RelevantInformation" that can contain the current customer, etc. When the user clicks on the menu item, I call the delegate and pass in all of the information it might need to make its decision. It returns a View object I can then put into whatever region is appropriate.

I also allow the module to pass a "canExecute" delegate, similar to how a Command works (in fact, I take all of the menu registrations and turn them into Commands). This way the module can also choose to disable itself if some condition in RelevantInformation would make the menu item invalid.

In reality this is only one of many ways to solve this problem, but this is close to what I do. Hopefully you find it helpful or it gets you thinking about alternate ways to solve the problem.

Anderson Imes
Thanks for your reply. I started implementing a similar approach, but it was clear early on that this would get a bit complex. So if there is a better solution I'd like to do this instead. Looking into solving it with event aggregation instead. Looks promissing.
stiank81
I've seen an event aggregator solution before and that will certainly work (this is the way I went at first), but it gets pretty messy and you lose seperation of concerns... you are making modules responsible for the operation of the menuing system. It *feels* right at first, but quickly becomes unmanageable, especially if you have other developers making modules.
Anderson Imes
To me it seems reasonable that the module itself gets to decide what to do when it is requested. Doing so the menuitems are only a caption and the event they are to trigger when clicked. At least for now I find this being more reasonable than building logic into the menu items.
stiank81
I appreciate your answer. However, I've changed to use event aggregation, and I think the new architecture looks good. If we see problems with this in the future I'll probably go with your strategy or something similar.
stiank81
It's fine and it's very close to what I proposed, only there's another step in subscribing to and filtering out event aggregation events that you have to do to get everything to work. In the case I have above you don't need this extra part and don't have to trust Module authors to know about this part. It's just simpler. The event aggregation approach will of course work.
Anderson Imes