当窗体没有焦点时激活ContextMenuStrip

3
  1. 我能够成功地在 Windows 窗体之外显示 ContextMenuScript (CMS)。
  2. 我可以使用鼠标指针选择/点击项目。
  3. 然而,在窗体没有焦点的情况下,它不支持键盘控制(上下箭头、ESC)。
  4. 如果窗体有焦点并且 CMS 显示出来,则键盘可以控制它,但是在没有焦点时不能控制 :(。
  5. 我需要代码方面的帮助,以实现在没有窗体焦点的情况下进行控制。

谢谢

   Public Const CTRL_Key As Integer = &H2
   Public Const Hot_Key As Integer = &H312
   Public Declare Function RegisterHotKey Lib "user32" (ByVal hwnd As IntPtr, ByVal id As Integer, ByVal fsModifiers As Integer, ByVal vk As Integer) As Integer
   Public Declare Function UnregisterHotKey Lib "user32" (ByVal hwnd As IntPtr, ByVal id As Integer) As Integer

   Private Sub Hot_Key_Register() Handles MyBase.Load
    RegisterHotKey(Me.Handle, 100, CTRL_Key, Keys.NumPad1)
    RegisterHotKey(Me.Handle, 200, CTRL_Key, Keys.NumPad2)
    RegisterHotKey(Me.Handle, 300, CTRL_Key, Keys.NumPad3)
   End Sub

   Protected Overrides Sub WndProc(ByRef Window_Message As Message)

    If Window_Message.Msg = Hot_Key Then
        Dim id As IntPtr = Window_Message.WParam
        Select Case (id.ToString)
            Case "100"
                CMS_01.Show(Cursor.Position.X, Cursor.Position.Y)
            Case "200"
                CMS_02.Show(Cursor.Position.X, Cursor.Position.Y)
            Case "300"
                CMS_03.Show(Cursor.Position.X, Cursor.Position.Y)
        End Select
    End If
    MyBase.WndProc(Window_Message)
   End Sub
1个回答

1

选项1 - 使用NotifyIcon

最简单的解决方法是使用一个不可见的NotifyIcon组件,因为它在其内部代码中处理了此情况。

在您的表单上放置一个NotifyIcon实例,然后将上下文菜单条分配给其ContextMenuStrip属性,然后使用反射调用其ShowContextMenu私有方法来使用它显示上下文菜单。

示例

Private Sub ShowContextMenu(menu As ContextMenuStrip)
    NotifyIcon1.Visible = False
    NotifyIcon1.ContextMenuStrip = menu
    Dim m = NotifyIcon1.GetType().GetMethod("ShowContextMenu",
        Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)
    m.Invoke(NotifyIcon1, Nothing)
End Sub
Protected Overrides Sub WndProc(ByRef Window_Message As Message)
    If Window_Message.Msg = Hot_Key Then
        Dim id As IntPtr = Window_Message.WParam
        Select Case (id.ToString)
            Case "100"
                ShowContextMenu(CMS_01)
        End Select
    End If
    MyBase.WndProc(Window_Message)
End Sub

选项2 - 使用本地窗口

以下是不使用NotifyIcon,而是使用NativeWindow的修复方法。下面的代码片段关注活动窗口,如果当前窗体是活动的,则不使用本地窗口,否则创建并使用本地窗口。

示例

Private window As NativeWindow
Private Sub ShowContextMenu(menu As ContextMenuStrip, p As Point)
    If (Form.ActiveForm IsNot Me) Then
        If (window Is Nothing) Then
            window = New NativeWindow()
            window.CreateHandle(New CreateParams())
        End If
        SetForegroundWindow(window.Handle)
    End If
    menu.Show(p)
End Sub

并显示菜单:

ShowContextMenu(CMS_01, Cursor.Position)

记得在关闭/释放窗体时释放窗口句柄:

If (window IsNot Nothing) Then
    window.DestroyHandle()
    window = Nothing
End If

嗨Reza,非常感谢您提供的代码。您概述的两种方法都帮助我实现了想要的功能;但是,还存在一些小问题。(A) CMS在按下热键后第一次不会显示,但屏幕上会出现一个小交叉按钮框。(B)同样的交叉按钮框将保留在屏幕上。如果您能为我提供隐藏此框的解决方案,或者它可以出现在系统托盘中,那将是最好的。再次感谢 :) - J D
嗨JD,我再次检查了解决方案,但没有复现任何问题。我正在使用10版本1709。 - Reza Aghaei
确保你已正确注册热键(在窗体已显示后),并且在关闭或销毁时,也确保总是正确注销它们。如果你使用了NativeWindow的解决方案,则还要确保正确地处理窗口的释放(在关闭或销毁时)。 - Reza Aghaei
嗨Reze,是的,你说得对。代码完美无缺。我已经标记并回答了。非常感谢。小框是我在测试期间添加的子表单。非常感谢 :) - J D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接