Form MenusAs interesting as forms themselves are ”with their lifetime, adornments, transparency settings, and input options ”they're all the more interesting with controls on them. But before we get into managing a form's controls in general, we need to take a quick look at menus, which have special support in WinForms. Not only does VS.NET have a special Menu Designer (as shown in Figure 2.7), but also, unlike every other control, a Form can show only one main menu at a time, as stored in the Form.Menu property (which is of type MainMenu). Figure 2.7. The VS.NET Menu Designer
Although you are limited to a single main menu showing on a form at a time, you can switch menus at run time to your heart's content by setting the Form.Menu property: Sub showMenu1Button_Click(sender As System.Object, e As EventArgs) _ Handles showMenu1Button.Click Me.Menu = Me.mainMenu1 End Sub Sub showMenu2Button_Click(sender As System.Object, e As EventArgs) _ Handles showMenu2Button.Click Me.Menu = Me.mainMenu2 End Sub Sub showNoMenuButton_Click(sender As System.Object, e As EventArgs) _ Handles showNoMenuButton.Click Me.Menu = Nothing End Sub In fact, if you drag multiple MainMenu components from the Toolbox onto the form, you can select each one and edit it separately, but you'll need to set the form's Menu property to pick which one to start with. No matter which menu you choose to designate as the form's main menu (or even none at all), menus themselves are only containers for items modeled via the MenuItem class. In fact, menus and menu items are both containers. The MainMenu class has a MenuItems collection that contains zero or more MenuItem objects. This makes up the list of items across the top of the menu, such as File, Edit, and Help. Each of these MenuItem objects in turn has its own MenuItems collection, which contains the next level of items ”for example, File Save, File Recent Files, File Exit. Anything below that level shows up as a cascading menu of items, such as File Recent Files foo.txt. The Menu Designer takes the menu structure you lay out and generates the code to populate the menu items in InitializeComponent. For example, using the Designer to create the File Exit and Help About menu items as shown in Figure 2.7 results in code that looks like this (and really makes you appreciate the Designer): Friend WithEvents mainMenu1 As System.Windows.Forms.MainMenu Friend WithEvents mainMenu2 As System.Windows.Forms.MainMenu Friend WithEvents fileMenuItem As System.Windows.Forms.MenuItem Friend WithEvents helpMenuItem As System.Windows.Forms.MenuItem Friend WithEvents fileExitMenuItem As System.Windows.Forms.MenuItem Friend WithEvents helpAboutMenuItem As System.Windows.Forms.MenuItem Sub InitializeComponent() Me.mainMenu1 = New System.Windows.Forms.MainMenu() Me.mainMenu2 = New System.Windows.Forms.MainMenu() Me.fileMenuItem = New System.Windows.Forms.MenuItem() Me.fileExitMenuItem = New System.Windows.Forms.MenuItem() Me.helpMenuItem = New System.Windows.Forms.MenuItem() Me.helpAboutMenuItem = New System.Windows.Forms.MenuItem() ... ' mainMenu1 Me.mainMenu1.MenuItems.AddRange( _ New System.Windows.Forms.MenuItem() { _ Me.fileMenuItem, _ Me.helpMenuItem}) ' fileMenuItem Me.fileMenuItem.Index = 0 Me.fileMenuItem.MenuItems.AddRange( _ New System.Windows.Forms.MenuItem() { _ Me.fileExitMenuItem}) Me.fileMenuItem.Text = "File" ' fileExitMenuItem Me.fileExitMenuItem.Index = 0 Me.fileExitMenuItem.Text = "Exit" ' helpMenuItem Me.helpMenuItem.Index = 1 Me.helpMenuItem.MenuItems.AddRange( _ New System.Windows.Forms.MenuItem() { _ Me.helpAboutMenuItem}) Me.helpMenuItem.Text = "Help" ' helpAboutMenuItem Me.helpAboutMenuItem.Index = 0 Me.helpAboutMenuItem.Text = "About" ' Form1 ... Me.Menu = Me.mainMenu1 ... End Sub The MenuItem class has the following design-time properties and events: Public Class MenuItem Inherits Menu Implements IComponent, IDisposable ' Properties Public Property Checked() As Boolean Public Property DefaultItem() As Boolean Public Property Enabled() As Boolean Public Property Index() As Integer Public Property MdiList() As Boolean Public Property MergeOrder() As Integer Public Property MergeType() As MenuMerge Public Property RadioCheck() As Boolean Public Property Shortcut() As Shortcut Public Property ShowShortcut() As Boolean Public Property Text() As String Public Property Visible() As Boolean ' Events Public Event Click As EventHandler Public Event Disposed As EventHandler Public Event DrawItem As DrawItemEventHandler Public Event MeasureItem As MeasureItemEventHandler Public Event Popup As EventHandler Public Event Select as EventHandler End Class The major things you'll want to focus on are the Checked and RadioCheck properties (which mark an item as chosen), the Enabled and Visible properties (which determine whether the item can be chosen or whether it will be shown), the Shortcut property (which allows you to assign a keyboard shortcut to a menu item, such as Ctrl+S for Save), and the Text property, which is what's shown to the user . A Text property that includes an "&" (ampersand) will underline the next character; for example, "&Save" will show as " S ave", thereby providing a visual cue for keyboard menu navigation via the Alt key. Typing "-" (hyphen) as the Text in the Menu Designer will create a separator between groups of related menu items. The menu merging and MdiList properties are MDI- related , and we discuss them later in this chapter. Of course, the Click event handler is the big celebrity in the menu item list of events because it gets fired when the user clicks on a menu item: Sub fileExitMenuItem_Click(sender As Object, e As EventArgs) _ Handles fileExitMenuItem.Click Me.Close() End Sub Sub helpAboutMenuItem_Click(sender As Object, e As EventArgs) _ Handles helpAboutMenuItem.Click MessageBox.Show("Ain't menus cool?", "About...") End Sub Context MenusJust as a form can show at most one main menu, a form (or a control) can show at most one context menu, as managed via the ContextMenu property. Unlike the MainMenu property, which is of type MainMenu, the ContextMenu property is of type ContextMenu, and you'll need to make sure to drag the correct class from the Toolbox. A ContextMenu is also a collection of menu items, but unlike MainMenu objects, ContextMenu objects have no concept of items "across the top." Context menus are always vertical at every level, and this is reflected in the Context Menu Designer, as shown in Figure 2.8. Figure 2.8. Context Menu Designer
In the case of context menus, the Designer always shows "Context Menu" at the top level, and items can only fall under that. However, everything else is the same: Each ContextMenu object has a MenuItems collection filled with MenuItem objects, all with the same properties and events. The one remaining difference between MainMenu objects and ContextMenu objects is that controls also have a ContextMenu property, whereas only a form has a MainMenu property. Although many controls have their own context menus ”for example, a TextBox has things such as Copy and Paste in its context menu ”you can replace a control's built-in context menu by setting the ContextMenu property of the control. As a rule, most of the operations available from any control's context menu are also available as methods on the control. This means that you can replace the context menu on a control but still provide the operations that the control's menu would provide, implementing those options by sending the command to the control itself: Sub copyMenuItem_Click(sender As Object, e As EventArgs) _ Handles copyMenuItem.Click textBox1.Copy() End Sub |