Module Loading with ModuleManager

Dec 18, 2008 at 8:58 PM
I am a little lost on loading modules on demand, and I hope you guys can enlighten me. I am using v2 #7.

Here's what I want to accomplish:
1) I have 2 regions - one for buttons that instantiate the modules (MenuRegion), another to show the modules (MainRegion). Only one module is to be visible at a time in MenuRegion.
2) Modules are to be found in a directory
3) The MenuModule module is associated with MenuRegion and is to create buttons showing the module names. When one of the buttons is clicked, the corresponding module is to be loaded and displayed in MainRegion.
4) Behavior:
    a) ModuleA button is clicked and ModuleA is displayed. User enters data in ModuleA and data is left in an unsaved state.
    b) ModuleB button is clicked and ModuleA is displayed. User enters data in ModuleB and data is left in an unsaved state.
    c) ModuleA button is click and ModuleA is displayed with the information previously entered.

Please correct me if I am wrong in my assumptions, and please give me other suggestions:
1) MainRegion should be a ContentControl, so only one module is visible at a time.
2) I think I need to enumerate the "GrouplessModules" of my Catalog to get the ModuleInfo for the modules available in the directory
3) To load the module I think I need to call myModuleManager.LoadModule(moduleName)

Finally, my questions:
1) Should I have the moduleManager as a parameter in my MenuModuleView's constructor?
2) How do I get the catalog accessible from inside MenuModuleView, in order to enumerate the available modules?
3) From MenuModuleView, as I enumerate through the modules, I create the buttons, assigning the ModuleInfo to the button's Tag property. This way, I have only one click event to load the module. Is this correct? It smells a bit work-aroundish to me...

Thanks a lot for your help!!!



Dec 19, 2008 at 12:31 AM
I think that you shoudn't use the module manager for that purpose. Remember, a module is an unit of deployment and development. Within a module, you can have several views.

A module can only be loaded & initialized once, and there is no way to unload or uninitialize a module.

What you are looking for is some form of navigation manager, which unfortunately we don't have time for to build. But the way I would build it is:
1 Create a form of button view that you can easily put in the button region. (It doesn't have to be a usercontrol, it can also just be a button)
2 Put some logic on the buttoncontrol that, when clicked will instantiate a view and add it to the region. It should also remember that it has created the view
3 In the initialize of the modules, register the buttontype (configured for the specific viewtype) with the buttonregion.

So the code would look something like this (in pseudocode)

Class MenuButtonControl<ViewType> : Button
{

    ViewType view;  
  
     void OnButtonClick()
{
    if (view == null)
        view = ServiceLocator.Current.Resolve(typeof(ViewType));

    IRegion mainRegion = RegionManager.Regions["MainRegion"]
    if (!mainRegion.Views.Contains(view))
        mainRegion.Add(view);
    mainRegion.Activate();
}
}
}

// Then in the Initialize of the module
public void Initialize()
{
    // This code will show this button everytime the "ButtonRegion" gets loaded and shown.
    RegionManager.RegisterTypeWithRegion("ButtonRegion", typeof(MenuButtonControl<MyOwnViewThatIsAssociatedWithThisButton>));
}

In the next couple of weeks, we might look at some ways to make this scenario a bit easier. Or at least put out some blog posts on how to do this scenario.

Hope this helps.
_Erwin
Dec 19, 2008 at 7:03 AM
Thanks Erwin, I am looking forward to what you guys can come up to make this scenario easier.
One question: Doesn't XAML have a problem with generic classes?
Dec 20, 2008 at 7:19 AM
Edited Dec 20, 2008 at 7:21 AM
I would also suggest looking at implementing a controller for this sort of scenario.  DON'T put any knowledge about the module manager/catalog or other views in a view -- i.e. your MenuModuleView (that is a view, right, and not a module?). 

You should have at least a presenter or model for each view, in your scenario, that know only about their views, the container and possibly other "global" services.  In order to communicate between views -- as you suggest -- you would typically use a controller to handle the coordination.  If you look, you'll see examples of controllers within the RI as well as within, I think, at least a couple of the Quickstarts.  Actually, you might want to take a close look at the TopDownUIComposition quickstart --see the EmployeesController.  In that example, the controller receives an employee selection event from one view and then loads another view into a different region (different from the source of the event) -- creating the view if necessary.

Granted, the specifics of your case are different but it sounds conceptually similar.  Note, you can still use dynamic loading in your situation but just recognize, as Erwin states above, that you don't load and unload modules.  You can delay loading it but you typically wouldn't unload it then.  Whether your view, model or presenter preserves its data within activations is entirely up to how you manage the view.  Are you recreating it or storing and just reloading it into your region?  The choice is yours...
Dec 20, 2008 at 6:42 PM
Edited Dec 20, 2008 at 6:44 PM

I raised this (region and controls visibility) previously in similar context, see the thread http://www.codeplex.com/CompositeWPF/Thread/View.aspx?ThreadId=41066

I had some private email exchanges with Erwin van der Valk’s about this, and currently there is no way to manage this as out of the box in PrismV2. There may be something coming up later phase of PrismV2 but is not certain.

I am using controller to manage this currently, and you can find a concept in SL2WithPrism sample. The Authentication module has this behavior implemented by controller. You can find SL2WithPrism sample refresh with PrismV2 code drop 7 from tread link http://www.codeplex.com/CompositeWPF/Thread/View.aspx?ThreadId=42393

Regards,
Alexander