Composite UI and Menus

Topics: Prism v2 - WPF 4, Prism v4 - WPF 4
Aug 23, 2010 at 3:17 PM


I'm fairly new to prism and have undertaken a WPF project using it. A concept that I have not come across so far is the idea of having a standard Menu bar in the Shell but having Menu Items populated by Prism modules so that commands in said modules can be triggered from the menu. I would have thought that a module could have a "menu view" that injects into the menu bar just like you can inject a view into a ContentControl or TabControl but I can't see how to do this currently. Has anyone tried to do something similar?



Aug 24, 2010 at 1:45 PM



Just the question that was formulating in my mind as I start the planning of a rewrite to an application I wrote a few years ago using CAB.
(This previous one being generated for me by Deklarit)
Anyway, I think the main idea is to hide the implementation of the controls used to provide the menu - whether you might use MS ones, or those from DevExpress or Infragistics, etc.
So it seems to me that the module needs to request its menus via a service - then developers in the team developing modules need no references to actual UI controls. The modules need to subscribe to events to receive the users actions.

That’s what I’m looking into, so if others have more words of wisdom, I think both of us would like to hear.



Aug 24, 2010 at 1:57 PM

Now I've been reminded of the correct terms, heres a question posted here

and the authors project


Aug 24, 2010 at 7:27 PM

I would go about this by creating a menu module that encapsulates the display of MenuControl in its proper region [i.e. MenuBarRegion etc.]. The MenuModule will also expose a Service [e.g. IMenuService] that lets other modules add MenuGroups and SubGroups to the Menu Instance managed by the module. You'd need to make sure MenuModule loads before any other modules.

Other Modules can resolve an instance of IMenuService and call the proper methods to add their menu items when the modules are initializing. And it would be better if these modules can also specify the command to execute when the menu item is selected so that those events are handled locally by  the modules and not by the menu module.

Hope this helpts


Aug 24, 2010 at 10:51 PM

I actually achieved my goal with a Prism Event, it seems to work rather well too. I'll try and share it here:

I defined an Event and Parameters that would allow me to set up both a Menu Item and a ToolBar item optionally.


    public class RegisterMenuCommandEvent : CompositePresentationEvent<MenuCommandEntry>

    public class MenuCommandEntry
        public string MenuCatagory { get; set; }
        public string MenuItemName { get; set; }
        public object ToolTip { get; set; }

        public bool OnToolBar { get; set; }
        public object ToolbarContent { get; set; }

        public ICommand Command { get; set; }
        public KeyGesture KeyGesture { get; set; }


Then I hooked up my Shell to subscribe to this event. The shell contains a Menu control and a ToolBarTray control. Here is my Shell code:


    public partial class Shell : Window
        public Dictionary<string, MenuItem> MenuByCategory { get; set; }
        public Dictionary<string, ToolBar> ToolBarByCategory { get; set; }

        public Shell(IEventAggregator eventAggregator)
            this.Closing += new System.ComponentModel.CancelEventHandler(Shell_Closing);

            this.MenuByCategory = new Dictionary<string, MenuItem>();
            this.ToolBarByCategory = new Dictionary<string, ToolBar>();

            this.RegisterMenuCommandEvent = eventAggregator.GetEvent<RegisterMenuCommandEvent>();


        #region Events

        public RegisterMenuCommandEvent RegisterMenuCommandEvent { get; set; }

        private void RegisterMenuCommand(MenuCommandEntry menuCommand)
            if (menuCommand.KeyGesture != null)
                this.InputBindings.Add(new InputBinding(menuCommand.Command, menuCommand.KeyGesture));


            if (menuCommand.OnToolBar)

        private void AddToMenu(MenuCommandEntry menuCommand)
            if (!this.MenuByCategory.ContainsKey(menuCommand.MenuCatagory))
                this.MenuByCategory[menuCommand.MenuCatagory] = new MenuItem() { Header = menuCommand.MenuCatagory };

            string inputGestureText = menuCommand.KeyGesture != null ? menuCommand.KeyGesture.GetDisplayStringForCulture(CultureInfo.CurrentCulture) : null;
            this.MenuByCategory[menuCommand.MenuCatagory].Items.Add(new MenuItem() { Header = menuCommand.MenuItemName, Command = menuCommand.Command, InputGestureText = inputGestureText });

        private void AddToToolbar(MenuCommandEntry menuCommand)
            if (!this.ToolBarByCategory.ContainsKey(menuCommand.MenuCatagory))
                this.ToolBarByCategory[menuCommand.MenuCatagory] = new ToolBar();

            if (menuCommand.ToolbarContent is Image)
                Image image = menuCommand.ToolbarContent as Image;
                image.Style = this.Resources["ToolBarImageStyle"] as Style;

            this.ToolBarByCategory[menuCommand.MenuCatagory].Items.Add(new Button() { Content = menuCommand.ToolbarContent, Command = menuCommand.Command, ToolTip = menuCommand.ToolTip });



That's pretty much it! Here's an example of one of my modules registering a menu and toolbar item:


        private void RegisterCommands()
            Image newIcon = new Image();
            newIcon.Source = new BitmapImage(new Uri(@"/RBC1a.Client.Infrastructure;component/Images/new_48x48.png", UriKind.Relative));

            MenuCommandEntry newMenuCommand = new MenuCommandEntry();
            newMenuCommand.MenuCatagory = "Volunteers";
            newMenuCommand.MenuItemName = "New";
            newMenuCommand.ToolTip = "New Volunteer";
            newMenuCommand.Command = VolunteerCommands.NewCommand;
            newMenuCommand.KeyGesture = new KeyGesture(Key.N, ModifierKeys.Control);          
            newMenuCommand.ToolbarContent = newIcon;
            newMenuCommand.OnToolBar = true;

            Image deleteIcon = new Image();
            deleteIcon.Source = new BitmapImage(new Uri(@"/RBC1a.Client.Infrastructure;component/Images/delete_48x48.png", UriKind.Relative));

            MenuCommandEntry deleteMenuCommand = new MenuCommandEntry();
            deleteMenuCommand.MenuCatagory = "Volunteers";
            deleteMenuCommand.MenuItemName = "Delete";
            deleteMenuCommand.ToolTip = "Delete Volunter(s)";
            deleteMenuCommand.Command = VolunteerCommands.DeleteCommand;
            deleteMenuCommand.KeyGesture = new KeyGesture(Key.D, ModifierKeys.Control);  
            deleteMenuCommand.ToolbarContent = deleteIcon;
            deleteMenuCommand.OnToolBar = true;


Whether this is the best approach or not, who knows, but its working nicely for me!



Oct 17, 2010 at 3:17 PM

Why did you choose the event aproach instead of shared service aproach.
I see that your event has been published just one time for each metod. For this purpos wasn't better a public serivece used by all modules for publish his menu or toolbar items?