c#切换窗口通过点击NotifyIcon(任务栏图标)

本文关键字:NotifyIcon 任务栏 图标 窗口 | 更新日期: 2023-09-27 18:04:27

我的c#应用程序由一个任务栏图标(NotifyIcon)和一个初始隐藏的顶部窗口组成。我希望用户能够通过单击NotifyIcon来切换窗口可见性(左,单单击)。当失去焦点时,窗口也被隐藏。

这是我到目前为止,一个子类System.Windows.Forms.Form:

初始化:

this.ControlBox = false;
this.ShowIcon = false;
this.ShowInTaskbar = false;
// Instance variables: bool allowVisible;
//                     System.Windows.Forms.NotifyIcon notifyIcon;
this.allowVisible = false;
this.notifyIcon = new NotifyIcon();
this.notifyIcon.MouseUp += new MouseEventHandler(NotifyIconClicked);
this.Deactivate += new EventHandler(HideOnEvent);
实例方法:

private void NotifyIconClicked(object sender, MouseEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Left)
    {
        if (this.Visible)
            this.Hide();
        else
            this.Show();
    }
}
new public void Show()
{
    this.allowVisible = true;
    this.Visible = true;
    this.Activate();
}
new public void Hide()
{
    this.allowVisible = false;
    this.Visible = false;
}
private void HideOnEvent(object sender, EventArgs e)
{
    this.Hide();
}
protected override void SetVisibleCore(bool visible)
{
    base.SetVisibleCore(this.allowVisible ? visible : this.allowVisible);
}

点击图标显示窗口。但是,只要按下鼠标,再次点击它就会隐藏它,然后将其重置为可见。

我的猜测是,鼠标下降事件窃取焦点从窗口,所以它消失了。然后触发鼠标向上事件,显示隐藏的窗口。

我的下一个想法是读取鼠标按下事件时的窗口可见性,所以我测试了三个事件并记录了它们被调用时的UNIX时间:

notifyIcon.MouseDown
notifyIcon.MouseUp
this.LostFocus

结果很奇怪:假设窗口是可见的。当我点击图标时就会发生这种情况:焦点丢失会立即被调用。当我释放鼠标时,鼠标向下调用,就在鼠标向上事件之前。

1312372231 focus lost
1312372235 mouse down
1312372235 mouse up

为什么鼠标按下事件延迟?
我如何切换窗口?

c#切换窗口通过点击NotifyIcon(任务栏图标)

我想这可能对你有用。

我发现了一个专家交流帖子,其中包含一个类,该类提供了检查光标当前是否在托盘上的方法。

NotifyIcon - Detect MouseOut

使用这个类,我修改了你的HideOnEvent方法,像这样:

    private void HideOnEvent(object sender, EventArgs e)
    {
        if (!WinAPI.GetTrayRectangle().Contains(Cursor.Position))
        {
            this.Hide();
        }
    }

似乎可以满足你的需要。

我包含了下面的类:

using System.Runtime.InteropServices;
using System.Drawing;
public class WinAPI
{
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
        public override string ToString()
        {
            return "(" + left + ", " + top + ") --> (" + right + ", " + bottom + ")";
        }
    }
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindow(string strClassName, string strWindowName);
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    public static IntPtr GetTrayHandle()
    {
        IntPtr taskBarHandle = WinAPI.FindWindow("Shell_TrayWnd", null);
        if (!taskBarHandle.Equals(IntPtr.Zero))
        {
            return WinAPI.FindWindowEx(taskBarHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero);
        }
        return IntPtr.Zero;
    }
    public static Rectangle GetTrayRectangle()
    {
        WinAPI.RECT rect;
        WinAPI.GetWindowRect(WinAPI.GetTrayHandle(), out rect);
        return new Rectangle(new Point(rect.left, rect.top), new Size((rect.right - rect.left) + 1, (rect.bottom - rect.top) + 1));
    }
}

这不是一个完美的解决方案,但我希望这有助于。