Checking the visibility of a ContextMenu when associated with a NotifyIcon

无人久伴 提交于 2019-12-11 22:57:18

问题


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().

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.

Are there any workarounds?


回答1:


Under the "Remarks" section for the MSDN docs on TrackPopupMenuEx, it says:

To display a context menu for a notification icon, the current window must be the foreground window before the application calls TrackPopupMenu or 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. You can see from by looking at NotifyIcon.ShowContextMenu() that it is indeed the case:

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


来源:https://stackoverflow.com/questions/8032972/checking-the-visibility-of-a-contextmenu-when-associated-with-a-notifyicon

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!