Showing posts with label RenderTransform. Show all posts
Showing posts with label RenderTransform. Show all posts

1/10/08

How to move WPF controls with mouse at runtime

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.



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

    }