I have the following event handler for a NotifyIcon within a WPF application using Forms integration:
void MyNotifyIcon_MouseDown(Object sender, System.Windows.Forms.MouseEventArgs e)
{
ShowSettingsWindow();
}
However, e.Location = {X=0,Y=0} always. Is there a way to make this work?
Update
Oddly enough, people have voted to close this question and have downvoted it. However, its clearly not working and simple enough to create a new NotifyIcon inside of a WPF application's App.xaml.cs file and try it out for yourselves.
Update
As Hans pointed out, this is by design. It still doesn't answer the question of what possible workarounds are. Furthermore, this is a bad design, because:
This event occurs on a MouseDown, which means it should have some context of the mouse position when it was clicked in order for it to have occurred. The WmMouseDown handler for NotifyIcon does have the ref Message m property which other controls use to establish the correct position, however it seems to disregard this property and not use it in the event handler. I'd call this a major bug.
Since its post-mortem, getting the Cursor.Position inside of MouseDown will not give you the exact last location in which the MouseDown was raised after the tray icon is clicked. There is a small delay between you clicking it, and it raising the event in which you can further move the mouse. You can test this out yourself with an application that gets the mouse coordinates by quickly moving the mouse after clicking the tray and getting its location within the MouseDown handler. A workaround (which answers my question) would be to save the last location on every MouseMove using Cursor.Position instead and using this last location on MouseDown as the location that clicked the icon. All of which spells out a clear need for the mouse location of when the event actually occurred.
Apparently, I am the only one who cares about these inconsistencies in .NET while a lot of people seem to tolerate them or not understand their implications properly.
Its not ideal because the framework is designed to not send proper mouse event arguments as Hans pointed out, but one workaround is to save the last location on every MouseMove using Cursor.Position and using this last location on MouseDown as the location that contextually clicked the icon.
Have you considered setting a global mouse hook? It would bypass the typical WPF event model, and you would have to manually determine coordinates. This may involve additional API calls.
Details can be found in this post Global mouse event handler
Related
On System.Windows.UIElement there is a CaptureMouse() and a paired ReleaseMouseCapture() method. In this WPF DragDrop sample they call CaptureMouse on MouseDown and release it on MouseUp. The documentation in MSDN is about as useless as it comes - "CaptureMouse -> Captures the mouse."
In my head before trying it I assumed that it somehow locked the mouse inside the UIElement bounds, but that's clearly not the case when I try it. From experimenting, it seems to have something to do with responding to events when the mouse is outside of the UIElement, but not wanting to be a cargo cult programmer I don't want to just use it because the example does, I'd like an authoritative description of what it means.
From Capture and Uncapture the Mouse on MSDN:
When an object captures the mouse, all mouse related events are treated as if the object with mouse capture perform the event, even if the mouse pointer is over another object.
Only the capturing control receives the mouse events until released.
Capturing the mouse is useful for dragging because all the dragging code can exist in the one control, rather than being spread over multiple controls.
When it has captured the mouse, a control will receive mouse events even if the mouse pointer is no longer within its bounding area.
Typically, it's used for:
Drag and drop
Buttons (to handle Mouse Up when you put the mouse down on the button and move the mouse before you release the button)
The Silverlight 2 documentation for it has a more verbose description, I don't know why it isn't a part of the 3.5 documentation page too:
When an object has captured the mouse, that object receives mouse input whether or not the mouse pointer is within its bounding area. The mouse is typically only captured during simulated drag operations.
...
It works the same with WPF, and so the reason it is used with DragDrop, is that is how the
it knows to report back to the control being dragged from when the mouse may be outside of that control. If you comment out the MyCanvas.Capture() and the Capture(Null) (which clears it) then you can no longer drop.
I'm trying to write to a status bar the current mouse position and in order to that I took over OnMouseMove() event handler which is triggered when the mouse cursor enters my control. The problem is that in my control I have a WPF control which is has Dock.Fill Dockstyle, meaning, it fills the entire parent control.
When I run the applicaiton I see that nothing happens and the mouse position isn't updated, so I've noticed that the OnMouseMove() event of the WPF control is triggered and not the OnMouseMove() event of my control, which contains the relevant code for updating the mouse location coordinates.
I wanted to know if there's a way (other than implementing the code in the WPF OnMouseMove() event handler, of course) to bypass the WPF control event handler and use always my control's event handler.
I hope I was clear enough in my question, if not please let me know and I'll try to elaborate.
Thanks!
try the PreviewMouseMove-Version of OnMouseMove - this one should fire correct
and you need to have some kind of background (not null) or your controll won't see the mouse - so give it a transparent color or something)
Hallo,
I am trying to keep track of the mouse position and also its delta position. Is there any nicer way of doing this then implementing all the mouse events for all my forms in my window?
The problem with using the MouseMove event is that as soon as the mouse moves outside of the form it stops working properly. Implementing the mouseEnter, mouseLeave improves it somewhat, but it does still not feel perfect. Any ideas?
Regards,
You have to handle lower level windows events.
Check out this example: http://www.codeproject.com/KB/cs/globalhook.aspx
My UserControl is a kind of a container that has a set of controls inside. One of the UI behaviours I designed is that the move over nested control makes it selected for some keyboard triggered actions.
The other way of setting up the nested control that is targeted to receive keyboard input is with arrow keys that change focus to certain control within my UserControl.
The problem is that in most cases my UserControl has scrollbars and switching between its elements with arrow keys causes contents to move. Because of that movement it seems that mousemove event is launched also when the mouse arrow stands still, but its over my usercontrol. In the end, the wrong nested control is being selected.
I tried to set a boolean flag to temporary lock the actions of mousemove event while the arrow keys handling function is launched, but it seems to not to work at all.
Does anybody have an idea how to prevent that unwanted triggering of mousemove event and avoid the problems it causes?
I did some debugging/experiments and it appears that though mouse stays still over controll the MouseMove is actually called frequently and not only when control move is caused by some UI behaviour (scrolling of parent controll called using keyboard).
It also seems like it is called twice every single second (but probably only when application is launched form VS during debug session?), the calls are separated by few hundred parts of seconds and for now i couldnt determine what causes those.
Solution (maybe not only, and not the best) is to store last position of cursor and compare it inside event to check if mouse was really moved from last MouseMove call. I achieved it using System.Windows.Forms.Cursor.Position because position from MouseEventArgs will be diffrent depending on circumstances but still will be inconclusive to determine if mouse cursor was moved.
Point lastCursorPosition = new Point();
private void panelPictures_MouseMove(object sender, MouseEventArgs e)
{
if (System.Windows.Forms.Cursor.Position != lastCursorPosition)
{
Console.WriteLine("mouse moved");
lastCursorPosition = System.Windows.Forms.Cursor.Position;
}
else
{
Console.WriteLine("mouse in place");
}
}
Is there a way to get mouse position without attaching a event handler?
I'm trying to get a box to appear where the mouse is.
Thanks
Sp
Wouldn't you rather want it on a mouse-up or mouse-down event? Here are a few drag-and-drop tutorials that might help with ideas for capturing mouse positions:
http://msdn.microsoft.com/en-us/library/cc189066%28vs.95%29.aspx
(SL 1, but still good) http://blogs.msdn.com/b/nickkramer/archive/2007/06/27/drag-drop-with-feedback.aspx
Unfortunately, I think you'll have no other way than using the MouseMove event. You can attach it to the Application.Current.RootVisual (or any other layout root) though, so you should be able to implement your scenario.