I'm building a small, simple (for now) modular application, based on guidance from the Create composite modular UI application in WPF using MEF and PRISM article. So far I have a main Window, with two Regions, a Bootstrapper
class, and two module projects, ModuleA and ModuleC, which export only themselves. They also each place a a view (a UserControl
) in one of the regions of the main window, e.g:
[ModuleExport(typeof(ModuleC))]
public class ModuleC: IModule
{
public void Initialize()
{
IRegionManager regionManager = (IRegionManager)ServiceLocator.Current.GetInstance(typeof(IRegionManager));
regionManager.Regions["Region2"].Add(new MoneyUserControl());
}
}
My vision is to have one large UI region in the MainWindow
, which gets used by the current, high level app feature being used, and this feature being an imported module. While these modules have lots in common and are currently part of a monolithic application, I have striving for basically just a frame (MainWindow
) that supplies basic services, while each feature of of the application is imported as a module.
I want the active module to provide menu items (commands) to the main window. It would be quite easy for me to do this 'manually', with e.g. an IModuleWithMenu
interface, and have the main window query that and integrate menus, or an 'IMenuHost` interface on the main window, and have the module push it's menu commands in.
However, I can't help think there must be a better way seeing as I'm already using MEF, and have catalogues of exports and imports for loaded modules. Surely I could query the exports and filter those that are commands, and wire them up to menus or other forms of command invocation, but doesn't MEF supply something like this already made, or close, that I keep my own code down to a minimum, and thus the risk of bugs.
As an aside, extra, question: Does anyone have copies of or links to really good tutorial matter on building composite apps with MEF (in WPF mainly, but I can adap others for WPF), as it should be done. The article I worked through is but a small introduction to modules, catalogues, and MEF itself. I'd like something really, really technical and in depth. A book purchase might even be in order.
While I don't know of any tutorials for creating a MEF WPF Prism application, I am currently developing many of these apps for work, so I can offer some of the tricks I use.
The first thing I'd say is that since you're using MEF, you should use it. You don't need to use the
ServiceLocator
. Import thatIRegionManager
! Another thing that I really like about MEF over other IoC containers in Prism is that I don't usually write anIModule
implementation. Your module doesn't define exports, as that is handled with attributes. I created a customAttribute
to export aView
to aRegion
, and an infrastructureIModule
that will register these views with their regions.For adding a
Menu
to your app, I think the best way would to be to export theMenu
as a separateView
. Then you'd have aRegion
that is just aContentControl
named something likeMenuRegion
. If you have multiple views that register aMenu
, they can callIRegionManager.NavigateToView
on the menu region when the main view changes. Of course, you can use an interface (or maybe an attribute you decorate your main view with) to make this part of your infrastructure so individual views don't have to rewrite the same code.If you are going to have some global commands as well as exported menu commands, you're likely going to need to do one of 2 things:
IRegionAdapter
to manage how to add the menu items. In this case, I'd recommend exporting your top levelMenuItem
objects. You could also define individualMenuItem
s as regions. Like aFileMenuRegion
that would allow you to addMenuItem
s to theFile
menu.ICommand
with a name, andImportMany
in a specialMainMenu
ViewModel
that handles how to add the commands. This might be a bit more complicated, as you're going to need to figure out a way of creating the menu hierarchy. You probably will need some new interface that can describe the menu more fully than anICommand
can.