getting postion of a control in mousemove - silverlight

I have a silverlight control in which i am dynamically creating shapes on button click
These shapes are draggable across the form. Now i want to get top and left postion of a control on dragging (mousemove). Please help

Taking a look at your question history I can think of two approaches. I suspect that the shape is simply being placed on a Canvas and the MouseMove of which you speak refers to an event handler you've attached to the Canvas. On that basis then.
void Canvas_MouseMove(object sender, MouseEventArgs e)
{
Type currentType = e.OriginalSource.GetType();
// Make decisions based on value of currentType here
DependencyObject source = (DependencyObject)e.OriginalSource;
Point p = new Point(Canvas.GetLeft(source), Canvas.GetTop(source));
}
The more general solution is to use the TransformToVisual approach. Something like:-
var transform = ((UIElement)e.OriginalSource).TransformToVisual(MyCanvas);
Point p = transform.Transform(Point(0,0));

Related

WPF - Get current cell details

I have a grid which contains 2 rows and 2 columns. Each cell hosting a windows forms host control. I want to capture the selected cell when the user clicks on any of the cell. I have searched and found that there is no 'Click' event but I can make use of 'MouseDown' event with similar results. But now I am stuck because you would think there must be an easier way like 'GetCurentRow' and 'GetCurrentColumn' to capture the selected cell but there isn't.
What I want further to do is to get the child element in that particular cell of the grid.
I tried the following code but no matter which cell I click, I always get 0 for the row and column:
void InnerGridToContainWindowsFormsHost_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var element = (UIElement)e.Source;
int c = Grid.GetColumn(element);
int r = Grid.GetRow(element);
}
Is there any way to get the selected/clicked cell details or the children inside the cell?
I think that you may be going down the wrong route here... if you just want to know what control was clicked on, try using the VisualTreeHelper.HitTest method. You can find information on the VisualTreeHelper.HitTest Method page on MSDN. Basically, you would do something like:
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Get the position of the mouse pointer relative to the grid
Point clickPoint = e.GetPosition(grid);
HitTestResult result = VisualTreeHelper.HitTest(grid, clickPoint);
if (result != null)
{
// Do something here
}
}
You may also need some kind of basic recursive function to drill down through the Visual objects until you get to the one you want.

WPF Adorner appear on mouseover animation - what's the best pattern?

An Adorner is defined over part of an Image. The required behavior is as follows:
When the mouse is over the image area, including the Adorner area, the Adorner appears.
When the mouse leaves the image and Adorner area, the Adorner dissapears.
Adorner appearing and disappearing is to be through a fade in / out animation, accordingly.
A click on the Adorner area must raise event AdornerClicked
A click on the area over the Image which is not hidden by the adorner, must rais ImageClicked.
A naive implementation
Attach an animation on the Adorner opacity on the Image's MouseEnter and MouseLeave events, and attach Click events for each. This however causes the Adorner to disappear when the mouse is directly above it (as a MouseLeave is triggered on the Image below), violating requirement number 1.
A possible amendment to the naive implementation is to set IsHitTestVisible=false on the Adorner. However, no clicks are then captured by the Adorner, violating requirement number 4.
What is the correct pattern which will fulfill the requirements?
A bit old question but I've just had the same problem and could not find an answer so here's what I've come up with.
So the problem is that the control and its adorner are overlapping and setting the adorner to visible triggers a MouseLeave on the adorned control because it is now covered by the adorner.
The solution is to react on every MouseEnter and MouseLeave on both the adorned control and its adorner(s) and do a hit test manually. If any of them are hit then the adorner(s) should be visible otherwise collapsed.
So you need to be able to get the adorners from the adorned control and vica versa. Getting the adorned control from the adorner is no problem (use the AdornedElement property) but getting the adorners for a control is not provided by the framework (AFAIK) so I use a dictionary that maps my controls to a list of their adorners.
Here's the code inside my Panel-derived class (that contains and arranges my controls and their adorners):
private readonly Dictionary<Control, List<Adorner>> _controlToAdornersMap;
...
private void CreateMyControl()
{
var control = new MyControl();
control.MouseEnter += OnMyControlMouseEnterOrLeave;
control.MouseLeave += OnMyControlMouseEnterOrLeave;
Children.Add(control);
AddAdorners(control);
}
private void AddAdorners(Control control)
{
var myAdorner = new MyAdorner(control);
myAdorner.MouseEnter += OnMyAdornerMouseEnterOrLeave;
myAdorner.MouseLeave += OnMyAdornerMouseEnterOrLeave;
var adornerLayer = AdornerLayer.GetAdornerLayer(control);
adornerLayer.Add(myAdorner);
_controlToAdornersMap[control] = new List<Adorner> {myAdorner};
}
private void OnMyControlMouseEnterOrLeave(object sender, MouseEventArgs e)
{
HitTestAndSetAdornersVisibility((MyControl)sender, e);
}
private void OnMyAdornerMouseEnterOrLeave(object sender, MouseEventArgs e)
{
var adorner = (Adorner)sender;
HitTestAndSetAdornersVisibility((MyControl)adorner.AdornedElement, e);
}
private void HitTestAndSetAdornersVisibility(MyControl control, MouseEventArgs e)
{
var adorners = _controlToAdornersMap[control];
var hitTestSubjects = new List<UIElement> { control }.Concat(adorners);
var hit = hitTestSubjects.Any(i => VisualTreeHelper.HitTest(i, e.GetPosition(i)) != null);
SetAdornersVisibility(adorners, hit ? Visibility.Visible : Visibility.Collapsed);
}
private static void SetAdornersVisibility(IEnumerable<Adorner> adorners, Visibility visibility)
{
if (adorners != null)
foreach (var adorner in adorners)
adorner.Visibility = visibility;
}

