3

我正在 WPF 中实现一个 Windows 7/Vista 风格的通知区域(“系统托盘”)弹出应用程序。到目前为止,我已经在这里写过我的工作(确定通知图标的位置、禁用调整大小等)。

但是,有一个问题我还没有完全解决:当第二次单击通知图标时隐藏窗口。如果您单击(例如)Vista/7 中的音量图标以显示音量控制,请注意在第二次单击该图标时它会再次隐藏。

我处理了窗口的 Deactivated 事件来隐藏窗口,当点击通知图标时,窗口确实被停用了。但是,单击通知图标当然会显示并激活窗口,因此最终发生的情况是,当鼠标按下时窗口消失,而在释放鼠标时重新出现(完成鼠标单击事件)。

我的第一个想法是我可能会使用通知图标的 MouseDown 事件(我使用的是 System.Windows.Forms.NotifyIcon)并检查当时窗口是否可见 - 如果是,我可以将其解释为用户单击通知图标第二次隐藏窗口。不幸的是,MouseDown 事件似乎在鼠标真正被点击之前不会触发(换句话说,它的工作原理与 MouseClick 事件相同),此时窗口已经被停用并因此被隐藏。这似乎排除了这个解决方案。

我的下一个想法(以及我最终使用的方法)是在窗口被停用时获取光标位置(GetCursorPos)并检查该点是否在通知图标的范围内。同时,我还使用GetForegroundWindow来查找当前活动窗口——如果确实要点击通知图标,它应该是任务栏(类名为Shell_TrayWnd的顶层窗口)或通知区域飞出(类名为 NotifyIconOverflowWindow 的顶级窗口;仅限 Windows 7+)。简而言之,如果光标在通知图标上并且通知区域处于活动状态,我假设用户鼠标按下通知图标以隐藏窗口。如果这些条件为真,那么下面的 MouseClick 事件将不会导致窗口被显示/激活。

但是,此解决方案至少存在一个问题:如果光标悬停在通知图标上并且用户按下 Windows 键打开开始菜单(或使用 Windows 键 + 数字快捷键打开应用程序),我的程序将错误将其解释为通知图标的鼠标按下(因为这些键盘快捷键使任务栏处于活动状态)。这意味着下次用户实际单击通知图标时,将不会显示该窗口。(再次单击通知图标将显示它。)

我希望我写的东西有点道理;如果没有,我很乐意尝试进一步澄清情况。

我很想知道是否有人对如何解决这个问题有任何其他想法。

我怀疑这可能是不可能的:在我看来,本机 Windows 7 通知区域弹出应用程序本身使用简单的计时器实现。在音量控制打开时单击(例如)音量图标只会在窗口停用和鼠标单击之间的时间小于约 2 秒时关闭音量控制。将鼠标按住图标较长时间然后松开将再次显示音量控制,即使它在鼠标按下之前已打开。

4

1 回答 1

1

这不是音量控制窗口的工作方式。当您单击任意位置时,它会消失,包括通知图标。该图标不相关。这是一个标准的 Win32 技巧,它捕获鼠标,以便它可以看到其窗口外的点击。

WPF 中的 Mouse.Capture。几乎没有那么容易做到,因为它需要一个 IInputElement 而不是窗口句柄。

于 2011-01-03T14:56:12.400 回答