I have a program which uses the mouse's .X position (relative to the form boundaries) to change the .Left value of a button Object.
The problem is that I have this button over the top of other objects like Picture Boxes, Buttons, TrackBar's etc. and when I hove over these other elements, the button stops tracking the mouse's .X position.
How can I make the button track the mouse movement regardless of the mouse doing other stuff on the form too? (I also need to interact with the other elements at the same time too).
My Code:
/* i create the mousemove tracking event */
this.MouseMove += new MouseEventHandler(btnBat1_MouseMove);
/* and use it by making a new method */
public void btnBat1_MouseMove(Object sender, MouseEventArgs e)
{
// I use the variable mouseXCo to change the button1.Left value.
mouseXCo = e.X;
}
Thanks in advance guys :-)
Related
I try to automate tests of a drag and drop behavior in a WPF application. One custom control is dragged on another:
Drag and drop behavior implemented in the usual WPF way:
<UserControl ...
MouseMove="ToolboxModule_OnMouseMove">
private void ToolboxModule_OnMouseMove(object sender, MouseEventArgs e)
{
base.OnMouseMove(e);
var data = new DataObject();
data.SetData("ModuleDescription", DataContext);
if (e.LeftButton == MouseButtonState.Pressed)
DragDrop.DoDragDrop(this, data, DragDropEffects.Copy);
}
<UserControl ...
Drop="WorkspaceView_OnDrop" AllowDrop="True">
private void WorkspaceView_OnDrop(object sender, DragEventArgs e)
{
var dropped = e.Data.GetData("ModuleDescription");
var viewModel = (WorkspaceViewModel)DataContext;
if (viewModel.ChainVm.AddModuleCommand.CanExecute(dropped))
viewModel.ChainVm.AddModuleCommand.Execute(dropped);
}
But when I try to automate this with WinAppDriver, the drag and drop does not work. Cursor shape is not changed and nothing happens.
I've tried several approaches:
Actions Drag and Drop
var moduleControl = mainWindow.GetToolboxModuleControl(moduleName);
var actions = new Actions(_session);
actions.DragAndDrop(moduleControl, mainWindow.WorkspaceControl).Perform();
Actions click and hold
var moduleControl = mainWindow.GetToolboxModuleControl(moduleName);
var actions = new Actions(_session);
actions.ClickAndHold(moduleControl).MoveByOffset(200, 0).Release().Perform();
Driver mouse operations (from example)
_session.Mouse.MouseMove(moduleControl.Coordinates, 50, 50);
_session.Mouse.MouseDown(null);
_session.Mouse.MouseMove(mainWindow.WorkspaceControl.Coordinates, 100, 100);
_session.Mouse.MouseUp(null);
Driver mouse operations with delays
_session.Mouse.MouseMove(moduleControl.Coordinates, 50, 50);
Thread.Sleep(1000);
_session.Mouse.MouseDown(null);
Thread.Sleep(1000);
_session.Mouse.MouseMove(mainWindow.WorkspaceControl.Coordinates, 100, 100);
Thread.Sleep(1000);
_session.Mouse.MouseUp(null);
Nothing works. Any ideas what could be wrong and how to fix it?
When I try to move the app window by dragging it's title bar via WinAppDriver, it successfully moves the window. So the dragging operations technically work, but not in the case of dragging a control within the window.
Found the answer.
WinAppDriver doesn't move the mouse, but "teleport" it. It means mouse cursor is not dragged all the way to the target with finite speed, it is being jumped from start to end position without any intermediate positions.
In this particular case it causes the problem. What actually happens:
Cursor teleported to the center of first element. MouseMove and
other mouse movement events are firing on first element.
DragDrop.DoDragDrop method is not executed, because left mouse
button is not pressed.
Left mouse button is pressed. MouseDown, Click and other related event are firing on first element. DragDrop.DoDragDrop method is
not executed, because there is no mouse movement.
Cursor jumped to second element without touching the first. MouseMove and other mouse movement events are firing on second
element only. Since no MouseMove event is firing on first element
with left mouse button pressed, the drag and drop process never
starts.
Solutions are simple: move the cursor within first element boundaries before jump to the second or change the event, where drag and drop process starts (MouseDown instead of MouseMove, for example). I chose the latter:
<UserControl ...
MouseDown="ToolboxModule_OnMouseDown">
private void ToolboxModule_OnMouseDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseDown(e);
var data = new DataObject();
data.SetData("ModuleDescription", DataContext);
DragDrop.DoDragDrop(this, data, DragDropEffects.Copy);
}
I'm making a panel with selectable items. This works perfectly at first but my panel is 45,000 pixels long and I cant select anything beyond 2^16/2(32,600 something). I'm getting the position relative to the panel, not the screen or program.
I'm currently using this code:
private void Panel_MouseClick(object sender, MouseEventArgs e)
{
Point screenPos = Panel.PointToClient(Cursor.Position);
...
}
I have also tried it as in the following code but it also doesn't work correctly, e.g. (at 30,000 pixels along the panel width it returns 58,404 and at 4,000 pixels down height it returns 7,032):
private void Panel_MouseClick(object sender, MouseEventArgs e)
{
Point screenPos = Panel.PointToClient(new Point(e.X, e.Y));
....
}
Is there a way to use cursor.Position but with a bigger range?
EDIT
strangely when doing this in a MouseMove event it can return a value higher then 2^16/2
private void Panel_MouseMove(object sender, MouseEventArgs e)
{
Point screenPos = Panel.PointToClient(Cursor.Position);
Coordinate.Text = screenPos.ToString();
...
}
this shows the correct value everywhere in my panel but even if i make screenPos a global variable and use that variable on my MouseClick event it doesnt work
EDIT2
Found that the issue is that MouseClick event doesnt work when values are that high(finding it a bit odd that it works with MouseMove tho). Now i've tried getting the latest coordinates from mousemove(which only updates when hovering the panel). Now i need to get another MouseClick Eventhandler, i tried it on the smaller pannel which holds the very big panel but this doesnt work. Also tried the handler on the entire Form but this only registers a click when im not clicking on any element so not on the panel.
Is there another solution for this?
I'm beginner in c# and need some help. After loading Form I want to display on Form coordinates of a Mouse when it's Clicked. Click can be made outside of the Form. For example in Browser. Can someone help me with this.
Maybe the most simple way is setting Capture property of a form to true, then handle click event and convert the position (that is position related to top left point of form) to screen position using PointToScreen method of form.
For example you can put a button on form and do:
private void button1_Click(object sender, EventArgs e)
{
//Key Point to handle mouse events outside the form
this.Capture = true;
}
private void MouseCaptureForm_MouseDown(object sender, MouseEventArgs e)
{
this.Activate();
MessageBox.Show(this.PointToScreen(new Point(e.X, e.Y)).ToString());
//Cursor.Position works too as RexGrammer stated in his answer
//MessageBox.Show(this.PointToScreen(Cursor.Position).ToString());
//if you want form continue getting capture, Set this.Capture = true again here
//this.Capture = true;
//but all clicks are handled by form now
//and even for closing application you should
//right click on task-bar icon and choose close.
}
But more correct (and slightly difficult) way is using global hooks.
If you really need to do it, you can take a look at this links:
Processing Global Mouse and Keyboard Hooks in C#
Low-Level Mouse Hook in C#
Application and Global Mouse and Keyboard Hooks .Net Libary in C#
I think you can't handle the mouse click outside your Form at least easily.
inside the form using MouseEventArgs it can simply be handled.
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
// e.Location.X & e.Location.Y
}
Learn more about this topic at Mouse Events in Windows Forms.
I hope it helps.
Cursor.Position and Control.MousePosition both return the position of the mouse cursor in screen coordinates.
The following articles deal with capturing Global mouse click events:
Processing Global Mouse and Keyboard Hooks in C#
Global Windows Hooks
You need a global mouse hook.
See this question
I made Event for Grid in WPF C#.
The MouseMove Event.
I want to Trigger MouseMove event When mouse Left button is Pressed and Keep the Event even when mouse is Out of Grid Or even out of the main Window.
When Button is Pressed Keep the Mousemove event for the Grid All over the screen Until Button is Releasd.
consider this is Mouse move event Method for the Grid
private void Grid_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed) // Only When Left button is Pressed.
{
// Perform operations And Keep it Until mouse Button is Released.
}
}
The Goal is to Rotate 3D model When User Hold Left button and to rotate Model while he is moving the mouse until button releases.
This is for To make the Program and Rotation Eeasier for the user. Especialy performing Long rotations cause mouse get out of the grid.
I tried to use while but it fails and you know its because of single threaded.
so the way im thinking is to somehow expand a new Grid all over the screen when button is pressed inside the original Grid and to keep it until release.
And of course Dummy Grid witch is Hidden.
What are you trying to do is to work with the stream of events. As far as I understand your flow supposed to be the following:
Left mouse button pressed
Mouse moved1 (rotate model)
Mouse moved2 (rotate model)
...
N. Left mouse up (stop rotation)
There is an interesting concept which is called Reactive Programming.
http://rxwiki.wikidot.com/101samples
There is a library for C# (Reactive-Extensions)
Your code could look like this one:
// create event streams for mouse down/up/move using reflection
var mouseDown = from evt in Observable.FromEvent<MouseButtonEventArgs>(image, "MouseDown")
select evt.EventArgs.GetPosition(this);
var mouseUp = from evt in Observable.FromEvent<MouseButtonEventArgs>(image, "MouseUp")
select evt.EventArgs.GetPosition(this);
var mouseMove = from evt in Observable.FromEvent<MouseEventArgs>(image, "MouseMove")
select evt.EventArgs.GetPosition(this);
// between mouse down and mouse up events
// keep taking pairs of mouse move events and return the change in X, Y positions
// from one mouse move event to the next as a new stream
var q = from start in mouseDown
from pos in mouseMove.StartWith(start).TakeUntil(mouseUp)
.Let(mm => mm.Zip(mm.Skip(1), (prev, cur) =>
new { X = cur.X - prev.X, Y = cur.Y - prev.Y }))
select pos;
// subscribe to the stream of position changes and modify the Canvas.Left and Canvas.Top
// property of the image to achieve drag and drop effect!
q.ObserveOnDispatcher().Subscribe(value =>
{
//rotate your model here. The new mouse coordinates
//are stored in value object
RotateModel(value.X, value.Y);
});
Actually building a stream of mouse events is a very classical example of using RX.
http://theburningmonk.com/2010/02/linq-over-events-playing-with-the-rx-framework/
You can subscribe on this stream of events in the Windows constructor, so you don't depend on the Grid, and you don't have to draw fake Grid!
Some nice links to start with:
The Rx Framework by example
Rx. Introduction
I have a program with two WPF treeviews that allow dragging and dropping between the two. The problem is, it can be annoying to open / close items on the treeviews because moving the mouse just one pixel while holding the left mouse button triggers the drag / drop functionality. Is there some way to specify how far the mouse should move before it's considered a drag / drop?
There's a system parameter for this. If you have
Point down = {where mouse down event happened}
Point current = {position in the MouseMove eventargs}
then the mouse has moved the minimum drag distance if
Math.Abs(current.X - down.X) >= SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(current.Y - down.Y) >= SystemParameters.MinimumVerticalDragDistance
Just build a little buffer into your code that determines when the drag starts.
flag mouse down
on mouse move - check for mouse down.. if yes, check to see if its moved farther than whatever buffer you specify (3 pixels is probably good)
if it has, start the drag.
Following this article for Drag and Drop implementation, you would have to handle 2 mouse events in order to delay the dragging until the mouse has moved a certain distance. First, add a handler for PreviewMouseDown which stores the initial mouse position relative to your control. Don't use the MouseDown event because it is a bubbling event and may have been handled by a child control before reaching your control.
public class DraggableControl : UserControl
{
private Point? _initialMousePosition;
public DraggableControl()
{
PreviewMouseDown += OnPreviewMouseDown;
}
private void OnPreviewMouseDown(object sender, MouseButtonEventArgs e) {
_initialMousePosition = e.GetPosition(this);
}
Additionally, handle MouseMove to check the moved distance and eventually initiate the drag operation:
...
public DraggableControl()
{
...
MouseMove += OnMouseMove;
}
...
private void OnMouseMove(object sender, MouseEventArgs e)
{
// Calculate distance between inital and updated mouse position
var movedDistance = (_initialMousePosition - e.GetPosition(this)).Length;
if (movedDistance > yourThreshold)
{
DragDrop.DoDragDrop(...);
}
}
}