65.9K
CodeProject 正在变化。 阅读更多。
Home

Visual Basic .NET 中的上下文菜单和事件处理

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (17投票s)

2004年11月9日

9分钟阅读

viewsIcon

299868

downloadIcon

6125

本文介绍了 Visual Basic .NET 中的 ContextMenu 和事件处理。

目录

引言

本文面向那些尚未在 .NET 环境中使用过 ContextMenu 并希望以一种更简单的方式理解 ContextMenu 及其关联事件处理程序如何工作的人。如何在用户右键单击通知图标时以编程方式生成通知图标的上下文菜单?作为先决条件,您应该对面向对象编程有一些了解。

此 Windows 应用程序功能允许您右键单击 Windows 窗体上的任何控件,并显示上下文相关的菜单。如果用户在 .NET 应用程序中右键单击或左键单击,窗体会显示自己的菜单。这对于用户了解特定控件或对象附加了哪些选项非常有用。

.NET 中的 ContextMenu

ContextMenu 是一个快捷菜单,您可以使用它为用户提供指定对象项的上下文相关菜单选项。您可以编写代码,在用户右键单击指定控件(如 TextBoxListBoxListView 等)时显示快捷菜单。通常,当用户右键单击控件或窗体本身时,会显示快捷菜单。ContextMenu 在 .NET 中的优点是,可以将一个 ContextMenu 用于多个控件。您需要做的是将每个控件的 ContextMenu 属性设置为 ContextMenu 类。您甚至可以在 ContextMenu 中创建嵌套的子菜单。

在某些方面,ContextMenuMainMenu 更简单,主要是因为它更小,有时只包含菜单项列表而没有子菜单。

示例

以下示例提供了逐步说明,用于使用分配给 ListViewTextBox 控件的快捷菜单,以在用户右键单击指定控件时显示一些菜单项。这意味着上下文菜单将根据每个控件而变化。此示例为 ContextMenuPopUp 事件创建了一个事件处理程序。事件处理程序中的代码确定两个控件中的哪一个(名为 listView1ListView 和名为 textBox1TextBox)是显示快捷菜单的控件。根据哪个控件导致 ContextMenu 显示其快捷菜单,该控件会将适当的 MenuItem 对象添加到 ContextMenu。此示例假定您在窗体中定义了一个名为 contextMenu1ContextMenu 类实例。此示例还假定您已将 TextBoxListView 添加到窗体中,并且这些控件的 ContextMenu 属性已设置为 ContextMenu1