Getting type of control on mouseover

I wanted to get the type of the control on mouseover. Please help
You can get the type of the UIElement over which the mouse is currently moving using the MouseMove event. Since this is a bubbling event you can attach a handler to the container such as a Canvas.
The UIElement over which the mouse is currently moving can be aquired from the the MouseEventArgs OriginalSource property.
Hence to determine the type over which the mouse is moving you could use code like this:-
void Canvas_MouseMove(object sender, MouseEventArgs e)
{
Type currentType = e.OriginalSource.GetType();
// Make decisions based on value of currentType here
}
However you need be careful, MouseMove fires frequently as the user moves the mouse so you might want to defer any heavy work until there is some time period after the last mouse move.
There is unfortunately no bubbling mouse over event.
The other alternative is to attach the same MouseEnter handler to each child UIElement you add to the Canvas. You could use sender instead of e.OriginalSource in that case. You would have to be careful to remove the handler if the element is removed from the Canvas, else you can create what would appear to be a memory leak.
Add mouse_enter event to the control.
You can get the type with a line of code as follow
var x = sender.GetType();
You can then compare it using something like:
if (x.Equals(typeof(TreeView)))

How to get a global location from MouseDown?

I'm working on a WinForms app and need to record the location of MouseDown and MouseUp events. My problem is that the events happen on different controls so their coordinate systems don't match (all I need is the amount of drag). I tried adding in the location of the sending control but it still doesn't work right.
Is there a simple solution to this?
You may use PointToScreen method for the purpose. Your mouse handler code could then look like this:
private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
Control control = (Control) sender;
Point pointOnScreen = control.PointToScreen(new Point(e.X, e.Y));
...
}

How easy it really is to implement drag&drop in silverlight?

I am new to silverlight - I've seen the tutorials and all, what I am looking for are high-level steps required to implement drag&drop and maybe a bit of (pseudo)code just to get an idea.
Any help appreciated!
Could you explain exactly what you would like to achieve with drag and drop in Silverlight? The top answer in the question that you linked to links to this page:
http://www.adefwebserver.com/DotNetNukeHELP/Misc/Silverlight/DragAndDropTest/
This contains a sample project with source that implements drag and drop (coincidentally, based on a sample I made for beta 1 of Silverlight 2 :-) ). What about this code is not suitable for your needs?
EDIT:
The basic skeleton of a drag and drop implementation would look like:
bool isDragging = false;
void elementMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (element.CaptureMouse())
{
isDragging = true;
element.MouseMove += elementMouseMove;
//start drag code goes here
}
}
void elementMouseMove(object sender, MouseEventArgs e)
{
//Drag code goes here
}
void element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (isDragging)
{
element.ReleaseMouseCapture();
isDragging = false;
element.MouseMove -= elementMouseMove;
//Drop code goes here
}
}
Add the MouseLeftButtonUp/Down handlers to the element that you want to drag.
In the MouseMove event handler, add the code that you want to execute during the drag: e.g. change Canvas.Top and Canvas.Left to match the mouse position. You can get the mouse position from the event args. You would probably want to get the position relative to the elements container.
In the MouseLeftButtonUp event handler, add the code that would execute when the "drop" occurs. For example, you might want to implement a "recycle bin" that elements can be dragged to. In that case, you would want to know what elements are underneath the mouse at the point of the drop. You can use VisualTreeHelper.FindElementsAtHostCoordinates, passing the mouse position relative to the application's root (use e.GetPosition(null)). Then if your "recycle bin" element is returned by FindElementsInHostCoordinates you know to execute the appropriate action.
Does this help answer you question?
isn't MouseLeftButtonDown where you are supposed to be starting the capture, not on mouseleftbuttonup?

Resources