当与NotifyIcon关联时,检查ContextMenu的可见性

本文关键字:ContextMenu 可见性 检查 NotifyIcon 关联 当与 | 更新日期: 2023-09-27 18:13:37

根据对另一个问题的回答,ContextMenu的Collapsed事件只有在调用Show()之前与控件关联时才会引发。

由于NotifyIcon不作为一个控制,我不能挂钩到Collapsed事件来检测当菜单关联到一个被隐藏。

有什么变通办法吗?

当与NotifyIcon关联时,检查ContextMenu的可见性

在TrackPopupMenuEx的MSDN文档的" comments "部分,它说:

显示通知图标的上下文菜单,当前窗口在应用程序调用之前必须是前台窗口TrackPopupMenu或TrackPopupMenuEx。否则,菜单不会显示当用户在菜单或窗口外单击该按钮时消失创建菜单(如果它是可见的)。如果当前窗口是子窗口窗口时,必须将(顶级)父窗口设置为前景窗口。

所以这可能意味着当ContextMenu可见时,NotifyIcon上的窗口将是前景窗口。从NotifyIcon.ShowContextMenu()可以看出,情况确实如此:

    private void ShowContextMenu()
    {
        if (this.contextMenu != null || this.contextMenuStrip != null)
        {
            NativeMethods.POINT pOINT = new NativeMethods.POINT();
            UnsafeNativeMethods.GetCursorPos(pOINT);
            UnsafeNativeMethods.SetForegroundWindow(new HandleRef(this.window, this.window.Handle));
            if (this.contextMenu != null)
            {
                this.contextMenu.OnPopup(EventArgs.Empty);
                SafeNativeMethods.TrackPopupMenuEx(new HandleRef(this.contextMenu, this.contextMenu.Handle), 72, pOINT.x, pOINT.y, new HandleRef(this.window, this.window.Handle), null);
                UnsafeNativeMethods.PostMessage(new HandleRef(this.window, this.window.Handle), 0, IntPtr.Zero, IntPtr.Zero);
                return;
            }
            if (this.contextMenuStrip != null)
            {
                this.contextMenuStrip.ShowInTaskbar(pOINT.x, pOINT.y);
            }
        }
    }

使用ILSpy,我注意到NotifyIcon有一个私有成员window,它引用了一个基类型为NativeWindow的私有类。因此,您可以这样检查:

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetForegroundWindow();
...
FieldInfo notifyIconNativeWindowInfo = typeof(NotifyIcon).GetField("window", BindingFlags.NonPublic | BindingFlags.Instance);
NativeWindow notifyIconNativeWindow = (NativeWindow)notifyIconNativeWindowInfo.GetValue(notifyIcon1);
bool visible = notifyIcon1.Handle == GetForegroundWindow();