Creating Dynamic Menus in Your .NET Applications
This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.
Summary: Frank Rice demonstrates how to use the MainMenu control to create customized menus based on menu selections, both at design time and programmatically, which results in a more professional and versatile presentation of your application. (10 printed pages)
Frank C. Rice, Microsoft Corporation
Applies to: Microsoft Visual Studio .NET, Microsoft Office Excel 2003
Applications created with Microsoft .NET can present different menus for different contexts (or different application states). Menu structures are created on Microsoft .NET forms by using the MainMenu control. The MainMenu control represents the container for the menu structure of a form. A menu is composed of MenuItem objects that represent the individual menu commands in the menu structure. Each MenuItem object can be a command for your application or a parent menu for other submenu items. To bind the MainMenu control to the form that will display it, you assign the MainMenu to the Menu property of the form.
It is possible to have many MainMenu objects, each of which presents different menu choices to the user. By having a number of MainMenu objects to present the correct menu structure to the user, you can handle the varying states of your application as users interact with it.
In the procedure that follows, you will create a menu structure for use when the application first opens and there is no file or data for the user to interact with. Thus, the application will have only a traditional File menu with New, Open, and Exit commands. When the user selects the New menu item, a blank Microsoft Office Excel 2003 workbook is opened. When the user selects the Open menu item, a blank Excel workbook is opened and populated with some rudimentary data. Both the New and Open menu items trigger a change in application state that displays a second menu structure with additional menu items (Close Workbook and Print Preview) that target the Excel worksheet.
In the following steps, you will design a Microsoft Windows application, in the Windows Forms Designer, that switches menu structures:
Start Microsoft Visual Studio .NET and create a new Visual Basic Windows Application.
Add a reference to the Microsoft Excel Object Library. To do this, follow these steps:
On the Project menu, click Add Reference.
Click the COM tab, locate the Microsoft Excel Object Library and click Select.
Click OK in the Add References dialog box to accept your selections.
Drag a MainMenu component from the Toolbox to the form, as shown in Figure 1.
In the Menu Designer, create a top-level menu item with the Text property set to &File (you can set this by typing in the Type Here box), and three submenu items with the Text properties set to &New, &Open, and E&xit, in that order.
Click on each one of the menu items, in turn, and assign the Name property as shown in the following table:
In the Windows Forms Designer, click the form (Form1.vb) to give it focus. In the Properties window, ensure that the Menu property is set to the menu you have just created (MainMenu1).
In .NET, it is possible to have the same event handler accommodate more than one event where multiple events point to the same function. This type of handler is called a multicast event handler.
Create a multicast event handler for the two Exit menu items (one existing Exit menu item and one Exit menu item you will create shortly) by adding the following:
You can create the shell for this procedure by double-clicking the Exit menu item and then adding Exit2.Click after the Handles Excel1.Click directive.
Private Sub Exit_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Exit.Click, _ Exit1.Click ' Shut down Excel. oXL.Quit() oXL = Nothing End Sub
In this subroutine, the two Click events following the Handles keyword mean that when either of the Exit menu items is clicked, the statement that closes Form1 is executed.
Next, in the Code Editor, create a method, similar to the following, to set the form's menu to the second MainMenu component you will create in the next set of steps:
Private Sub LoadSecondMenu() Me.Menu = MainMenu2 End Sub
In Solution Explorer, right-click the form name and choose View Designer on the shortcut menu.
In the component tray, click the icon for the MainMenu1 component so that it has focus in the form as shown in Figure 2 below.
In the Menu Designer, click the top-level menu item you created (File). Right-click and choose Copy.
This makes a copy of the top-level menu item and all of its submenu items.
Drag another MainMenu component from the Toolbox onto the form.
In the Menu Designer, right-click the Type Here area and choose Paste.
The menu items you previously selected from the first MainMenu component are pasted into the second MainMenu.
In the Menu Designer, right-click the area to the left of the Exit menu item and choose Insert New. Do this again so that you have inserted two new menu items.
Set the Text property of these two new menu items to &Print Preview and &Close Workbook, in that order, either in the Properties window or by clicking the item and typing in the space provided.
Click on each one of the menu items, in turn, and assign the Name property as shown in the following table:
The following subroutine opens an instance of Excel by using a process called automation. Automation allows applications that are written in languages such as Visual Basic or C (pronounced C Sharp) to programmatically control other applications. As shown here, automation allows you to perform actions such as creating a new workbook and adding data to the workbook. Once the worksheet is populated, the function to load the alternate menu is called. Add the following to the Code Window:
Public oXL As Excel.Application Private Sub Open_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Open.Click, Open1.Click Dim oWB As Excel.Workbook Dim oSheet As Excel.Worksheet oXL = CreateObject("Excel.Application") oXL.Visible = True ' Get a new workbook. oWB = oXL.Workbooks.Add oSheet = oWB.ActiveSheet ' Add table headers to each column. oSheet.Cells(1, 1).Value = "First Name" oSheet.Cells(1, 2).Value = "Last Name" ' Populate with sample names. oSheet.Cells(2, 1).Value = "Nancy" oSheet.Cells(2, 2).Value = "Davolio" oSheet.Cells(3, 1).Value = "Janet" oSheet.Cells(3, 2).Value = "Leverling" ' Load the alternate menu. LoadSecondMenu() End Sub
The next subroutine is executed when the user clicks the New menu item and opens up a blank workbook before loading the alternative menu. Add this subroutine to the Code Window:
Private Sub New_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles New.Click, New1.Click Dim oWB As Excel.Workbook Dim oSheet As Excel.Worksheet oXL = CreateObject("Excel.Application") oXL.Visible = True ' Get a new blank workbook. oWB = oXL.Workbooks.Add oSheet = oWB.ActiveSheet ' Load the alternate menu. LoadSecondMenu() End Sub
The next subroutine is executed when the user clicks the Print Preview menu item. Add this procedure to the Code Window:
Private Sub Print_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Print.Click ' Print Preview menu item. oXL.ActiveSheet.PrintPreview() End Sub
And finally, this procedure shuts down the instance of Excel when the user clicks the Close Worksheet menu item. Again, add this procedure to the Code Window:
Private Sub Close_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Close.Click ' Exit menu items. Form1.ActiveForm.Close() End Sub
Press F5 to run the application. The form has a menu that contains File, New, Open, and Exit menu items. Clicking New or Open triggers an event, which is handled by the appropriate event handlers. These methods either load a new blank workbook or load a workbook and populate it with data. The methods also change the application state by calling the LoadSecondMenu subroutine. The application state change is indicated by the addition of two menu items, Print Preview and Close Workbook.
In addition to creating the menus using the Windows Forms Designer, you can also programmatically design a Windows application by using the MainMenu object. The following subroutine uses a MainMenu object that is opened when the application is first opened; it has only the traditional File menu with New, Open, and Exit commands. Additionally, the code below uses an overloaded Add method that creates menu items and associates event handlers with them.
In order to reference members of the Excel object model, you will need to set a reference to the Microsoft Excel Object Library as explained in the section Creating a Menu at Design Time.
' Create a MainMenu object and a MenuItem object. Private mmAppStart as MainMenu Private miFile as MenuItem Public Sub AppStartMenu() ' Create an instance of the MainMenu object. mmAppStart = new MainMenu ' Create a top-level menu item and two menu items. Use this ' overloaded constructor that takes an event handler ' (MenuSelect) so that later, you can cause the menu ' selection to change the application state. miFile = New MenuItem("&File", _ New System.EventHandler (AddressOf Me.MenuSelect)) miFile.MenuItems.Add("&New", _ New System.EventHandler (AddressOf Me.MenuSelect)) miFile.MenuItems.Add("&Open", _ New System.EventHandler (AddressOf Me.MenuSelect)) miFile.MenuItems.Add("&Exit") ' Add the top-level menu item to the MainMenu component ' and set the MainMenu component to be the form's menu. mmAppStart.MenuItems.Add(miFile) ' Set the form's menu to the menu you have just created. Me.Menu = mmAppStart End Sub
This procedure creates a second instance of a MainMenu component with menu items that correspond to a second application state. In this case, after the user has opened a file, you can expose commands to preview the worksheet and close the workbook.
' Create the alternate MainMain object. Private mmFileLoadedMenu As MainMenu Public Sub FileLoadedMenu() mmFileLoadedMenu = New MainMenu() ' Clone the first menu with the CloneMenu method. mmFileLoadedMenu.MenuItems.Add(miFile.CloneMenu()) ' Create two additional menu items related to the ' application state. Dim mnuitemPrintPre As New MenuItem("&Print_Preview", _ New System.EventHandler(AddressOf Me.MenuSelect)) Dim mnuitemClose As New MenuItem("&Close_Workbook", _ New System.EventHandler(AddressOf Me.MenuSelect)) ' Add the two new menu items to the MenuItems collection of the ' top-level menu item cloned above, using the Add method to ' specify their order within the collection by their index. mmFileLoadedMenu.MenuItems(0).MenuItems.Add((2), mnuitemPrintPre) mmFileLoadedMenu.MenuItems(0).MenuItems.Add((3), mnuitemClose) ' Assign the newly-created MainMenu object to the form. Me.Menu = mmFileLoadedMenu End Sub
Add a line of code to the Form1 constructor, after the InitializeComponent method call, to call the AppStartMenu method created previously:
Next, create an event handler within the class to add functionality to each of the menu items and to switch the form's Menu property to the FileLoadedMenu. The subroutine adds functionality by using Select Case..End Select statement based on the value of the menu item clicked:
Protected Sub MenuSelect(ByVal sender As Object, _ ByVal e As System.EventArgs) Dim itemClicked As New MenuItem() itemClicked = CType(sender, MenuItem) ' Console.WriteLine("You have selected the item " & _ itemClicked.Text) Select Case itemClicked.Text Case "&New" Dim oWB As Excel.Workbook Dim oSheet As Excel.Worksheet oXL = CreateObject("Excel.Application") oXL.Visible = True ' Get a new blank workbook. oWB = oXL.Workbooks.Add oSheet = oWB.ActiveSheet Case "&Open" Dim oWB As Excel.Workbook Dim oSheet As Excel.Worksheet oXL = CreateObject("Excel.Application") oXL.Visible = True ' Get a new workbook. oWB = oXL.Workbooks.Add oSheet = oWB.ActiveSheet ' Add table headers to each column. oSheet.Cells(1, 1).Value = "First Name" oSheet.Cells(1, 2).Value = "Last Name" ' Populate with sample names. oSheet.Cells(2, 1).Value = "Nancy" oSheet.Cells(2, 2).Value = "Davolio" oSheet.Cells(3, 1).Value = "Janet" oSheet.Cells(3, 2).Value = "Leverling" Case "E&xit" ' Shut down Excel. oXL.Quit() oXL = Nothing Case "&Print_Preview" oXL.ActiveSheet.PrintPreview() Case "&Close_Workbook" Form1.ActiveForm.Close() End Select FileLoadedMenu() End Sub
In this column, we looked at two different ways to add menus to your .NET applications. One of the methods involved creating the menus at design time. The other method created the menus at runtime by creating the menu programmatically. One or both of these methods may be suitable depending on your applications. By using the techniques described in this article, you can add more versatility to your .NET applications.
About the Author
Frank Rice is a programmer writer for the Microsoft Office Developer Center, where he adds his teaspoon of content to the flood of developer documents. In previous incarnations, he was an Access application developer and Access support engineer.