For the record: I'm new to Silverlight and XAML.
I'm trying to simply display the mouse coordinates relative in my canvas (or any other element).
After reading a lot on the subject, unfortunantly I havn't figured this our yet.
My Silverlight 5 project uses MVVM with Caliburn micro.
How can this be done?
Would Appreciate help on implementing this.
Thanks,
Guy.
You need to be a little more specific with what control you're trying to get this with, but have you tried wiring something up to the MouseMove event? Like MouseMove="Handle_MouseMove"
public void Handle_MouseMove(object sender, MouseEventArgs args)
{
mouseVerticalPosition = args.GetPosition(null).Y;
mouseHorizontalPosition = args.GetPosition(null).X;
}
Is that what you're looking for?
If you want this to happen on the entire canvas, you can instead wire it up to PointerMoved
See MouseEventArgs. This can get you the X and Y position and it can be used with the MouseUp, MouseDown, and MouseMove events.
To complete tnw Answer : You have to start mouse capture on object : MyElement.CaptureMouse()
In the handler method, you can use GetPosition on MouseEventArgs with an UIElement in parameter for relative coordinates...
public void Handle_MouseMove(object e, MouseEventArgs f)
{
var point = f.GetPosition(MyElement);
}
you have to catch the mouse click event and there are some event handlers you can use it to capture the position.
private void CadLayoutRoot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
double point1 = e.GetPosition(bitmapCadView.UIElement).X;
double point2 = e.GetPosition(bitmapCadView.UIElement).Y;
}
Related
I think that must be only a little problem, but I can't get a clear thought on that. Someone an idea?
I have some borders on a canvas (filled with images) and i want to click the border (i do this with the OnMouseLeftButtonDown) where the border gets red (so the user knows for sure which object he had clicked) and then, after 1 or 2 seconds, when the mousebutton is still pushed down, a drag'n'drop should start.
At first I had the borders inside buttons, but the clickevent seems to conflict with the dragevent. So I got rid of the buttons and did everything inside the borders directly, which works well also. But how can I start the drag after the mousebuttondown and stop it when the mousebuttonup happens before the time runs out.
Someone an idea for a clean solution?
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_source = sender as Border;
Mouse.Capture(_source);
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_source = null;
Mouse.Capture(null);
}
and in event OnMouseMove you can modify border margins depends on mouse position but after checking if _source is type of Border.
var position = e.GetPosition(Canvas);
EDIT:
For that time you can add property Stopwatch _watch, and inside OnMouseLeftButtonDown event handler you can do it:
_watch = Stopwatch.StartNew();
in OnMouseLeftButtonUp:
_watch.Stop();
and in OnMouseMove before your code:
while (_watch.ElapsedMilliseconds < 2000 && _watch.IsRunning)
{
Thread.Sleep(100);
}
I registered Hotkey: Ctrl + Space. Hotkey message is sent to:
private void Hotkey_press()
{
... // I want to show tooltip "Hello" at current mouse location.
}
Is there any way to show this tooltip even the mouse doesnt point to any control and it is outside my Window.Form1?
Edit: That ToolTip can show even the form lost focus or hide
You want something like
ToolTip tt = new ToolTip();
IWin32Window win = this;
tt.Show("String", win, mousePosition);
Where the MousePosition can be obtained from the MouseEventArgs via
private SomeMouseEventHandler(object sender, MouseEventArgs e)
{
System.Drawing.Point mousePosition = e.Location;
...
}
or using
System.Drawing.Point mousePosition = Cursor.Position;
also, you may want to set a longer duration for which the ToolTip is displayed, well just use the overloads available for the Show method, tt.Show("String", win, mousePosition, 5000); will display the tool tip for 5 seconds.
I hope this helps.
Tooltip tip = new ToolTip();
tip.ShowAlways = true;
tip.Show("My tooltip",this,Cursor.Position.X,Cursor.Position.Y);
http://msdn.microsoft.com/en-us/library/system.windows.forms.tooltip.aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.tooltip.showalways.aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.cursor.aspx
As this answer suggests, there is no managed way to accomplish this. If you want to show a tool tip control when your program is not in focus then the "right" way to do it is to PInvoke Win32 and use CreateWindowEx. The answer linked above given by gideon shows some pointers on how to do it, but nonetheless it is very complicated.
If you don't mind using thrid party libraries, AutoIt provides a way to create tool tips easily without having to deal with Win32 yourself.
Here is a very simple example demonstrating use:
//make sure AutoItX3.dll is referenced in your project
using AutoItX3Lib;
private AutoItX3 myAutoIt = new AutoItX3();
private async void ShowToolTipAtMouse(string message)
{
//default position is bottom right of mouse pointer,
//but you can set the x and y positions yourself
myAutoIt.ToolTip(message);
//call the function again with an empty argument to close
await Task.Delay(1000);
myAutoIt.ToolTip(String.Empty);
}
This will work as long as your program is running; doesn't matter if it is in/out of focus or even hidden. Downside is you don't get the regular fade out animation (it just vanishes). Also, if you need multiple tool tips at once you need to have multiple AutoItX3 objects.
You need Show/Hide it in the mouse events, also converting mouse location from Screen coordinate to your control coordinate. the little problem is if you put tooltip exactly on mous pointer location toolTip will catch mouseEnter event and unintended mouseLeave event on your control will be triggered so my solution was adding a little offset to final location.
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
Point p = pictureBox3.PointToClient(Cursor.Position);
p.X += 5;
p.Y += 5;
toolTip1.Show("My tooltip" ,
pictureBox1, p);
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
toolTip1.ShowAlways = false;
Text = ("Leave");
}
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
toolTip1.ShowAlways = true;
Text=("Enter");
}
It is a shame Winforms does not have a position property for tooltips.
The easiest thing I found is to add your own mouse-over and mouse-leave handlers and then use the Show() function to set the location (x and y), in pixels, relative to the upper left corner of the second argument of the Show() function.
The second argument can be any control, but probably makes most sense to use the control containing the tooltip itself (this), the parent the control, or a child control inside the control.
You can use a Point instead of two arguments (x and y) for the position, but remember Show() will take the point's x coordinate and y coordinate and add them to the x and y coordinates of the upper left corner of the control you chose as the second argument.
private void UserControl1_MouseHover(object sender, EventArgs e)
{
toolTip1.Show("this text is so new", this, 10, 10);
}
private void UserControl1_MouseLeave(object sender, EventArgs e)
{
toolTip1.Hide(this);
}
I've been trying to get my head around creating a custom event to handle mouse controls and such, but i keep running into certain errors that none of the tutorials seem to address. I'm pretty sure my logic of creation / assigning is correct, but maybe theres something fundamentally wrong that I'm missing here.
First off i create my delegate with the same signature as the method;
public delegate void MouseDown(object sender, MouseEventArgs e, Control control);
And then i assign it my event;
public event MouseDown OnMouseDown;
and then finally i try and subscribe to the event;
public static void Init(Control control, Control container, Direction direction)
{
control.MouseDown += OnMouseDown;
}
//ignore the parameters I'm passing, these are out of the scope of my problem.
However on this section I'm getting the error "an ohject reference is required for the non-static field, method, or propery "blah blah.OnMouseDown""
Finally heres my method I'm trying to subscribe to on mouseDown;
public void MouseDownEvent(object sender, MouseEventArgs e, Control control)
{
Dragging = true;
DragStart = new Point(e.X, e.Y);
control.Capture = true;
}
It probably doesn't help that I'm trying to modify a helper class i found somewhere. If any further information is needed feel free to ask.
Note: The prime objective of this class is to allow controls to be moved at runtime.
Edit:
I believe the first two have worked, but to move i need to use the following method;
public void MouseMoveEvent(object sender, MouseEventArgs e, Control control, Control container, Direction direction)
{
if (Dragging)
{
if (direction != Direction.Vertical)
container.Left = Math.Max(0, e.X + container.Left - DragStart.X);
if (direction != Direction.Horizontal)
container.Top = Math.Max(0, e.Y + container.Top - DragStart.Y);
}
}
so i need to send Direction direction, which i can't send as sender. The reason I'm making these changes to the whole system is, i had it working before using anonymous delegates, but these proved tough to unsubscribe from when i wanted to re-lock a control in place.
Edit 2:
scratch that, the mouseDown and mouseUp won't work if i don't pass the correct control, at least subscribing the way i was doing it before. i could try your method but, the way i was doing it i was just calling one method which subscribed to all 3 MouseControls. it looks like either i can subscribe in sepearate methods as suggest, or i need to pass the right control correctly, i.e. not sender as control. any ideas?
Currently I'm subscribing by running this method from anywhere;
helper.Init(this.Controls["btn" + i]);
and then it runs through these methods before subscribing the button to my mouseup, down and move.
public static void Init(Control control)
{
Init(control, Direction.Any);
}
public static void Init(Control control, Direction direction)
{
Init(control, control, direction);
}
public static void Init(Control control, Control container, Direction direction)
{
control.MouseDown += new MouseEventHandler(FireOnMouseDown);
control.MouseUp += new MouseEventHandler(FireOnMouseUp);
control.MouseMove += delegate(object sender, MouseEventArgs e)
{
if (Dragging)
{
if (direction != Direction.Vertical)
container.Left = Math.Max(0, e.X + container.Left - DragStart.X);
if (direction != Direction.Horizontal)
container.Top = Math.Max(0, e.Y + container.Top - DragStart.Y);
}
};
}
Note: the third subscription is how they were before (anon delegates). I believe i need to pass the correct control in the events though. Does this give more clarity to my problem?
Answer to this question:
However on this section i'm getting the error "an ohject reference is
required for the non-static field, method, or propery "blah
blah.OnMouseDown""
Init method is static which means that any non local variable used inside it must be static. In your code, the public event MouseDown OnMouseDown; must be static.
Just do this and it will work fine (without the need for a delegate):
EDIT
Please see code below to see how to get the control that has been clicked.
public static void Init(Control control, Control container, Direction direction)
{
control.MouseDown += new System.Windows.Forms.MouseEventHandler(On_MouseDown);;
}
private static void On_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
Control control = sender as Control;
if(control != null){
// Here we go, use the control to do whatever you want with it
}
}
You should write:
control.MouseDown += new MouseEventHandler(MouseDownEvent);
Be careful here that you must change the signature of MouseDownEvent, here, since the MouseDown event of Control needs only the sender and the MouseEventArgs as parameters.
But I'm not sure if this is what you really want. The effect of this instruction is that when the mouse goes down on the control MouseDownEvent is executed. Is this what you want?
The instruction public event MouseDown OnMouseDown; is unesuful unless somewhere in the same class where this appears you do not write something that fires this event in this way:
if (OnMouseDown!= null)
OnMouseDown(aSenderObject, aMouseEventArgs, aControl);
And to subscribe to thgis event you should write this (here hc anObj is an instance of the class where the event is defined):
anObj.OnMouseDown+= new MouseDown(MouseDownEvent);
Hope it helps. Maybe a little more context could be useful.
EDIT:
If you are trying to implement a class that manages the movement of controls you could have the Helper class that contains:
public delegate void MouseDown(object sender, MouseEventArgs e, Control control);
public static event MouseDown OnMouseDown;
If you want to be able to "register" a control to your class this is the way to do it (note that the event is static). Here you say that when the mouse goes down on control, FireMouseDown is executed.
public static void Init(Control control, Control container, Direction direction)
{
control.MouseDown += new MouseEventHandler(FireOnMouseDown);
}
In FireMouseDown you have to fire the OnMouseEvent with the right arguments:
public static void FireOnMouseDown(object sender, MouseEventArgs e)
{
if (OnMouseDown != null)
OnMouseDown(this, e, sender as Control);
}
Now you can subscribe to OnMouseDown your original method from outside Helper:
Helper.OnMouseDown += new MouseDown(MouseDownEvent);
EDIT2:
I didn't specify it, but what's happening here is that the OnMouseDown event is fired everytime there is a MouseDown event (the windows event, I mean) on one of the controls that were passed to Init. This means that the registration to OnMouseDown has to be done only once. After that, every time you have a MouseDown on one of these controls MouseDownEvent is executed passing these parameters:
sender -> the Helper class
e -> the original MouseEventArgs generated by Windows
control -> the control that generated the original event
With regard to the MouseMove event, you should do something like for MouseDown, just adding the extra parameters you need (even if it's not clear to me what is the meaning of container and direction, since it seems that container is always equal to control and direction is always Direction.Any). I mean something like:
public delegate void MouseMove(object sender, MouseEventArgs e, Control control, Control container, Direction direction);
public static event MouseMove OnMouseMove;
public static void FireOnMouseMove(object sender, MouseEventArgs e)
{
if (OnMouseMove != null)
OnMouseMove(this, e, sender as Control, aContainer, aDirection);
}
What I don't understand here is from where you are going to find out aContainer and aDirection. If I should replicate your Init I would write OnMouseMove(this, e, sender as Control, sender as Control, Direction.Any);, but I don't think that it would work.
I'm sure I've read that there is a way of getting co-ordinates on TouchDown in a WPF app and finding out what UI elements are 'underneath' this touch. Can anyone help?
You have to do a hit test against the visual tree.
Here is an example with mouse click (but touch is more or less the same thing in this respect):
// Respond to the left mouse button down event by initiating the hit test.
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Retrieve the coordinate of the mouse position.
Point pt = e.GetPosition((UIElement)sender);
// Perform the hit test against a given portion of the visual object tree.
HitTestResult result = VisualTreeHelper.HitTest(myCanvas, pt);
if (result != null)
{
// Perform action on hit visual object.
}
}
Other overload of HitTest can give you multiple hit visuals.
Let your UI elements extend UIElement class like this:
class MyUIElement : UIElement
{
protected override void OnManipulationStarting(System.Windows.Input.ManipulationStartingEventArgs e)
{
base.OnManipulationStarting(e);
UIElement involvedUIElement = e.Source as UIElement;
// to cancel the touch manipulaiton:
e.Cancel();
}
}
involvedUIElement should hold the UI elements that raised the touch event, if you need to cancel the manipulation for specific elements you just need to call e.Cancel();
I hope this will help!
I had written an event handler for MouseMove for my form
but When I add a panel to form, this handler does NOT run while mouse moves on panel.
I added event handler to panel and this works but I had several panels on the form,
is there an easier solution?
Unfortunately, WinForms doesn't support event bubbling. But you can write some code to ease the task of hooking up events.
public void AssignMouseMoveEvent(Form form)
{
foreach(Control control in form.Controls)
{
if(! (control is Panel))
continue;
control.MouseMove += PanelMouseMove;
}
}
You should call the above code passing it your current form and it will assign PanelMouseMove as event handler for MouseMove event of all the panels.
I think you should be able to "propagate" the handlers, so you don't have to re-write the code in each one. Just remember that the MouseMove event has control-relative coordinates, so if you pass the event from your panel to your form, you'll have to translate the X & Y values in the event to the form coordinates (something like subtracting panel.location.X from event.X, etc).
This code worked for me (assumes you have a form with a panel and a label. The label is named "MouseCoords"
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void ShowCoords(int x, int y)
{
this.MouseCoords.Text = string.Format("({0}, {1})", x, y);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
this.ShowCoords(e.X, e.Y);
}
protected override void OnControlAdded(ControlEventArgs e)
{
// hook the mouse move of any control that is added to the form
base.OnControlAdded(e);
e.Control.MouseMove += new MouseEventHandler(Control_MouseMove);
}
private void Control_MouseMove(object sender, MouseEventArgs e)
{
// convert the mouse coords from control codes to screen coords
// and then to form coords
System.Windows.Forms.Control ctrl = (System.Windows.Forms.Control)sender;
Point pt = this.PointToClient(ctrl.PointToScreen(e.Location));
this.ShowCoords(pt.X, pt.Y);
}
private void Form1_Load(object sender, EventArgs e)
{
this.MouseMove += this.Form1_MouseMove;
}
}
}
You could Implement IMessageFilter to pre-process messages that are going to your controls.
http://blogs.msdn.com/csharpfaq/archive/2004/10/20/245412.aspx
However, I don't think this is a very clean way to do things from a design perspective.
No there is no simpler way, and you should assign event handler for each control where you need to receive MouseMove events.
If you set the Capture property of the form to true, it will receive all mouse input, regardless of which control that is under the mouse. It will lose the mouse capture at certain operations (I am not sure exactly when, though). Also, according to the documentation for the property, shortcut keys should not work while the mouse is captured. So, depending on what you want to achieve, this might not be the preferred way to go.
Assuming that mouse starts moving over the form rather than over the panel - which is a big assumption - you'll get a MouseLeave event when it enters a sub control. You could check the cursor location and call the mouse move code if it's still within the bounds of the form.
This doesn't work if the mouse move event starts on a control.
I found another solution :) "Raise events in controls which hide events"
I catch the event in panel and rise the Mouse move event of the form by calling onMouseMove