WPF: How to translateTransform a rectangle?

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.

You Might Also Like