开发者

Alternate showing/hiding window when notify icon is clicked

I'm implementing a Windows 7/Vista-style notification area ('system tray') pop-up application in WPF. I've written about my work so far here (determining the notify icon's position, disabling resize, etc.).

There is one problem that I haven't solved quite to my satisfaction, however: hiding the window when the notify icon is clicked a second time. If you click (for example) the volume icon in Vista/7 to show the volume control, notice that it is hidden again when the icon is clicked a second time.

I handle the window's Deactivated event to hide the window, and the window is indeed deactivated when开发者_如何学Python the notify icon is clicked. However, clicking the notify icon of course shows and activates the window, so what ends up happening is that the window disappears while the mouse is down and re-appears when the mouse is released (completing the mouse click event).

My first thought was that I might use the notify icon's MouseDown event (I'm using a System.Windows.Forms.NotifyIcon) and check whether the window is visible at that time - if it were, I could interpret it as the user clicking the notify icon a second time to hide the window. Unfortunately, the MouseDown event seems not to fire until the mouse has actually been clicked (in other words it works identically to the MouseClick event), by which time the window has already been deactivated and thus hidden. This seems to rule out this solution.

My next idea (and the approach I've ended up using) was to get the cursor position when the window is deactivated (GetCursorPos) and checking whether that point is within the notify icon's bounds. At the same time, I also use GetForegroundWindow to find the currently active window - if the notify icon is indeed to be clicked, it should either be the taskbar (the top-level window with class name Shell_TrayWnd) or the notification area fly-out (top-level window with class name NotifyIconOverflowWindow; Windows 7+ only). In short, if the cursor is over the notify icon and the notification area is active, I assume that the user mouse-downed the notify icon to hide the window. If these conditions are true, then the following MouseClick event will not result in the window being shown/activated.

This solution has at least one problem, though: if the cursor is hovering over the notify icon and the user presses the Windows key to open the start menu (or uses a Windows key + number shortcut to open an application), my program will wrongly interpret that as a mouse-down to the notify icon (because the taskbar is made active by those keyboard shortcuts). This means that the next time the user actually does click the notify icon, the window will not be shown. (Clicking the notify icon once more will show it.)

I hope what I've written makes some sense; if not, I'm happy to try and clarify the situation further.

I'm interested to hear if anyone has any other ideas about how to solve this.

I suspect that it might not be possible: it seems to me that the native Windows 7 notification area pop-up applications themselves use a simple timer implementation. Clicking on (for example) the volume icon when the volume control is open will only close the volume control if the time between the window deactivation and mouse click is less than about 2 seconds. Holding the mouse down on the icon for a longer period of time and then releasing will show the volume control again, even if it was open before the mouse-down.


That's not how the volume control window works. It disappears when you click anywhere, including the notification icon. The icon isn't relevant. This is a standard Win32 trick, it captures the mouse so it can see clicks outside of its window.

Mouse.Capture in WPF. Not nearly as easy to do because it requires an IInputElement instead of a window handle.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