There are several events that you can handle from a MenuItem. The most important is the one that you defined the item for in the first place. Remember from our button click example earlier that the events are hooked to the Click event source by a delegate defined by the system. In Listing 3.1.7, a handler that pops up a message box is defined and added to the methods of the SizeApp class.
public class SizeApp : System.WinForms.Form { public void OnFileOpen(Object sender, EventArgs e) { MessageBox.Show("You selected File-Open!"); } |
The event handler has the standard method signature for events void function(Object, EventArgs) and can be added to the File, Open MenuItem's Click event source like this:
open.Click += new EventHandler(OnFileOpen);
This line is added to the menu setup code after the shortcut initialization.
Whenever the menu item is selected with the mouse, the Alt+F+O key sequence, or the Ctrl+O shortcut, the menu handler will fire and the message box will pop up.
The complete C# file for the modified resize.cs program is available as resize2.cs on this book's Web site. You can find this at http://www.samspublishing.com/. Type in the ISBN 067232153X for this book.
Other events are fired by MenuItems to enable you to give better feedback to the user or to customize the user experience. MFC had the CCmdUI class for this purpose. Windows Forms provides the Popup event source.
Just before a MenuItem is shown, the Popup event is fired to give you time to decide whether to show, check, or change the appearance of a menu item. You can trap this event by adding an event handler to the Popup event source:
filemenu.Popup += new EventHandler(OnPopupFilemenu);
The handler for this event is defined in Listing 3.1.8. It shows some of the standard things you can do, checking, enabling, hiding, and so on, with MenuItems. The class has a Boolean variable called m_bPopupChecked. Every time the File menu is expanded, the program toggles this variable to true or false depending on its previous state. The Sender object is known to be a MenuItem, so it's possible to cast to that type safely. The three menu entries in the File menu are then checked, disabled, or hidden entirely, depending on the state of the variable. The image (seen in Figure 3.1.5) shows the menus in their two states.
Very often a group of menu entries will be strongly associated with one another, or one menu item will be separated from another by strategic placement of a menu separator. Under Windows Forms the menu separator is a menu item that does nothing but draw a line across the menu. This is very simple; just set the text of a menu item to a single dash:
MenuItem dummymenu = new MenuItem(); dummymenu.Text = "Separator"; menu.MenuItems.Add(dummymenu); dummymenu.MenuItems.Add(new MenuItem("Above")); dummymenu.MenuItems.Add(new MenuItem("-")); dummymenu.MenuItems.Add(new MenuItem("Below"));
Once a menu item has been popped up, all of its visible members can be selected by positioning the mouse over them or using the arrows keys. When this selection takes place, an event is fired. The event source for this is called Select, and it is handled in much the same way as the Popup event.
The Select event is used primarily to update a status bar or other control with a help string that explains an otherwise cryptic menu entry. It could also be used for other user-interface customization.
The demonstration in Listing 3.1.9 uses the Select event to display a string in a label control on the client area.
Figure 3.1.6 shows the menus.cs program in action.
Menus are built up from MenuItem components. These can be arranged across the screen on the menu bar, and are most often arranged vertically in drop-down menus. You can change the default layout of MenuItems to give a different UI style.
The Break and BarBreak methods are used to create menus that are arranged horizontally rather than vertically. Setting the BarBreak property in a MenuItem causes the item to be drawn in a new column. BarBreak adds a vertical separator bar to the menu between the columns. Break makes a new column but doesn't add the vertical bar. The modifications to the menus.cs code on lines 14 and 20 in the following result in the change seen in Figure 3.1.7.
1: MenuItem filemenu = new MenuItem(); 2: filemenu.Text = "&File"; 3: menu.MenuItems.Add(filemenu); 4: 5: MenuItem open = new MenuItem(); 6: open.Text = "&Open"; 7: open.Select += new EventHandler(ShowInfo); 8: filemenu.MenuItems.Add(open); 9: 10: MenuItem save= new MenuItem(); 11: save.Text = "&Save"; 12: save.Select += new EventHandler(ShowInfo); 13: filemenu.MenuItems.Add(save); 14: save.BarBreak=true; 15: 16: MenuItem exit= new MenuItem(); 17: exit.Text = "E&xit"; 18: exit.Select += new EventHandler(ShowInfo); 19: filemenu.MenuItems.Add(exit); 20: exit.Break=true; 21:
Similarly, the code changes to lines 14 and 20 in the following result in the menu style shown in Figure 3.1.8.
1: MenuItem filemenu = new MenuItem(); 2: filemenu.Text = "&File"; 3: menu.MenuItems.Add(filemenu); 4: 5: MenuItem open = new MenuItem(); 6: open.Text = "&Open"; 7: open.Select += new EventHandler(ShowInfo); 8: filemenu.MenuItems.Add(open); 9: 10: MenuItem save= new MenuItem(); 11: save.Text = "&Save"; 12: save.Select += new EventHandler(ShowInfo); 13: filemenu.MenuItems.Add(save); 14: //save.BarBreak=true; 15: 16: MenuItem exit= new MenuItem(); 17: exit.Text = "E&xit"; 18: exit.Select += new EventHandler(ShowInfo); 19: filemenu.MenuItems.Add(exit); 20: exit.Break=true; 21:
Each time you set the Break property, the MenuItem is placed in a new column.
To cater to cultures that read right-to-left or to add an unconventional style to your menus, you can modify the menu's RightToLeft property.
1: MainMenu menu = new MainMenu(); 2: menu.RightToLeft=RightToLeft.Yes; 3: MenuItem filemenu = new MenuItem(); 4: filemenu.Text = "&File";
Adding line 2 to resize.cs results in the effect seen in Figure 3.1.9.
A context menu is a floating menu that can pop up wherever it's needed for selections in a particular editing or user interface context. The convention is for the context menu to appear in response to a right-mouse button click.
Windows Forms follows this convention. The application has a ContextMenu property that, like its MainMenu counterpart, is available from the top-level application form.
Adding, showing, or modifying the appearance of a context menu and specifying its handler are largely the same as the main menu. The following adds a context menu with three items to the main window of the resize.cs form:
ContextMenu cmenu = new ContextMenu(); cmenu.MenuItems.Add(new MenuItem("&First")); cmenu.MenuItems.Add(new MenuItem("&Second")); cmenu.MenuItems.Add(new MenuItem("-")); cmenu.MenuItems.Add(new MenuItem("&Third")); this.ContextMenu=cmenu;
A simple right mouse click will bring up the context menu.
A common practice in Windows applications is to change menus according to the data displayed in the client window. To save you from having to create and destroy menus on-the-fly, .NET allows you to swap out menus and create new ones by merging one or more predefined menu hierarchies.
Listing 3.1.10 shows a simple application that constructs several menus and then combines them in different ways according to selections made by the user.
In this listing you can see that initially the menu creation process is normal, but that no menus are actually added to the MenuItem lists of a parent. The Edit and Play menus are kept separate.
The BuildMenu function on line 28 creates a new main menu and assigns it to the application's main menu. This will cause the GC to delete all of the submenus and entries from the main menu. BuildMenu then goes on to create the menu order or merge the two submenus into one, depending on the settings of the class member variables.
This technique allows you to create an initial set of menu items with all their handlers and settings in place, and then use them in many combinations without having to keep track of them or reset them to default values.
In Listing 3.1.10 the merge is very simple. There are however, more complex ways that MenuItems can be combined. The MenuItem has a merge order property so that when they are merged into another menu, they will sort themselves into a specific sequence. For example, you might want to have a File menu on which functionality is grouped according to the file type or system resources. With the menu merge order, you can ensure that common functions are first in the menu and less common ones are last. To illustrate the merge order functionality, Listing 3.1.11 shows a program in which the menu sorts itself according to the popularity of the selections.
This listing also illustrates how you can add more than one event handler to a Windows Forms Click. The same is true for the Select, Popup, and all other events.
MenuItem objects in Windows Forms have their own MenuItem collections. This allows you to create a hierarchical structure of menus that have their own cascading child menus within them. The following listing illustrates this process.
MenuItem filemenu = new MenuItem(); filemenu.Text = "&File"; menu.MenuItems.Add(filemenu); MenuItem open = new MenuItem(); open.Text = "&Open"; filemenu.MenuItems.Add(open); MenuItem print= new MenuItem(); print.Text = "Print..."; filemenu.MenuItems.Add(print); MenuItem temp= new MenuItem(); temp.Text = "Pre&view"; print.MenuItems.Add(temp); temp= new MenuItem(); temp.Text = "To &File"; print.MenuItems.Add(temp); MenuItem exit= new MenuItem(); exit.Text = "E&xit"; filemenu.MenuItems.Add(exit);
As before, the indentation shows the menu level. Figure 3.1.10 shows the menu in action.
3.144.31.163