I wanted to be able to drag or move controls around at runtime (using TranslateTransform) - by clicking the mouse on the desired control and moving it to a new location on the parent screen/control. This code sample uses the simplest WPF Elements - a Canvas and a couple of Rectangles.
I don't think this needs much explaination. So just copy/paste and run it. You should be able to see two rectangles on canvas and move them around when mouse is down.
I don't think this needs much explaination. So just copy/paste and run it. You should be able to see two rectangles on canvas and move them around when mouse is down.
L O G I C
- Program maintains a variable "current" that keeps track of which control (or UI element) on canvas is under a possible dragging action.
- Each Rectangle declares RenderTransform's TranslateTransform and subscribes to MouseLeftButtonDown events, where it is assigned to the current element.
- Canvas subscribes to MouseDown, MouseUp and MouseMove. In MouseDown canvas gets the coordinates of the current control and captures the mouse on it. In MouseUp it releases the current element and the mouse. The MouseMove resets the location of the current element by adjusting the current element's RenderTransform with the new position.
C O D E
/* * * * * * * * * * * * * * * * * * * ** * * * ** * * * * * * * * *
. .xaml file:
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
<Window x:Class="MoveObjectOnMouseDownUpMove.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Canvas x:Name="canvas"
MouseDown="Canvas_MouseDown"
MouseUp="Canvas_MouseUp"
MouseMove="Canvas_MouseMove">
<Rectangle x:Name="rect2" Height="50" Width="50" Fill="Blue"
Canvas.Left="50" Canvas.Top="100"
MouseLeftButtonDown="rect2_MouseLeftButtonDown">
<Rectangle.RenderTransform>
<TranslateTransform/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="rect1" Height="50" Width="50" Fill="Red" MouseLeftButtonDown="rect1_MouseLeftButtonDown">
<Rectangle.RenderTransform>
<TranslateTransform />
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
</Window>
/* * * * * * * * * * * * * * * * * * * ** * * * ** * * * * * * * * *
. xaml.cs file:
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MoveObjectOnMouseDownUpMove
{
public partial class Window1 : Window
{
//see the Element class declaration at the bottom, using it for readablity
private Element current = new Element();
public Window1()
{
InitializeComponent();
}
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
this.current.X = Mouse.GetPosition((IInputElement)sender).X;
this.current.Y = Mouse.GetPosition((IInputElement)sender).Y;
// Ensure object receives all mouse events.
this.current.InputElement.CaptureMouse();
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
if (this.current.InputElement != null)
this.current.InputElement.ReleaseMouseCapture();
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
// if mouse is down when its moving, then it's dragging current
if (e.LeftButton == MouseButtonState.Pressed)
this.current.IsDragging = true;
if (this.current.IsDragging && current.InputElement != null)
{
// Retrieve the current position of the mouse.
var newX = Mouse.GetPosition((IInputElement)sender).X;
var newY = Mouse.GetPosition((IInputElement)sender).Y;
// Reset the location of the object (add to sender's renderTransform
// newPosition minus currentElement's position
var rt = ((UIElement)this.current.InputElement).RenderTransform;
var offsetX = rt.Value.OffsetX;
var offsetY = rt.Value.OffsetY;
rt.SetValue(TranslateTransform.XProperty, offsetX + newX - current.X);
rt.SetValue(TranslateTransform.YProperty, offsetY + newY - current.Y);
// Update position of the mouse
current.X = newX;
current.Y = newY;
}
}
private void rect1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.current.InputElement = (IInputElement)sender;
}
private void rect2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.current.InputElement = (IInputElement)sender;
}
}
}
/* * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * *
helper class (don't need it, but makes things easier to read)
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
public class Element
{
#region Fields
bool isDragging = false;
IInputElement inputElement = null;
double x, y = 0;
#endregion
#region Constructor
public Element() { }
#endregion
#region Properties
public IInputElement InputElement
{
get { return this.inputElement; }
set
{
this.inputElement = value;
/* every time inputElement resets, the draggin stops (you actually don't even need to track it, but it made things easier in the begining, I'll change it next time I get to play with it. */
this.isDragging = false;
}
}
public double X
{
get { return this.x; }
set { this.x = value; }
}
public double Y
{
get { return this.y; }
set { this.y = value; }
}
public bool IsDragging
{
get { return this.isDragging; }
set { this.isDragging = value; }
}
#endregion
}