One of the easiest ways to build a menu on Winforms is by simply dragging and dropping a MenuStrip control from the toolbox on your form and then go to town filling in menu text and attaching events. Most of the time this is the way to go and works for the majority of programs out there. What we will cover this time around is just a few examples of how you can build these menus dynamically. Why would you do that?
Well sometimes the menus have to change or be created based on program information. For instance, let’s say you want the user to be able to create a menu item, as a shortcut, for some particular operation. Maybe we even allow them to assign their own accelerator key to it. This could be a menu item that your program can’t possibly know until the user creates it. Then we could save that menu item on their system (in the form of a setting or even a piece of XML or whatever) and next time the program starts it would read that setting and recreate the menu for the user. That mechanism is outside the scope of our article here, but knowing how to build these menus dynamically can be useful for software developers.
Our first example below is a simple form menu we create from scratch. For simplicity we will simply wrap all these examples in functions so we can call them from a button click or any other type of event. No need to drag the MenuStrip control on the form at design time, this code will add it in at runtime instead. The below example will serve as the basis for further examples so keep it in mind. For clarity, and to avoid possible headaches, these examples were created with Visual Studio 2012 and .NET Framework 4.5 but should even work in 2010.
private void CreateSimpleMenu() { // Create high level menu container MenuStrip strip = new MenuStrip(); // Create a top level menu item called "File" with "F" being the access key (Alt + f) ToolStripMenuItem fileItem = new ToolStripMenuItem("&File"); // Create one sub menu item on this menu fileItem.DropDownItems.Add("First Menu Item"); // Add the high level menu item to the menu container strip.Items.Add(fileItem); // Add menu to form this.Controls.Add(strip); }
In this first example we create our MenuStrip object and attach a top level ToolStripMenuItem to it with the text “&File”. The ampersand here denotes a quick access key. By putting it in front of a letter (in this case “F”) we are saying that if the user presses Alt + F it will trigger the opening of this menu. We also create another menu item to fit under this “File” menu item using some simple text added to the DropDownItems collection. Each ToolStripMenuItem has this collection representing the sub-menu items it contains. Among its versions is one which takes a typical string and one that takes another ToolStripMenuItem.
As you can see here, building menus is very much a top down hierarchy. Create the top menu, add some high level menus, add sub menus to those high level menus and even add sub menus to the sub menus.
In our next example we demonstrate this nesting process by creating a menu which has some nested sub-items. We also take the opportunity to show you how you can go about adding an icon to a ToolStripMenuItem to give more of a visual flair to the option. Here we add a simple delete icon. This icon is then placed on the left side of the menu option.
private void CreateNestedMenu() { MenuStrip strip = new MenuStrip(); ToolStripMenuItem fileItem = new ToolStripMenuItem("&File"); // Create our first sub item with a delete icon image ToolStripMenuItem firstSubitem = new ToolStripMenuItem("First Sub Item", Image.FromFile("c:\\Delete.png")); // Create two independent sub sub items ToolStripMenuItem subSubItem = new ToolStripMenuItem("First Sub Sub Item"); ToolStripMenuItem subSubItem2 = new ToolStripMenuItem("Second Sub Sub Item"); // Add the two items to the first sub item firstSubitem.DropDownItems.Add(subSubItem); firstSubitem.DropDownItems.Add(subSubItem2); fileItem.DropDownItems.Add(firstSubitem); strip.Items.Add(fileItem); this.Controls.Add(strip); }
In the example above you can see that we create two sub-items one by one. Of course this can get a bit tiresome if you have a lot of options that are a bit repetitive or follow some kind of pattern that could probably make use of a loop to generate them. We demonstrate this with another example below.
You can build a menu based on an array or collection. We use a for loop to create four menu items dynamically. In the process we also show you how you can control the state of an item as we create them. The first item is checked, the second item is disabled, the third item has our icon again and the last item is normal.
private void CreateMenuBasedOnArray() { MenuStrip strip = new MenuStrip(); ToolStripMenuItem fileItem = new ToolStripMenuItem("&File"); // Create an array of ToolStripMenuItems ToolStripMenuItem[] col = new ToolStripMenuItem[4]; // Populate the list with menus named "Menu 1" through "Menu 4" for (int i = 0; i < 4; i++) { col[i] = new ToolStripMenuItem("Menu " + (i + 1)); // Make first item checked if (i == 0) { col[i].Checked = true; } // Disable second item if (i == 1) { col[i].Enabled = false; } // Set the image on the third item if (i == 2) { col[i].Image = Image.FromFile("c:\\Delete.png"); } } // Create menu item containing icon and a collection ToolStripMenuItem collectionMenu = new ToolStripMenuItem("Collection", Image.FromFile("c:\\collection.png"), col); fileItem.DropDownItems.Add(collectionMenu); strip.Items.Add(fileItem); this.Controls.Add(strip); }
Notice in the preceding code that the menu names are created by specifying its text plus the index counter value. This leads to the menu showing “Menu 1” through “Menu 4”. The loop that builds these menus could be reading a file of settings and customizing each menu item before adding it to the array of ToolStripMenuItems. This is the mechanism that would serve you well if you were creating items that were initially built by the user in a previous run of the program. It could be used for displaying windows open, it could be used to display similarly named lists or even a list of menu items that will share an event.
In our next example we demonstrate attaching events to a menu dynamically. Here we create a menu that when clicked will call a function called “deleteItem_Click” and show our MessageBox. While we were at it, we showed the option to use another accelerator key and have it displayed on the right side of an element. Each ToolStripMenuItem has a parameter that allows us to specify a “Key”. Using the Shortcuts enum (and casting it to a Key) we can easily add our accelerator.
private void CreateMenuWithEventAndKey() { MenuStrip strip = new MenuStrip(); ToolStripMenuItem fileItem = new ToolStripMenuItem("&File"); // Create our first item with an image and wired to a click event // Also sets Alt + 7 as the shortcut ToolStripMenuItem itemWithEventAndKey = new ToolStripMenuItem("Delete Event", Image.FromFile("c:\\Delete.png"), deleteItem_Click, (Keys)Shortcut.Alt7); fileItem.DropDownItems.Add(itemWithEventAndKey); strip.Items.Add(fileItem); this.Controls.Add(strip); } // Event that is called from menu item. private void deleteItem_Click(object sender, EventArgs e) { MessageBox.Show("Delete Event"); }
Our last example is a one off showing you how you can go about adding a menu separator in between menu items. Now since the ToolStripSeparator is a ToolStripItem but not a ToolStripMenuItem it can’t be tossed in a ToolStripMenuItem collection. It has to be added to the ToolStripMenuItem’s DropDownItems collection which will accept it. That or your array has to be of type ToolStripItem which both ToolStripMenuItems and ToolStripSeparator objects are part of. So be careful of that when trying to get a separator in a menu collection which you are trying to display.
private void CreateMenuWithSep() { MenuStrip strip = new MenuStrip(); ToolStripMenuItem fileItem = new ToolStripMenuItem("&File"); // Create one sub menu item on this menu fileItem.DropDownItems.Add("First Menu Item"); // Add a separator item fileItem.DropDownItems.Add(new ToolStripSeparator()); // Create our next item fileItem.DropDownItems.Add("Second Menu Item"); strip.Items.Add(fileItem); this.Controls.Add(strip); }
I hope you enjoyed reading through the examples and learning how to create menus dynamically. While we didn’t cover everything these menu systems can do, the basics here will go far when it comes to building both form level menus as well as context based menus. The trick here is to understand that menus are built in a hierarchy fashion. We covered how to add some icons to them, how to attach a basic click event, work with an array of items which can help you create whole lists of items on the fly and use separators.
Thanks for reading! 🙂