winforms 在Deactivate事件中,是否可以知道新的活动窗口/控件?

ewm0tg9j  于 2023-08-07  发布在  其他
关注(0)|答案(1)|浏览(108)

我的应用程序是一个基于系统托盘的弹出窗体。我在系统托盘中有一个NotifyIcon。当单击通知图标时,它将切换主窗体。当主窗体被停用时,它会隐藏自己。这基本上是大多数基于系统托盘的应用程序的标准行为。
当显示主窗体时,用户单击通知图标,人们会期望主窗体隐藏,这也是标准行为。但是,在Deactivate事件处理程序中,我隐藏了主窗体。紧接着,在notify图标的Click事件处理程序中,我们看到主窗体被隐藏,我们将其切换为再次显示。这是不正确的行为。
所以,我想知道,是否有一种方法可以在Deactivate处理程序中知道,我们失去焦点的原因是否是用户单击了通知图标。或者,有没有其他更聪明的方法来处理这个问题?

  • 谢谢-谢谢
cig3rfwq

cig3rfwq1#

Deactivate事件中,您可以取得NotifyIconIconRectangle,然后检查它是否为Contains()MousePosition,进而决定是否为Close()MainForm
我引用了这篇文章:How to obtain the icon rectangle of a NotifyIcon

internal static class NotifyIconExtensions
{
    //Works with Shell32.dll (version 6.1 or later)
    [DllImport("shell32.dll")]
    static extern int Shell_NotifyIconGetRect([In] ref NOTIFYICONIDENTIFIER identifier, [Out] out RECT iconLocation);

    [StructLayout(LayoutKind.Sequential)]
    struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct NOTIFYICONIDENTIFIER
    {
        public uint cbSize;
        public IntPtr hWnd;
        public uint uID;
        public Guid guidItem;
    }

    public static bool TryGetRectangle(this NotifyIcon notifyIcon, out Rectangle rectangle)
    {
        rectangle = Rectangle.Empty;

        var type = notifyIcon.GetType();

        var idFieldName = "id";
        var windowFieldName = "window";

        // Due to the difference in field names between .NET and .NET Framework,
        // it requires conditional checking.
        var fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
        if (!fields.Any(x => x.Name == idFieldName))
        {
            idFieldName = "_id";
            windowFieldName = "_window";
        }

        var idFieldInfo = type.GetField(idFieldName, BindingFlags.NonPublic | BindingFlags.Instance);
        if (idFieldInfo == null)
            return false;

        var iconId = (uint)idFieldInfo.GetValue(notifyIcon);

        var windowFieldInfo = type.GetField(windowFieldName, BindingFlags.NonPublic | BindingFlags.Instance);
        var nativeWindow = windowFieldInfo.GetValue(notifyIcon) as NativeWindow;
        if (nativeWindow == null)
            return false;

        var iconHandle = nativeWindow.Handle;

        var nid = new NOTIFYICONIDENTIFIER();
        nid.cbSize = (uint)Marshal.SizeOf(nid);
        nid.hWnd = iconHandle;
        nid.uID = iconId;

        int result = Shell_NotifyIconGetRect(ref nid, out var rect);

        if (result != 0)
            return false;

        rectangle = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
        return true;
    }
}

// in MainForm
protected override void OnDeactivate(EventArgs e)
{
    if (Program.notifyIcon.TryGetRectangle(out Rectangle rect))
    {
        Debug.WriteLine("{0}, {1}", MousePosition, rect);

        if (rect.Contains(MousePosition))
            return;
    }

    Close();
}

字符串
这将引起另一个问题:当用户点击NotifyIcon触发MainFormDeactivate事件后,如果点击其他窗口,则不会再触发MainFormDeactivate事件。

相关问题