I'm trying to move a rectangle drawn in Canvas by mouse (drag and drop).

When I click on the Rectangle and move the mouse (keep clicking) to a new position it's OK:

enter image description here

But when I click on it again and move the mouse just a bit the Rectangle move to old position:

enter image description here

I don't know why it is. Can anybody give me some explaination?

Here is my code (all parameters have been assigned and initialized). Thanks in advance!

private void MyCanvas_MouseMove_1(object sender, MouseEventArgs e) { if (e.RightButton == MouseButtonState.Pressed && e.OriginalSource is Shape) { p2 = e.GetPosition(MyCanvas); TranslateTransform tf = new TranslateTransform(p2.X - p1.X, p2.Y - p1.Y); _MyTestRect.RenderTransform = tf; } } private void MyCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { if (e.OriginalSource is Shape) { p1 = e.GetPosition(MyCanvas); } } 
1

3 Answers

Mvvm Behavior Approach add the refference to: System.Windows.Interactivity.

  1. In XAML:

    <Canvas x:Name="MyCanvas" Background="#00FFFFFF"> <i:Interaction.Behaviors> <!--soSandBox is the reffrence to the behavior--> <soSandBox:MoveElementsInCanvasBehavior/> </i:Interaction.Behaviors> <Rectangle x:Name="_MyTestRect1" Fill="Tomato" Width="50" Height="50"/> <Rectangle x:Name="_MyTestRect2" Fill="Tomato" Width="50" Height="50"/> <Rectangle x:Name="_MyTestRect3" Fill="Tomato" Width="50" Height="50"/></Canvas> 
  2. Behavior code:

    protected override void OnAttached() { base.OnAttached(); AssociatedObject.MouseLeftButtonDown += AssociatedObjectOnMouseLeftButtonDown; AssociatedObject.MouseLeftButtonUp += AssociatedObjectOnMouseLeftButtonUp; AssociatedObject.MouseMove += AssociatedObjectOnMouseMove; } private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs e) { if (_shape != null && _shape.IsMouseCaptured) { _p2 = e.GetPosition(AssociatedObject); _shape.SetValue(Canvas.TopProperty, _p2.Y - _originalOffsetFromTop); _shape.SetValue(Canvas.LeftProperty, _p2.X - _originalOffsetFromLeft); } } private void AssociatedObjectOnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (_shape == null) return; _shape.ReleaseMouseCapture(); _shape = null; } private double GetDist(double originalValue, double newValue) { if (double.IsNaN(originalValue) || double.IsInfinity(originalValue)) return Math.Abs(newValue - 0); return Math.Abs(newValue - originalValue); } private void AssociatedObjectOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { _shape = e.OriginalSource as Shape; if (_shape != null) { _p1 = e.GetPosition(AssociatedObject); _shape.CaptureMouse(); _originalOffsetFromTop = GetDist((double)_shape.GetValue(Canvas.TopProperty), _p1.Y); _originalOffsetFromLeft = GetDist((double)_shape.GetValue(Canvas.LeftProperty), _p1.X); } } protected override void OnDetaching() { base.OnDetaching(); AssociatedObject.MouseLeftButtonDown -= AssociatedObjectOnMouseLeftButtonDown; AssociatedObject.MouseLeftButtonUp -= AssociatedObjectOnMouseLeftButtonUp; AssociatedObject.MouseMove -= AssociatedObjectOnMouseMove; } 
    1. Summary: This way you can put inside the canvas as much elements as you wish, and when you click the element (and when this element is a shape) you will be able to move it.

enter image description here

  1. Translate Transform XAML:

    <Canvas x:Name="MyCanvas" Background="#00FFFFFF"> <i:Interaction.Behaviors> <!--convert event to command mechanism--> <soSandBox:CanvasMouseEventObservingBehavior OnMouseMoveAction="{Binding OnMouseMoveAction, UpdateSourceTrigger=PropertyChanged}" OnMouseRightButtonDownAction="{Binding OnMouseRightButtonDownAction, UpdateSourceTrigger=PropertyChanged}" OnMouseRightButtonUpAction="{Binding OnMouseRightButtonUpAction, UpdateSourceTrigger=PropertyChanged}"/> </i:Interaction.Behaviors> <Rectangle x:Name="_MyTestRect1" Fill="Tomato" Width="50" Height="50"> <Rectangle.RenderTransform> <TransformGroup> <TranslateTransform X="{Binding TranslateTransformX, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Y="{Binding TranslateTransformY, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></TranslateTransform> </TransformGroup> </Rectangle.RenderTransform> </Rectangle></Canvas> 
  2. Translate Transform view model (translation related code):

     private void RightMouseUp(Point obj) { _originalPoint = obj; _currentOffsetByX = GetDist(_currentOffsetByX, obj.X); _currentOffsetByY = GetDist(_currentOffsetByY, obj.Y); } private void RightMouseDown(Point obj) { _originalPoint = obj; _currentOffsetByX = GetDist(_currentOffsetByX, obj.X); _currentOffsetByY = GetDist(_currentOffsetByY, obj.Y); } private void MouseMoved(Point obj) { TranslateTransformX = obj.X - _currentOffsetByX; TranslateTransformY = obj.Y - _currentOffsetByY; } private double GetDist(double originalValue, double newValue) { if (double.IsNaN(originalValue) || double.IsInfinity(originalValue)) return Math.Abs(newValue - 0); return Math.Abs(newValue - originalValue); } public double TranslateTransformY { get { return _translateTransformY; } set { _translateTransformY = value; OnPropertyChanged(); } } public double TranslateTransformX { get { return _translateTransformX; } set { _translateTransformX = value; OnPropertyChanged(); } } 

Regards

0

You should not create the transform every time otherwise you reset the translation.

Create a TranslateTransform if none exist.

Then cumulate the translations inside.

Regards

1

Try just using the Canvas.SetTop and Canvas.SetLeft.

Rectangle myRectangle = new Rectangle(); myRectangle += myRectangle_MouseLeftButtonDown; void myRectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { myRectangle.MouseMove += origin_MouseMove; } void myRectangle_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) { Point p = new Point() { // Just round the coordinates X = Math.Round(e.GetPosition(canvas).X, 0, MidpointRounding.AwayFromZero), Y = Math.Round(e.GetPosition(canvas).Y, 0, MidpointRounding.AwayFromZero), }; Canvas.SetTop(myRectangle, p.Y); Canvas.SetLeft(myRectangle, p.X); myRectangle.MouseLeftButtonUp += myRectangle_MouseLeftButtonUp; } void myRectangle_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) { myRectangle.MouseMove -= origin_MouseMove; myRectangle.MouseLeftButtonUp -= origin_MouseLeftButtonUp; } 
0

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.