In addition to buttons, labels, and textboxes, menus are one of the most common user interface elements in interactive programs. This lesson explains how to add menus and context menus to forms. It also explains how to catch their events so your program can take action when the user selects menu items.
To create a menu, simply drop a MenuStrip
control on a form. By default, the MenuStrip
is docked to the top of the form so you don't really need to position it carefully. Just double-click the Toolbox's MenuStrip
tool and you're set.
Unlike most controls, the MenuStrip
appears in the Component Tray below the form in addition to appearing on the form itself. Figure 5.1 shows the SimpleEdit program in the Form Designer. Below the form you can see the Component Tray containing a MenuStrip
and a StatusStrip
.
When you select a MenuStrip
in the Form Designer, either on the form's surface or in the Component Tray, the menu bar at the top of the form displays a Type Here box. Click that box and type the menu's caption to create a main menu.
If you create a main menu entry and then click it to select it, the Form Designer displays a new Type Here box to let you create menu items. Figure 5.2 shows the top of the Form Designer after I created the top-level File menu.
You can continue clicking menu items to add submenus as deeply as you like. Continue entering text in the Type Here boxes to build the whole menu structure. Figure 5.3 shows the Edit menu for a new version of the SimpleEdit program. Notice that the menu contains several cascading submenus. The Offset submenu is expanded in Figure 5.3.
You can use the Type Here boxes to create submenus to any depth, although in practice three levels (as in Edit Offset Subscript) are about all the user can stomach.
In addition to menu items, you can place Separator
s, TextBox
es, and ComboBox
es in menus. TextBox
es and ComboBox
es are unusual in menus, so I won't cover them here. Separator
s, however, are quite useful for grouping related menu items.
To create a Separator
, right-click an item, open the Insert submenu, and select Separator. Alternatively, you can create a normal menu item and set its Text
to a single dash (-).
The items in a menu are ToolStripMenuItem
s, and like other controls, they have properties that determine their appearance and behavior. Table 5.1 summarizes the most useful ToolStripMenuItem
properties.
Property | Purpose |
Checked |
Determines whether the item is checked. In Figure 5.3, the Normal item is checked. (See also CheckOnClick .) |
CheckOnClick |
If you set this to True , the item automatically toggles its checked state when the user selects it. |
Enabled |
Indicates whether the item is enabled. |
Name |
The ToolStripMenuItem 's name. Normally you should give a good name to any menu item that makes the program do something at run time so your code can refer to it. |
ShortcutKeys |
Indicates the item's shortcut key combination (if any). Either type a value such as Ctrl+N or click the dropdown arrow to the right to display the shortcut editor shown in Figure 5.4. |
Text |
The text that the item displays. Place an ampersand before the character that you want to use as the item's accelerator (if any). For example, if you set an item's Text to &Open , the item appears as Open in its menu and the user can activate it by pressing Alt+O while the menu is open. |
Accelerators allow the user to navigate menus with the keyboard instead of the mouse. When the user presses Alt, the menu's items display underlines below their accelerator keys. For example, if the File menu appears as File, the user can press Alt+F to open that menu and then use other accelerators to select the menu's items.
You should give accelerators to most if not all of your program's menus, submenus, and menu items. Experienced users can often navigate a menu system faster by using accelerators than they can by using the mouse.
Shortcuts allow the user to instantly activate a menu item. For example, in many programs Ctrl+O opens a file and Ctrl+S saves the current file. (You can remember the difference between accelerators and shortcuts by realizing that “accelerator” and the Alt key both begin with the letter “a.”)
When the user clicks a menu item, its control raises a Click
event exactly as a clicked Button
does, and you can handle it in the same way. You can even create default event handlers in the same way: by double-clicking the control.
A context menu appears when you right-click a particular control. In a Windows Forms application, using a context menu is almost as easy as using a main menu. Figure 5.5 shows an application displaying a context menu.
Start by dropping a ContextMenuStrip
on the form. Like a MenuStrip
, a ContextMenuStrip
appears below the form in the Component Tray so you can just double-click the Toolbox's ContextMenuStrip
tool and not worry about positioning it.
Unlike a MenuStrip
, a ContextMenuStrip
does not appear at the top of the form. In the Form Designer, you can click a MenuStrip
either on the form or in the Component Tray to select it. To select a ContextMenuStrip
, you must click it in the Component Tray.
After you select the ContextMenuStrip
, you can edit it much as you can a MenuStrip
. The big difference is that a ContextMenuStrip
does not have top-level menus, just submenu items.
Figure 5.6 shows the Form Designer with a ContextMenuStrip
selected. By now the menu editor should look familiar.
After you create a ContextMenuStrip
, you need to associate it with the control that should display it. To do that, simply set the control's ContextMenuStrip
property to the ContextMenuStrip
. To do that, select the control's ContextMenuStrip
property in the Properties window, click the dropdown arrow on the right, and select the ContextMenuStrip
. The rest is automatic. When the user right-clicks the control, it automatically displays the ContextMenuStrip
.
To create a menu in a WPF application, add a Menu
control to the window and use your preferred method to make it attach itself to the top. For example, if the window contains a Grid
, you can make the Menu
fill the Grid
's top row. Alternatively, if the window contains a DockPanel
, you can dock the Menu
to the top.
After you create the Menu
, you can add items to it in two ways. First, you can use the Properties window's menu editor. Select the Menu
, find the Menu
's Items
property in the Properties window, and click the ellipsis to the right to open the editor shown in Figure 5.7.
Use the editor to add and modify the items in the menu. Set a menu item's Header
property to the text that you want it to display. Place an underscore in front of the character that you want the item to use as an accelerator key. For example, the menu item in Figure 5.5 has Header
set to _Edit so when you press Alt at run time, it will appear as Edit.
To make a submenu, click the ellipsis to the right of the Items
property in the menu item editor (in the bottom right in Figure 5.5).
The second way you can create a menu hierarchy is to edit the XAML code manually. That may seem intimidating, but it's actually not too hard, particularly if you make a few menu items and then copy and paste their code.
The following code shows the XAML code for a menu structure that contains File and Format menus. Notice that the Format menu has two submenus, Align and Offset:
<Menu x:Name="menu" VerticalAlignment="Top" DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_New"/>
<MenuItem Header="_Open…"/>
<MenuItem Header="_Save"/>
</MenuItem>
<MenuItem Header="_Format">
<MenuItem Header="_Align">
<MenuItem Header="_Left" IsChecked="True"/>
<MenuItem Header="_Right"/>
<MenuItem Header="_Center"/>
</MenuItem>
<MenuItem Header="_Offset">
<MenuItem Header="_Normal" IsChecked="True"/>
<MenuItem Header="Su_perscript"/>
<MenuItem Header="Su_bscript"/>
</MenuItem>
</MenuItem>
</Menu>
If you click a menu item in the XAML editor, the Window Designer opens to show that item. You can then double-click the item to give it a Click
event handler.
Like Windows Forms applications, WPF applications let you associate a context menu with a control. When the user right-clicks the control at run time, the context menu appears.
To add a context menu to a control, first select the control. Then in the Properties window, find the ContextMenu
property (in the Miscellaneous section), and click the New button to its right.
After you create a ContextMenu
, you can edit it much as you can edit a main menu. The items inside a ContextMenu
are MenuItem
s just as they are inside a Menu
. In the Properties window, you can click the ellipsis next to its Items
property to open the menu item editor. Alternatively, you can edit the ContextMenu
's XAML code.
WPF has a whole system for handling standard commands such as Open, New, and Copy. You can even define your own commands.
The idea is that you might want to allow several different methods for invoking the same command. For example, you might allow the user to click a Button
, select a MenuItem
, or check a CheckBox
to invoke the Save command. The commands provide a central location for invoking the appropriate behaviors.
You can define code to execute when a command is invoked. Then you can assign a MenuItem
(or Button
or CheckBox
or whatever) to a command so when the user clicks the control, it invokes the command. You can even assign gestures to a command. For example, you could make the Ctrl+L gesture invoke a custom LeftAlign
command.
Gestures are quite powerful, but they're also fairly complicated so I'm not going to cover them in this book. You can learn more about them in the article “Commanding Overview” at msdn.microsoft.com/en-us/library/ms752308
.
Meanwhile, you can just create Click
event handlers for menu items.
In this Try It, you create a main menu and a context menu. The main menu includes an Exit command that closes the form. Both menus contain commands that let you change the appearance of a TextBox
on the form. Figure 5.8 shows the finished program displaying its context menu.
In this lesson, you:
TextBox
.this.Close()
.TextBox
's Font
property equal to that control's Font
property. And what better control to store the font than the menu item itself?MenuStrip
tool.TextBox
to the form. Type some text into its Text
property and set its properties: Name
= contentsTextBox
, MultiLine
= True
, Dock
= Fill
, ScrollBars
= Both
.ContextMenuStrip
tool.MenuStrip
. Click the Type Here box and type &File.formatFontSmallMenuItem
.private void fileExitMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
The keyword this
means “the object currently executing this code,” which in this case means the current form, so this line of code tells the current form to close itself.
private void formatColorRedMenuItem_Click(object sender, EventArgs e)
{
contentsTextBox.ForeColor = Color.Red;
}
private void formatFontSmallMenuItem_Click(object sender, EventArgs e)
{
contentsTextBox.Font = formatFontSmallMenuItem.Font;
}
Make the context menu duplicate the main menu's Format submenu.
Do either 1 or 2:
ContextMenuStrip
in the Component Tray to open it for editing.ContextMenuItem
, as in colorRedContextMenuItem
.MenuStrip
in the Component Tray to open it for editing. Expand the Format menu. Click the Color item and then shift-click the Font item to select all of the menu's items. Press Ctrl+C to copy the menu items into the clipboard.ContextMenuStrip
in the Component Tray to open it for editing. Press Ctrl+V to paste the menu items into the context menu.ContextMenuStrip
for editing. Expand the Color submenu and click the Red item. In the events page of the Properties window, select the Click
event. Open the dropdown on the right and select formatColorRedMenuItem_Click
.ContextMenuStrip
's other items, attaching them to the correct event handlers.TextBox
.
TextBox
. In the Properties window, set its ContextMenuStrip
property to formatContextMenu
.TextBox
's colors as in contentsTextBox.Foreground = Brushes.Red
.TextBox
's font size as in contentsTextBox.FontSize = formatFontSmallMenuItem.FontSize
.www.wrox.com
) and add the following menu structure. Set the Checked
property of the bold items to True
.
Add the code behind the Exit item, but don't worry about the other items yet.
Eventually the user will be able to use the Bullet menu item to toggle whether a piece of text is bulleted. To allow C# to toggle this item for you, set the menu item's CheckOnClick
property to True
.
Add a ContextMenuStrip
that duplicates the Format menu and use it for the TextBox
's ContextMenuStrip
property.
IsChecked
property to True
.PngFiles
directory of the Lesson 4 downloads available on the book's website.) Figure 5.9 shows what the menus should look like when you're finished.
Icon
property, but this isn't too hard to do in the XAML editor. First use the Project menu's Add Existing Item command to add the image files to the project. Then use XAML code similar to the following to add icons to the appropriate menu items:
<MenuItem Header="_New" Name="fileNewMenuItem">
<MenuItem.Icon>
<Image Source="New.png" />
</MenuItem.Icon>
</MenuItem>
Save
event handler:
private void fileSaveMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("Save");
}
Add placeholders for all menu items (except separators) that do not contain items. For example, add a placeholder for the Format Align Left item but not for Format Align because it contains items.
Attach the context menu's items to the same event handlers except give the context menu's Bullet item its own event handler. (If you make these two share the same event handler, they will interfere with each other because of their toggling behavior.)
Click="alignLeftContextMenuItem_Click"
. Then you can right-click the event handler's name and select Go To Definition to create the event handler.Modify the items' placeholder code so when the user selects a choice, the code:
For example, the following code executes when the user selects the Align submenu's Left choice:
private void formatIndentLeftMenuItem_Click(object sender, EventArgs e)
{
formatIndentNoneMenuItem.Checked = false;
formatIndentHangingMenuItem.Checked = false;
formatIndentLeftMenuItem.Checked = true;
formatIndentRightMenuItem.Checked = false;
formatIndentBothMenuItem.Checked = false;
indentNoneContextMenuItem.Checked = false;
indentHangingContextMenuItem.Checked = false;
indentLeftContextMenuItem.Checked = true;
indentRightContextMenuItem.Checked = false;
indentBothContextMenuItem.Checked = false;
MessageBox.Show("Indent Left");
}
IsChecked
property instead of the Checked
property.)Checked
property equal to the other item's Checked
property.)MenuItem
control doesn't have a CheckOnClick
property, so the Bullet menu items won't check and uncheck themselves when the user clicks them.
Add code to make those menu items check and uncheck themselves by setting each control's IsChecked
property equal to the negation of its current value. The !
character takes the logical negation of a value. In other words, !true
is false
and !false
is true
. For example, the following code toggles whether the Format menu's Bullet item is checked:
formatBulletMenuItem.IsChecked = !formatBulletMenuItem.IsChecked;
IsChecked
property instead of the Checked
property.)The program's File menu should contain:
ComboBox
with three choices.ListBox
with three choices.RadioButton
s.Image
.StackPanel
holding a Label
and a TextBox
.Grid
containing a 3 × 3 arrangement of RadioButton
s.Write a program that has three menus: File, Customers, and Employees. Give them each one menu item: Exit (and give it code), New Customer, and New Employee.
Give the program's form three RadioButton
s labeled General, Manage Customers, and Manage Employees. When the user clicks a RadioButton
, enable and disable the appropriate menus. (Some applications hide inappropriate menus, but that can be confusing to users who know a menu should exist but can't find it.)
For example, when the user clicks the Manage Customers button, enable the Customers menu and disable the Employees menu. Disable both menus when the user clicks the General button. (Hint: Make sure the program starts with the correct menus enabled.)
RadioButton
s share a single event handler.IsChecked.Value
tells whether a RadioButton
is checked.)