Context Menu and Event Handling in Visual Basic .NET






4.77/5 (17 votes)
Nov 9, 2004
9 min read

297764

6125
This article describes ContextMenu and event handling in Visual Basic .NET.
Contents
- Introduction
- ContextMenu in .NET
- Example
- Steps to create the context menu
- Sample Screenshots
- Requirements
- Summary
Introduction
This article targets those who have not yet worked with ContextMenu
in .NET environment and would like to understand a little easy way of how ContextMenu
and its associated event handler works. How can a context menu for a notify icon be programmatically generated when the user right clicks on the notify icon? As a prerequisite, you should have a little bit idea of object oriented programming.
This Windows application feature allows gives you the ability to right-click on any control of your Windows Form and get a context-sensitive menu. If a user right-clicks or left-clicks in a .NET application, the form shows its own menu. This is very helpful for the user to know what options are attached to a particular control or an object.
ContextMenu in .NET
A ContextMenu
is a shortcut menu, which you can use to give context-specific menu options of a specified object item to the user. You can write the code to display the shortcut menu whenever the user right-clicks on a specified control such as TextBox
, ListBox
, ListView
etc. Typically, a shortcut menu is displayed when a user clicks the right mouse button over a control or the form itself. The beauty of .NET in terms of ContextMenu
is that it is possible to use one ContextMenu
in more than one control. What you need to do is set the ContextMenu
property of each control to ContextMenu
class. Even you can also create nested submenus in a ContextMenu
.
ContextMenu
is in some ways simpler than MainMenu
, mostly because it is smaller, and sometimes contains only a list of menu items without any submenus.
Example
The following example gives a step by step instruction to use a shortcut menu assigned to the ListView
and TextBox
control to display some of the menu items based on the user right-click event of the mouse in a specified control. This means the context menu will be changed based on each control. This example creates an event handler for the PopUp
event of the ContextMenu
. The code in the event handler determines which of two controls, a ListView
named listView1
and a TextBox
named textBox1
, is the control displaying the shortcut menu. Depending on which control caused the ContextMenu
to display its shortcut menu, the control adds the appropriate MenuItem
objects to the ContextMenu
. This example assumes that you have an instance of the ContextMenu
class, named contextMenu1
, defined within the form. This example also assumes that you have a TextBox
and ListView
added to a form, and that the ContextMenu
property of these controls is set to ContextMenu1
.
Steps to create the context menu
- Placing ContextMenu Control:
Drag and drop a
ContextMenu
on to your form from the toolbox.Simply, if you want to place a context menu on your form, just drop a
ContextMenu
object from the form designer toolbox on to theForm
object, then type in the choices you want to present. Bring up the menu in your program, and respond to the events fired when the user clicks on a context menu choice. - Placing ListView and TextBox Controls:
Drag and drop a
ListView
and aTextBox
control onto your form. - Setting ContextMenu Property:
Add a
ContextMenu
to your form and set theContextMenu
property of yourTextBox
andListBox
to it. Then, in thePopUp
event of yourContextMenu
, you can dynamically create theMenuItem
s as shown below. You can trap which menu item was selected using an old schoolSelect Case
based on theMenuItem
text:Set the
ContextMenu
property of each control toContextMenu1
.A
ContextMenu
is associated with a control by changing theContextMenu
property of a control. The properties for theContextMenu
are both in the properties for the control and theContextMenu
component. - MouseUp Event Routine:
What kind of events are you firing and what will you be doing with
ContextMenu
control? As you can see from the code in the next section, you can determine which item was clicked by casting the "sender
" variable to aMenuItem
and querying theText
property. You can use that value to pass to another function or do something with it.Write a routine on the “
MouseUp
” event on your control. This will happen if the right mouse button was clicked and released; display the context menu assigned to thelistView1
orTextBox1
control.Private Sub listView1_MouseUp(Byval Sender as Object, _ Byval e As System.Windows.Forms.MouseEventArgs) _ Handles listView1.MouseUp 'Checking the Mouse right Button If e.Button = MouseButtons.Right Then ContextHandler(listView1,e) listView1.ContextMenu.Show(listView1, New Point(e.X,e.Y)) End if End sub Private Sub TextBox1_MouseUp(Byval Sender as Object, _ Byval e As System.Windows.Forms.MouseEventArgs) _ Handles TextBox1.MouseUp 'Checking the Mouse right Button If e.Button = MouseButtons.Right Then ContextHandler(TextBox1,e) TextBox1.ContextMenu.Show(TextBox1, New Point(e.X,e.Y)) End if End sub
Based on your programming skills, you can even reduce the number of lines of your source code by putting this event in a separate procedure and calling this procedure in control mouse up event. For example, I have recreated this source code in a different way, which you can see below:
Private Sub HandleMouseUp(Byval Control as Object, _ Byval e As System.Windows.Forms.MouseEventArgs) 'Checking the Mouse right Button If e.Button = MouseButtons.Right Then ContextHandler(Control,e) Control.ContextMenu.Show(Control, New Point(e.X,e.Y)) End if End sub
Call the routine “
HandleMouseUp
” to yourMouseUp
event ofListView1
control.Private Sub listView1_MouseUp(Byval Sender as Object, _ Byval e As System.Windows.Forms.MouseEventArgs) _ Handles listView1.MouseUp HandleMouseUp(listView1,e) End sub
Similarly, call the
HandleMouseUp
procedure inTextBox1
MouseUp
event:Private Sub TextBox1_MouseUp(Byval Sender as Object, _ Byval e As System.Windows.Forms.MouseEventArgs) _ Handles TextBox1.MouseUp HandleMouseUp(listView1,e) End sub
Wow, it reduced a lot of lines in your source code and looks neat. Right! As I mentioned earlier, you can write your own procedure in your source code based on your programming expertise or skills and appropriate coding standards. I would prefer to create a catalog of functions, and then, depending on the text in your new menu item, you can handle it with only one handler that checks the text of the sender as shown above.
It won’t bother to walk you through this process, as it is very intuitive. However, one change that you need to be aware of is that context menus are no longer taken from a form’s main menu. Instead, you now add a separate
ContextMenu
control for each context menu. To edit a context menu, click to select the correspondingContextMenu
control from the component tray. The menu will appear at the top as though it were a normal drop-down menu, except that you’ll be able to edit it as needed. - Writing ContextHandler Procedure:
Next step is to write a “
ContextHandler
” routine.Protected Sub ContextHandler (ByVal sender As System.Object, _ ByVal e As System.EventArgs) 'ListView Menu Captions Const LVW_NEW_MENU = "&New" Const LVW_OPEN_MENU = "&Open File" Const LVW_PREVIEW = "&Preview" Const LVW_DELETE = "&Delete" 'Text Menu Captions Const TEXT_MENU1 = "Text Menu&1" Const TEXT_MENU11 = "Text Menu1&1" ‘Sub Menu 1 Const TEXT_MENU12 = "Text Menu1&2" ‘Sub Menu 2 Const TEXT_CUT = "&Cut" Const TEXT_COPY = "&Copy" Const TEXT_PASTE = "&PASTE" Const TEXT_SELECT_ALL = "&Select All" Const SEPARATOR = "-" Const LIST_VIEW_NAME=”listView1” Const TEXT_BOX_NAME=”TextBox1” ' Clear all previously added MenuItems. ContextMenu1.MenuItems.Clear() If sender.name = LIST_VIEW_NAME Then 'ContextMenu1.SourceControl is 'Define the MenuItem object to display for the ListView1. Dim menuItem1 As New MenuItem(LVW_NEW_MENU) Dim menuItem2 As New MenuItem(LVW_OPEN_MENU) Dim menuItem3 As New MenuItem(SEPARATOR) Dim menuItem4 As New MenuItem(LVW_PREVIEW) Dim menuItem5 As New MenuItem(SEPARATOR) Dim menuItem6 As New MenuItem(LVW_DELETE) ' Add MenuItems to display for the TextBox. ContextMenu1.MenuItems.Add(menuItem1) ContextMenu1.MenuItems.Add(menuItem2) ContextMenu1.MenuItems.Add(menuItem3) ContextMenu1.MenuItems.Add(menuItem4) ContextMenu1.MenuItems.Add(menuItem5) If listView1.FocusedItem Is Nothing Then menuItem2.Enabled = False menuItem4.Enabled = False menuItem6.Enabled = False End If ElseIf sender.name = TEXT_BOX_NAME Then 'ContextMenu1.SourceControl is 'Define the MenuItem object to display for the TextBox1. Dim menuItem7 As New MenuItem(TEXT_MENU1) Dim menuItem8 As New MenuItem(TEXT_MENU11) Dim menuItem9 As New MenuItem(SEPARATOR) Dim menuItem10 As New MenuItem(TEXT_MENU12) Dim menuItem11 As New MenuItem(SEPARATOR) Dim menuItem12 As New MenuItem(TEXT_CUT) Dim menuItem13 As New MenuItem(TEXT_COPY) Dim menuItem14 As New MenuItem(TEXT_PASTE) Dim menuItem15 As New MenuItem(SEPARATOR) Dim menuItem16 As New MenuItem(TEXT_SELECT_ALL) 'Set the checked property to true since 'this is the default value. menuItem8.Checked = True 'Define a shortcut key combination for the menu item. menuItem9.Shortcut = Shortcut.CtrlS 'Add menuItem8 and menuItem9 to menuItem7's 'list of menu items or sub menus. MenuItem7.MenuItems.Add(menuItem8) MenuItem7.MenuItems.Add(SEPARATOR) MenuItem7.MenuItems.Add(menuItem9) 'Add MenuItems to display for the TextBox. ContextMenu1.MenuItems.Add(menuItem7) ContextMenu1.MenuItems.Add(menuItem10) ContextMenu1.MenuItems.Add(menuItem11) ContextMenu1.MenuItems.Add(menuItem12) ContextMenu1.MenuItems.Add(menuItem13) ContextMenu1.MenuItems.Add(menuItem14) ContextMenu1.MenuItems.Add(menuItem15) ContextMenu1.MenuItems.Add(menuItem16) 'If no text, disable the cut, copy, paste menus If TextBox1.Text = “” Then MenuItem12.Enabled=false MenuItem13.Enabled=false MenuItem14.Enabled=false MenuItem16.Enabled=false End If End If End Sub
As I mentioned earlier, you can even reduce the number of lines in your source code breaking it into different functions. The above line of code is split into different sub routines. This is listed below:
A new procedure called
AddContextMenu
will add aMenuItem
to the context menu based on theCaption
parameter. The details are listed in the following block of code:Private Sub AddContextMenu(ByVal Caption As String, _ Optional ByVal IsEnabled As Boolean = True) Dim objMenuItem As MenuItem objMenuItem = New MenuItem objMenuItem.Text = Caption objMenuItem.Enabled = IsEnabled ContextMenu1.MenuItems.Add(objMenuItem) ' Handling Popup menu item click event AddHandler objMenuItem.Click, AddressOf CMenuClick End Sub
The
AddHandler
routine will execute withContextHandler
object event at any time during program execution.AddHandler
routine details are explained in the consuming events section, which is described at the end of this article.Based on the new procedure “
AddContextMenu
”, which we created above, we can modify the “ContextHandler
” procedure as well.Protected Sub ContextHandler (ByVal sender As System.Object, _ ByVal e As System.EventArgs) 'ListView Menu Captions Const LVW_NEW_MENU = "&New" Const LVW_OPEN_MENU = "&Open File" Const LVW_PREVIEW = "&Preview" Const LVW_DELETE = "&Delete" 'Text Menu Captions Const TEXT_MENU1 = "Text Menu&1" Const TEXT_MENU11 = "Text Menu1&1" ‘Sub Menu 1 Const TEXT_MENU12 = "Text Menu1&2" ‘Sub Menu 2 Const TEXT_CUT = "&Cut" Const TEXT_COPY = "&Copy" Const TEXT_PASTE = "&PASTE" Const TEXT_SELECT_ALL = "&Select All" Const SEPARATOR = "-" Const LIST_VIEW_NAME=”listView1” Const TEXT_BOX_NAME=”TextBox1” ' Clear all previously added MenuItems. ContextMenu1.MenuItems.Clear() If ContextMenu1.SourceControl is listView1 Then 'or sender.name = LIST_VIEW_NAME ' Define the MenuItem object to display for the ListView1. AddContextMenu(LVW_NEW_MENU) AddContextMenu(LVW_OPEN_MENU, listView1.FocusedItem Is Nothing) AddContextMenu(SEPARATOR) AddContextMenu(LVW_PREVIEW, listView1.FocusedItem Is Nothing) AddContextMenu(SEPARATOR) AddContextMenu(LVW_DELETE, listView1.FocusedItem Is Nothing) ElseIf ContextMenu1.SourceControl is TextBox1 Then 'or sender.name = TEXT_BOX_NAME Then 'ContextMenu1.SourceControl is ' Define the MenuItem object to display for the TextBox1. ' Set the checked property to true since this is the default value. SubmenuItem1.Checked = True ' Define a shortcut key combination for the menu item. SubmenuItem2.Shortcut = Shortcut.CtrlS ' Add menuItem8 and menuItem9 to menuItem7's ' list of menu items or sub menus. ' My AddContextMenu procedure is not handling ' to support nested submenu creation MenuItem1.MenuItems.Add(SubmenuItem1) MenuItem1.MenuItems.Add(SEPARATOR) MenuItem1.MenuItems.Add(SubmenuItem2) ' Add MenuItems to display for the TextBox. ContextMenu1.MenuItems.Add(menuItem) AddContextMenu(SEPARATOR) AddContextMenu(LVW_NEW_MENU) AddContextMenu(TEXT_CUT, TextBox1.Text = “”) AddContextMenu(TEXT_COPY, TextBox1.Text = “”) AddContextMenu(TEXT_PASTE, TextBox1.Text = “”) AddContextMenu(SEPARATOR) AddContextMenu(TEXT_SELECT_ALL, TextBox1.Text = “”) End If End Sub
In the following
HandleMouseUp
event, you need to remove theContextHandler
method in order to useContextMenu1.SourceControl
method because the functionMenuSelected
will automatically handle the eventContextMenu1.Popup
. The revised procedure is shown below:Private Sub HandleMouseUp(Byval Control as Object, _ Byval e As System.Windows.Forms.MouseEventArgs) ' Checking the Mouse right Button If e.Button = MouseButtons.Right Then Control.ContextMenu.Show(Control, New Point(e.X,e.Y)) End if End sub
Again, in order to get fully functional, you need to add a new handle for
ContextMenu1
popup, which I created below and named as “HandlePopup
”.Private Sub HandlePopup(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles ContextMenu1.Popup MyPopupEventHandler(sender, e) End Sub
Note 1: I used a constant name called “
SEPARATOR
” for separating menu items, which is same as the old version of VB. You can even useBreak
orBreakLine
method from theContextMenu
class to include a separator into menu items.Note 2: I replaced
Sender.Name
method withContextMenu1.SourceControl
. TheSender.Name
will also function as same as theContextMenu1.SourceControl
, but, I personally feel this is much better to handle context menu in the right place. If you are usingSender.Name
instead ofContextMenu1.SourceControl
, you need to add the following lines of code in each of the control event.Note 3: The
AddContextMenu
procedure does not support adding nested sub menus. - Consuming Events:
An event is an action that informs an application that something has happened in the object. For example, when you click a particular menu item from the
ContextMenu
in order to fire the associated event, you need to define a newEventHandler
routine into your program.To consume a
ContextMenu
event in this application, you must provide an event handler (an event-handling method) that executes program logic in response to the event, and register the event handler with the event source.To wire an event handler to the
ContextMenu
, you must create an instance ofEventHandler
that takes a reference toContextMenu_Clicked
in its argument, and add this delegate instance to thePopUp_Click
event of theContextMenu
, as shown in the following example.AddHandler
method associates an event with an event handler, and it allows you to start event handling at any time during program execution.Please go through the program listed in, which is shown below:
Private Sub AddContextMenu(ByVal Caption As String, _ Optional ByVal IsEnabled As Boolean = True) Dim objMenuItem As MenuItem objMenuItem = New MenuItem objMenuItem.Text = Caption objMenuItem.Enabled = IsEnabled ContextMenu1.MenuItems.Add(objMenuItem) ' Handling Popup menu item click event AddHandler objMenuItem.Click, AddressOf CMenuClick End Sub
The
AddHandler
statement in the above code will fire an event whenever a user clicks on the menu item, and executes the procedurecMenuClick
which is listed below:Private Sub CMenuClick(ByVal sender As Object, _ ByVal e As System.EventArgs) 'Point to menu item clicked Dim objCurMenuItem As MenuItem = CType(sender, MenuItem) 'create the submenu based on whatever selection is being made, mnuSelection Select Case objCurMenuItem.Text Case LVW_NEW_MENU: Msgbox(“New Menu”) Case LVW_NEW_MENU: Msgbox(“New Menu”) Case LVW_OPEN_MENU: Msgbox(“New Menu”) Case LVW_PREVIEW: Msgbox(“New Menu”) Case LVW_DELETE Msgbox(“New Menu”) Case TEXT_CUT: Msgbox(“New Menu”) Case TEXT_COPY: Msgbox(“New Menu”) Case TEXT_PASTE: Msgbox(“New Menu”) Case TEXT_SELECT_ALL: Msgbox(“New Menu”) End Select objCurMenuItem = Nothing End Sub
Sample Screenshots
Requirements
- Namespace:
System.Windows.Forms
. - Platforms: Windows 98, Windows NT 4.0, Windows Millennium Edition, Windows 2000, Windows XP Home Edition, Windows XP Professional, Windows Server 2003 family, .NET Compact Framework - Windows CE .NET.
- Assembly:
System.Windows.Forms
(in System.Windows.Forms.dll).
Summary
Microsoft has invested heavily in Visual Studio .NET. Visual Studio .NET lets users easily tailor the tool to their personal working style and enables them to accommodate team practices. The Visual Basic 7.0 language gains several major features and many smaller enhancements that together provide significant increases in ease of use and developer productivity. With VB.NET, Microsoft has adopted a whole new philosophy. Rather than specific tools that do specific things, they give you objects that do the basic things. There are menu objects instead.
This article showed how to implement a simple context menu for the ListBox
and TextBox
controls. The definitions of ContextMenu
, MainMenu
, and MenuItem
in VB.NET show that all are derived from the Menu
abstract class. A lot of the great performance that you can get from menus is based on extending the properties and methods in these classes.
My next article is going to explain about Context Menu Extension in Windows Explorer.