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?
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 had this issue yesterday and it seems a lot of people have had similar issues in the past, so I figured I would pose my question & the solution I ended up coming up with. Microsoft has cleaner solutions to this in the 8.1 SDK, but the vast majority of WP app users are on 8.0 and below, so I imagine this will still be helpful.
When you open the virtual keyboard in a Windows Phone 7/8 Silverlight app, and the text box that caused the keyboard to open is on the lower half of the screen (that would be covered by the keyboard), it scrolls the entire page up. How can you determine how much it has scrolled, in case there was content at the top that you need displayed?
It's a little clunky, but you can get the amount the page was scrolled up by looking at the offset of the root frame.
Since this is animated into position, the question becomes "when". What I found that works is, when a text box's GotFocused event is fired, subscribe to the LayoutUpdated event, and when LayoutUpdated is fired, grab the offset from there. If you weren't already subscribed to that event, you can unsubscribe in the LostFocus event. That way as it moves, you'll get the change.
double lastOffset = 0;
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
LayoutUpdated += MyControl_LayoutUpdated;
}
private void MyControl_LayoutUpdated(object sender, EventArgs e)
{
// Grab the offset out of the root frame's RenderTransform object
PhoneApplicationFrame root = App.Current.RootVisual as PhoneApplicationFrame;
TransformGroup transform = root.RenderTransform as TransformGroup;
double offset = transform.Value.OffsetY;
if (offset != lastOffset)
{
// Do your logic here if the offset has changed
lastOffset = offset;
}
}
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
// Unsubcribe to updates and reset the offset to 0
LayoutUpdated -= MyControl_LayoutUpdated;
lastOffset = 0;
}
After you have this offset, you can alter your controls as needed. You can either shrink the height of a control by that amount, or if you have something small at the top, like a header, you can apply a TranslateTransform by the inverse of the offset to just move it downward.
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 :-)
I have a Form that contains only 2 things, a PictureBox and a Label.
I added a mouse click event handler to the picture box.
this.pictureBox1.MouseClick += picture_MouseClick;
Inside the handler I need to check if the location of the mouse click is within the bounds of the label. To do this, I am using the mouse event location and checking to see whether that location is within the bounds of the label.
private void picture_MouseClick(object sender, MouseEventArgs e)
{
if (label1.Bounds.Contains(e.Location))
{
MessageBox.Show("FOUND YOU!");
}
}
I expected this to work as it seems easy enough however the click location (the orange box in the image) that leads to the MessageBox being shown is offset down and to the right of the label.
Is this because the mouse event is relative to the PictureBox and the Label bounds are relative to the Form? Or vice versa?
By the way, the label you see in the image is hidden at runtime. I am just using the label as a "hack" way of knowing if the user clicked in a certain spot.
public Form1()
{
InitializeComponent();
this.label1.Visible = false;
this.pictureBox1.MouseClick += picture_MouseClick;
}
(I tried subtracting the width of the label from e.X and the height of the label from e.Y but that didn't seem to work.)
Thank you,
Jan
The e.Location is the mouse position (a point) relative to the upper-left corner of the picturebox.
The Bounds property is relative to the container of the control.
(And in this case, the container is the form, as you and SLacks have rightly pointed out)
To check the correct position I will try with this code (now tested)
Point p = e.Location;
p.X += pictureBox1.Left;
p.Y += pictureBox1.Top;
if(label1.Bounds.Contains(p))
.....
I've been coding a Windows app chess game in C# as an exercise in honing my skills, and also because it's fun. I have included functionality that allows a player to select the option to highlight the squares a piece can legally move to when it gets clicked. A CustomControl handles the rendering of the chessboard and it also highlights the squares.
It all works as planned until the player begins to drag the piece to a new square. The moment the mouse moves, the highlights go away. I suspect that a Paint event is raised and the board redraws itself. And since the highlights are not part of the initial board layout, they don't get drawn.
What I would like to happen is for the squares to remain highlighted until the piece is dropped on its destination square. Is it possible to accomplish this? Any suggestions will be appreciated.
Psuedo code:
void piece_MouseDown(object sender, MouseEventArgs e)
{
Piece piece = (Piece)sender;
legalSquares = CalculateLegalSquares(piece.CurrentSquare);
if (legalSquares.Count > 0 && this.showLegalMoves)
{
chessBoard1.HighlightSquares(legalSquares);
}
// I believe a Paint event gets raised either here...
piece.DoDragDrop(piece, DragDropEffects.Move);
}
void piece_DragEnter(object sender, DragEventArgs e)
{
// ...or here, that removes the highlights.
if (e.Data.GetDataPresent("Chess.Piece"))
{
e.Effect = DragDropEffects.Move;
}
else
{
e.Effect = DragDropEffects.None;
}
}
void piece_DragDrop(object sender, DragEventArgs e)
{
Piece piece = (Piece)e.Data.GetData("Chess.Piece");
if (piece.CurrentSquare != dropSquare)
{
if (legalSquares.Contains(dropSquare))
{
// This is where I’d like the highlights to stop
// DoStuff()
}
}
}
It sounds like you are highlighting the valid squares by drawing directly, but this will get erased on any repaint. You will probably lose the highlights if your window is repainted for other reasons also, such as minimizing and restoring it, or dragging another window on top of it.
If this is the case, you probably need to override the OnPaint method and do your highlighting there. When you want to change what is highlighted, set some state in your class to control what is drawn as highlighted in the OnPaint method, and then Invalidate your window.