简体   繁体   English

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

[英]Checking the visibility of a ContextMenu when associated with a NotifyIcon

According to this answer on another question, the Collapsed event of a ContextMenu is only raised if it's associated to a control before calling Show() . 根据另一个问题的答案 ,只有在调用Show()之前将ContextMenu的Collapsed事件与控件关联,才会引发它。

SInce a NotifyIcon does not count as a control, I can't hook onto the Collapsed event to detect when the menu associated to one is hidden. 因为NotifyIcon不算作控件,所以我无法挂起Collapsed事件来检测与之关联的菜单何时被隐藏。

Are there any workarounds? 有什么解决方法吗?

Under the "Remarks" section for the MSDN docs on TrackPopupMenuEx , it says: TrackPopupMenuEx上的MSDN文档的“备注”部分下,它说:

To display a context menu for a notification icon, the current window must be the foreground window before the application calls TrackPopupMenu or TrackPopupMenuEx. 若要显示通知图标的上下文菜单,在应用程序调用TrackPopupMenu或TrackPopupMenuEx之前,当前窗口必须是前景窗口。 Otherwise, the menu will not disappear when the user clicks outside of the menu or the window that created the menu (if it is visible). 否则,当用户在菜单或创建菜单的窗口之外单击时(如果可见),菜单将不会消失。 If the current window is a child window, you must set the (top-level) parent window as the foreground window. 如果当前窗口是子窗口,则必须将(顶层)父窗口设置为前景窗口。

So that could mean that when the ContextMenu is visible, the window on the NotifyIcon will be the foreground window. 因此,这意味着当ContextMenu可见时, NotifyIcon上的窗口将成为前景窗口。 You can see from by looking at NotifyIcon.ShowContextMenu() that it is indeed the case: 通过查看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);
            }
        }
    }

Using ILSpy I then noticed NotifyIcon has a private member window , which refers to a private class with base type NativeWindow . 然后,我使用ILSpy注意到NotifyIcon有一个私有成员window ,该window引用具有基本类型NativeWindow的私有类。 Therefore, you can check like this: 因此,您可以像这样检查:

[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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM