WPF Forcing MouseDevice to be pressed - c#

I have a windows form in a wpf window, and I'm trying to use DragMove when I click on the windows form, it's a picturebox so I want to be able to drag the window around just by clicking the picture.
I catch my form's mouse down, and raise the wpf window's mouseleftbuttondown event with:
if (e.Button == MouseButtons.Left)
{
MouseDevice mouseDev = InputManager.Current.PrimaryMouseDevice;
MouseButtonEventArgs mouseEvent = new MouseButtonEventArgs(mouseDev, 0, MouseButton.Left)
{
RoutedEvent = MouseLeftButtonDownEvent
};
RaiseEvent(mouseEvent);
}
However whenever I check the InputManager.Current.PrimaryMouseDevice from my handler (or my form's MouseMove handler), the LeftButton's state is "released".
Why is this? I can't figure out a way to force it to be "pressed" since all the properties are read-only.
Or is my approach simply wrong and is not possible? I did also try setting the location of my window on mouse move, but some weird stuff happens where my mouse values keep going back to the previous position.
Thanks!
edit: So I'm manually adjusting the window location, but still hope someone can enlighten me as to why MouseDevice doesn't get pressed on a windows form. The "weird stuff happens..." was just a dumb mistake on my part, I kept resetting the mouse coordinates on mouse move, but realized that my mouse never moves relative to the window since the window is moving too, duh!

A similar issue stumped me for a while: the ButtonState property of MouseButtonEventArgs reflects the real-time state of that button, not a state snapshot taken when the event was raised. I wonder if the same holds true re your accessing LeftButton's state.
Hope this helps,
Ben

Related

Run code after the user has finished moving the window?

I've made a WPF application and one of my windows is required to go fullscreen, however I'm trying to get it so that if the user drags the window to another monitor it will automatically resize to suit that monitor.
I've tried the previewmouse up down events, mouse up down events to set a bool that the window is being dragged to prevent the code from executing, however this does not appear to work and the window is still trying to resize itself as its being dragged and the mouse is down (as if mousedown is being set to false)
The code that resizes the window is in the window located changed event
Is there any other ways that can effectively detect that the mouse is down and dragging the window to another monitor before executing the code to resize it to suit?
Whilst the user is dragging the window I dont want the code to resize it to be executed, once the user has finished dragging the window, the code to resize the window to the new screen should be executed.
Currently I cant get the code to run after the window has finished moving.
Upon further investigation, no mouse up events are fired after the mouse is released on the title border.
You can override OnPreviewMouseMove for any UI element.
protected override void OnPreviewMouseMove(MouseEventArgs e)
Then using the event args of that handler (of type MouseEventArgs) - you check if the left mouse button is pressed (indicating a drag).
e.LeftButton == MouseButtonState.Pressed
When you start dragging a maximized Window, the size changes. This is how Windows behaves and is natural to a user. On end of drag you can just set the state back to maximized.
Application.Current.MainWindow.WindowState = WindowState.Maximized;
Did you checked this event ? Sounds like what you need.
https://msdn.microsoft.com/en-us/library/system.windows.window.locationchanged%28v=vs.110%29.aspx

Window.DragMove() causes the window to freeze temporarily if holding down the mouse left button without moving the cursor

I have a "borderless" window in WPF. It can be dragged from any part of the window that does not handle the Click event, using this code:
// Drag the window:
private void GlassWindow_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton != MouseButton.Left) return;
if (AllowDrag) DragMove();
}
(Note: AllowDrag is always set to true in this case)
This code works fine, except that when I click on the window and hold down the left mouse button, without moving the cursor (= not dragging the window), the window freezes for about 2-3 seconds (i.e. all animations pause, progressbar stops moving). This behaviour is consistent, and does not happen when I click on a button or when I drag the window, only when I hold left click.
Is there any solution for this or is this intended windows behavior?
EDIT: Things that don't solve the problem:
https://stackoverflow.com/a/3275712/2719183
https://stackoverflow.com/a/5494769/2719183
http://www.codeproject.com/Articles/11114
if (AllowDrag) DragMove();
DragMove() is the trouble-maker, it is uses a pretty hacky way to implement the move. And that causes the problem you describe, the WPF team is well-aware of the issue but chose to not fix it. You can read about it in this connect article. Vote if you are not pleased.
So you need to avoid DragMove(). The best way is to do it the way it is normally done, you minimize the risk of reproducing the exact same trouble that way. That requires knowing a little about the way the winapi works. Whenever a window is clicked, Windows sends the WM_NCHITTEST message to ask your app what part of the window was clicked. When you return HTCAPTION, even if you don't have a caption, then Windows takes your word for it and implements what normally happens when you click and drag a window by its caption.
That has been done, you don't have to be an expert in the winapi to get that going. Google "wpf wm_nchittest" to find code. The top hit is an existing SO question, Tergiver's code looks good.

How can I move the TrackBar in response to mouse events in C#?