创建上下文菜单的步骤

  1. 放置 ContextMenu 控件:

    ContextMenu 从工具箱拖放到您的窗体上。

    简单地说,如果您想在窗体上放置一个上下文菜单,只需将窗体设计器工具箱中的 ContextMenu 对象拖放到 Form 对象上,然后输入您要呈现的选项。在程序中调出菜单,并响应用户单击上下文菜单选项时触发的事件。

  2. 放置 ListView 和 TextBox 控件:

    ListViewTextBox 控件拖放到您的窗体上。

  3. 设置 ContextMenu 属性:

    向您的窗体添加一个 ContextMenu,并将 TextBoxListBoxContextMenu 属性设置为它。然后,在 ContextMenuPopUp 事件中,您可以动态创建 MenuItem,如下所示。您可以使用旧式 Select Case 根据 MenuItem 文本来捕获选择了哪个菜单项。

    将每个控件的 ContextMenu 属性设置为 ContextMenu1

    通过更改控件的 ContextMenu 属性来将 ContextMenu 与控件关联。ContextMenu 的属性位于控件的属性和 ContextMenu 组件的属性中。

  4. MouseUp 事件例程:

    您正在触发什么类型的事件,以及您将如何处理 ContextMenu 控件?从下一节的代码中可以看出,您可以通过将“sender”变量强制转换为 MenuItem 并查询 Text 属性来确定单击了哪个项。您可以使用该值传递给另一个函数或对其执行某些操作。

    在控件的“MouseUp”事件上编写一个例程。如果单击并释放了鼠标右键,将发生此情况;显示分配给 listView1TextBox1 控件的上下文菜单。

    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

    根据您的编程技能,您可以通过将此事件放在一个单独的过程并将该过程调用到控件的 mouse up 事件中来减少源代码的行数。例如,我以不同的方式重新创建了这段源代码,您可以在下面看到。

    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

    将“HandleMouseUp”例程调用到 ListView1 控件的 MouseUp 事件。

    Private Sub listView1_MouseUp(Byval Sender as Object, _
           Byval e As System.Windows.Forms.MouseEventArgs) _
           Handles listView1.MouseUp
      HandleMouseUp(listView1,e)
    End sub

    同样,在 TextBox1MouseUp 事件中调用 HandleMouseUp 过程。

    Private Sub TextBox1_MouseUp(Byval Sender as Object, _
           Byval e As System.Windows.Forms.MouseEventArgs) _
           Handles TextBox1.MouseUp
      HandleMouseUp(listView1,e)
    End sub

    哇,这大大减少了源代码的行数,看起来很整洁,对吧?如我之前提到的,您可以根据您的编程专业知识或技能和适当的编码标准在源代码中编写自己的过程。我倾向于创建一个函数目录,然后,根据您新菜单项中的文本,您可以用一个检查发送者文本的处理器来处理它,如上所示。

    它不会麻烦您走过这个过程,因为它非常直观。但是,您需要注意的一个更改是,上下文菜单不再从窗体的主菜单中获取。相反,您现在为每个上下文菜单添加一个单独的 ContextMenu 控件。要编辑上下文菜单,请单击组件托盘中的相应 ContextMenu 控件进行选择。菜单将出现在顶部,就像一个常规的下拉菜单一样,只是您可以根据需要进行编辑。

  5. 编写 ContextHandler 过程:

    下一步是编写一个“ContextHandler”例程。

    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

    如我之前提到的,您甚至可以通过将源代码分解为不同的函数来减少源代码的行数。上面的代码行被拆分成不同的子例程。下面列出了它们:

    一个名为 AddContextMenu 的新过程将根据 Caption 参数将 MenuItem 添加到上下文菜单。详细信息列在以下代码块中:

    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

    AddHandler 例程将在程序执行期间的任何时间与 ContextHandler 对象事件一起执行。AddHandler 例程的详细信息在 处理事件 部分中进行了说明,该部分在本文末尾进行描述。

    基于我们上面创建的新过程“AddContextMenu”,我们也可以修改“ContextHandler”过程。

    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

    在以下 HandleMouseUp 事件中,您需要删除 ContextHandler 方法,以便使用 ContextMenu1.SourceControl 方法,因为 MenuSelected 函数将自动处理 ContextMenu1.Popup 事件。修改后的过程如下所示:

    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

    同样,为了使其完全正常工作,您需要为 ContextMenu1 的 popup 添加一个新的处理程序,我在这里创建并命名为“HandlePopup”。

    Private Sub HandlePopup(ByVal sender As Object, _
           ByVal e As System.EventArgs) Handles ContextMenu1.Popup
      MyPopupEventHandler(sender, e)
    End Sub

    注意 1:我使用了一个名为“SEPARATOR”的常量来分隔菜单项,这与旧版本的 VB 相同。您也可以使用 ContextMenu 类中的 BreakBreakLine 方法将分隔符包含到菜单项中。

    注意 2:我用 ContextMenu1.SourceControl 替换了 Sender.Name 方法。Sender.Name 的功能与 ContextMenu1.SourceControl 相同,但个人认为这更好地处理了上下文菜单的正确位置。如果您使用 Sender.Name 而不是 ContextMenu1.SourceControl,则需要在每个控件事件中添加以下代码行。

    注意 3AddContextMenu 过程不支持添加嵌套子菜单。

  6. 处理事件:

    事件是通知应用程序某个对象已发生某事的行为。例如,当您从 ContextMenu 中单击某个菜单项以触发关联事件时,您需要在程序中定义一个新的 EventHandler 例程。

    要在此应用程序中处理 ContextMenu 事件,您必须提供一个事件处理程序(一个事件处理方法),该处理程序响应事件执行程序逻辑,并将事件处理程序注册到事件源。

    要将事件处理程序连接到 ContextMenu,您必须创建一个 EventHandler 实例,该实例在其参数中包含对 ContextMenu_Clicked 的引用,并将此委托实例添加到 ContextMenuPopUp_Click 事件中,如下例所示。

    AddHandler 方法将事件与事件处理程序关联起来,并允许您在程序执行期间随时开始事件处理。

    请查看下面列出的程序。

    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

    上面代码中的 AddHandler 语句会在用户单击菜单项时触发一个事件,并执行下面列出的 cMenuClick 过程。

    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

示例屏幕截图

要求

  • 命名空间System.Windows.Forms
  • 平台:Windows 98、Windows NT 4.0、Windows Millennium Edition、Windows 2000、Windows XP Home Edition、Windows XP Professional、Windows Server 2003 系列、.NET Compact Framework - Windows CE .NET。
  • 程序集System.Windows.Forms(在 System.Windows.Forms.dll 中)。

总结

微软在 Visual Studio .NET 上投入了巨资。Visual Studio .NET 让用户可以轻松地根据自己的工作风格定制工具,并使他们能够适应团队的实践。Visual Basic 7.0 语言获得了一些主要功能和许多小的增强功能,这些功能和增强功能共同提供了易用性和开发人员生产力的显著提高。通过 VB.NET,微软采取了一种全新的理念。它们不提供做特定事情的特定工具,而是提供做基本事情的对象。现在有菜单对象。

本文展示了如何为 ListBoxTextBox 控件实现一个简单的上下文菜单。VB.NET 中 ContextMenuMainMenuMenuItem 的定义表明它们都派生自 Menu 抽象类。您从菜单中获得的许多出色性能都基于扩展这些类中的属性和方法。

我的下一篇文章将解释 Windows Explorer 中的上下文菜单扩展。

© . All rights reserved.