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 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.
Related
I have a transparent controls and window where I can click through as it would not even exist. My question is: Is it possible to detect whenever click event is fired no matter where on the screen I click, while the wpf applicaton is running?
The reason why I need this is because I'm making an agent that will collect all information about actions made by user. Any suggestions, hacks, tricks will do.
You would need to create an event hook so that you could snoop all system wide messages before they are dispatched to the target window. Check the following link for more information...
In my app I am listening to Window.LocationChanged. On my machine, and some others this fires only after the window move is complete (the user releases the mouse after dragging from the title bar). On some users machine this fires continuously while the window is being dragged.
Why is there a difference, and what should the expected behavior be?
Just tested my theory that "Show window contents while dragging" (performance options) affects this. If the content is not shown the event does not fire multiple times.
I would like to remove the ability for a user to close a window in my application from the taskbar in windows 7:
The close button in the image should not be available.
Any suggestions?
You shouldn't do this. Window managing/decorating is left to the window manager, you should rather handle the "close" event in some way, and avoid the applicaiton exiting.
Also, middle clicking (mouse2) on any part of that preview will also close the window, so it's not a matter of just hiding that button.
I Have a VS2008 app that needs to display two notifyIcons in the System tray. One is the main application icon, which allows quick access to the GUI. The second is a "new message" icon, which is displayed when a new message arrives, and hidden when the user double-clicks on it, much like the new Outlook mail message icon.
The problem i am having is the second message icon is hidden whenever the mouse is moved over the system tray. The first icon behaves as expected, and remains in the system tray while the application is running.
Any ideas?
Thanks - this was partly due to windows glitch and a bug in my code.
Seems the icon will not stay visible when showing a baloon tip - it must be forced visible before showing the baloon tip. The icon did not refresh until i moved my mouse over the tray.
I know I can programatically make the taskbar item for a particular window start flashing when something changes, but is there any way I can stop it from flashing either programatically after a certain period of time or at least is there a keyboard shortcur I can give to my users to somehow stop the flashing?
The FlashWindowEx function which controls the flashing takes a FLASHWINFO struct which has a uCount field to control how many times it flashes. Also, a possible value for the dwFlags field is FLASHW_STOP to cause the flashing to stop.
EDIT: Forgot was a C# tagged question ... so P/Invoke goodness found here.
Instead of flashing the tasbar you can consider using the NotifyIcon. This will let you put something on the system tray (something else many consider evil because of the proliferation of apps that do this). Then you can popup a ballon tip with any change that actually describes the change itself.
To use:
(1) Drag the NotifyIcon onto your form or create in your app NotifyIcon notify = new NotifyIcon();
(2) Set the icon property to the required image
(3) Control whether it is visible on the system tray using the Visible property
(4) Call ShowBalloonText to show popup text (limited to 64 characters)
Either way, you shoudl add an option to the program that allows the end user to turn this feature on/off based on their feelings about it all. I personally like the notify icon because the ballon text can say something like "Server went down"
#thomas -- Amazingly Microsoft's own Windows Vista User Experience Guidelines agree with you ...
While having a background window flash its taskbar button is better than having it automatically come to the top and steal input focus, flashing taskbar buttons are still very intrusive. It is hard for users to concentrate when a taskbar button is flashing, so you should assume that users will immediately stop what they are doing to make the flashing stop. Consequently, reserve taskbar flashing only for situations where immediate attention is required.
Of course who knows who actually follows those guidelines ... or who even reads them. :)