This is probably a n00b query. I have a need where I want to change the trackbar value based on a mouse down event. This I achieved as follows:
private void MoveTrackBarToMouseClickLocation(TrackBar a_tBar, int a_mouseX)
{
// Jump to the clicked location
double dblValue;
dblValue = ((double)a_mouseX / (double)a_tBar.Width) * (a_tBar.Maximum - a_tBar.Minimum);
a_tBar.Value = Convert.ToInt32(dblValue);
}
That part works fine. I am having trouble getting the scroll working while the mouse button is pressed. e.g. If I click on the trackbar and it takes me to say value 50 with the mouse down, I want to be able to scroll right or left (from value=50) while that mouse is down.
I hope I have made my small issue clear.
Any help is appreciated.
Thanks
You need to execute your code in the MouseMove event, as well as the MouseDown event.
This event occurs when the mouse is moved while one of the buttons is held down. In contrast, the MouseDown event that you currently handle only gets raised once each time the mouse button is pressed down. That's why the TrackBar is not moving when the user moves the mouse, but is working properly the first time the button is pressed.
You didn't show the code where you wired up the event handlers and/or call the MoveTrackBarToMouseClickLocation function, so that's as specific as I can get. But if you managed to wire up the MouseDown event already, this should be a simple fix.

Issue with mouse move event

I have a WPF control1 (has a moving control) that is hosted through elementhost on a windows form. My aim is to capture the mouse move events for the elementhost.
I found out from the following link that MouseMove fires when Control moves under mouse while mouse stands still.
http://social.msdn.microsoft.com/Forums/en/wpf/thread/56e7b331-ac6f-4d62-a83b-c09009b79fa0
I am getting fake mouse move events for elementhost. In order to fix this issue, I added a button on top of elementhost and set its Visible property to Hidden. Still I get fake mouse move events.. How to fix this issue? Is there any workaround?
Appreciate your help...
In your mousemove event, log down the values of e.X and e.Y, keeping your mouse stationary. If they're the same, the problem is solved.
I just noticed this issue in a WPF app without ElementHost - mousemove fires continually for a stationary mouse!! I'm now putting an intermediary class between the publisher and subscriber to filter the events if a duplicate X & Y point comes through (plus decouple subscribers from MouseEventArgs so I can unit test subscribers)

How can I detect a held down mouse button over a PictureBox?

I need to fire an event when the mouse is above a PictureBox with the mouse button already clicked and held down.
Problems:
The MouseDown and MouseEnter event handlers do not work together very well.
For instance once a mouse button is clicked and held down, C# will fire the MouseDown event handler, but when the cursor moves over the PictureBox the MouseEnter event does not fire, until the mouse button is realeased.
When the mouse is pressed down most controls will then Control.Capture the mouse input. This means that all MouseMove events are sent to the original control that captured rather than the control the mouse happens to be over. This continues until the mouse loses capture which typically happens on the mouse up.
If you really need to know when the mouse is over your control even when another control has captured mouse input then you only really have one way. You need to snoop the windows messages destined for other controls inside your application. To do that you need add a message filter ...
Application.AddMessageFilter(myFilterClassInstance);
Then you need to implement the IMessageFilter on a suitable class...
public class MyFilterClass : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEMOVE)
// Check if mouse is over my picture box!
return false;
}
}
Then you watch for mouse move events and check if they are over your picture box and do whatever it is you want to do.
Mouse events
Use the MouseDown event to just detect a down press of a mouse button and set this.Capture to true so that you then get other mouse events, even when the mouse leaves the control (i.e. you won't get a MouseLeave event because you captured the mouse). Release capture by setting this.Capture to false when MouseUp occurs.
Just checking the state of the mouse
This may not be relevant, but you can check System.Windows.Control.MousePosition and see if it is in the PictureBox.ClientRectangle, then check the Control.MouseButtons static property for which buttons might be down at any time.
As in:
if (pictureBox.ClientRectangle.Contains(pictureBox.PointToClient(Control.MousePosition)))
{
if ((Control.MouseButtons & MouseButtons.Left) != 0)
{
// Left button is down.
}
}
Set up a MouseMove event within the PictureBox control:
this.myPictureBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.myPictureBox_MouseMove);
Then, within your MouseMove event handler, check to see if the left mouse button (or whatever) is pressed:
private void myPictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
// Do what you want to do
}
If you're trying to implement a drag-and-drop operation of some sort, the Drag... events (DragEnter, DragDrop etc.) on the receiving picture box are what you want to use. Basically, you start the drag operation using the DoDragDrop method of the source control, and then any control that you drag over will have its Drag... events raised.
Search "DoDragDrop" on MSDN to see how to implement this.
You can use the Preview Events
For example say I want to detect a mousedown event on my button. The MouseDown event is not going to work because as one of the answers here, the mouse capture is sent to the main control, however what you can do is use the mouse preview event.
Here is a code example
I want to check when the Left Mouse Button is pressed on my Button, hence I use the PreviewMouseLeftButtonDown
private void MyButton_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// code here
}
WPF has preview events for alot of other events, you can read about them here
Preview Events - It particular talks about Buttons and how the mouse events interacts with it, So I highly recommend you read it
The best way to move a Form based on mouse position and control relative position is similar to what Ian Campbell posted.
private void imgMoveWindow_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Form1.ActiveForm.Left = Control.MousePosition.X - imgMoveWindow.Left - (imgMoveWindow.Size.Width/2);
Form1.ActiveForm.Top = Control.MousePosition.Y - imgMoveWindow.Top - (imgMoveWindow.Size.Height/2);
}
}
Where imgMoveWindow is a PictureBox Control.
Bruno Ratnieks
Sniffer Networks
You should try MouseMove of the picture box instead of MouseEnter, MouseMove will normally fire regardless mouse button state.
set a flag or a state on mouse down. release it on mouse up.
When on mouse over fires for the picture box check your state.
Now you can detect when a person is dragging something.

Categories