none
copy a rectangle

    Question

  • Hello everyone,

    I dont know if this question has been answered before but I would like to know how can I create a copy of my rectangle (I have a rectangle on the canvas)when the user presses the mouse on it and then this copy I would like to drag and drop it in another position.
    I can drag the same rectangle around but I cannot create an identical draggable copy!
    I would appreciate your help!

    Penny

    ps)can you please move it to the appropriate forum if this is not it!
    Monday, September 07, 2009 4:53 PM

Answers

  • Hi

    Well, I played a bit with your requirement, just a simple sample.

    My XAML:
    <Canvas Grid.Row="0" Background="Orange">
        <Rectangle x:Name="myRect" Canvas.Top="12" Canvas.Left="12" 
            Fill="Red" Stroke="Black" StrokeThickness="1" Width="25" Height="25" 
            MouseMove="myRect_MouseMove" MouseLeftButtonDown="myRect_MouseLeftButtonDown" MouseLeftButtonUp="myRect_MouseLeftButtonUp" />
    </Canvas>

    My xaml.cs:
    bool _isDragging;
    Point _startPos;
    Rectangle _copy;
    
    private void myRect_MouseMove(object sender, MouseEventArgs e)
    {
        if (_isDragging) {
            _startPos = e.GetPosition((Canvas)myRect.Parent);
            _copy.SetValue(Canvas.LeftProperty, _startPos.X);
            _copy.SetValue(Canvas.TopProperty, _startPos.Y);
        }
    }
    
    private FrameworkElement Clone(FrameworkElement e)
    {
        XmlDocument document = new XmlDocument();
        document.LoadXml(XamlWriter.Save(e));
        return (FrameworkElement)XamlReader.Load(new XmlNodeReader(document));
    }
    
    private void myRect_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _isDragging = true;
        ((Rectangle)sender).CaptureMouse();
        _startPos = e.GetPosition((Canvas)myRect.Parent);
    
        _copy = (Rectangle)Clone(myRect);
        ((Canvas)myRect.Parent).Children.Add(_copy);
        _copy.SetValue(Canvas.ZIndexProperty, 1);
    }
    
    private void myRect_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        _isDragging = false;
        ((Rectangle)sender).ReleaseMouseCapture();
    }

    Your code for dragging is probably better than mine, but it demostrates dragging a clone of the original rectangle.

    :)
    Monday, September 07, 2009 9:05 PM

All replies

  • In WPF? Check this out.
    Monday, September 07, 2009 7:38 PM
  • In Windows Forms, this link might help.

    how to move a shape while program is running?


    Solution, courtesy of nobugz.

    Rudedog  =8^D
    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, September 07, 2009 7:52 PM
  • In WPF? Check this out.

    hello!thanx for the answer!
    unfortunately this link confused me even more :(

    What I have so far is a .cs file where I have added a rectangle like this:

    Rectangle rect1= new Rectangle ();
    ...
    myCanvas.Children.Add(rectangle1);

    I can drag and drop this rectangle using the DragDelta method.
    It's not what I want though!
    What I want is the user to click on the rectangle and then for him to be able to drag a copy of this rectangle!
    In principle, I want to create some application for diagram designing!The user will see on the left the toolbox, he will take the element he wants and he will position it on the canvas.
    But I started it simple with a rectangle on one side of the window!
    Can you please help me?


    Monday, September 07, 2009 8:15 PM
  • In Windows Forms, this link might help.

    how to move a shape while program is running?


    Solution, courtesy of nobugz.

    Rudedog  =8^D
    Mark the best replies as answers. "Fooling computers since 1971."

    Hello again!

    In my case, I want to move multiple copies of the rectangle on the canvas!
    I opened a wpf application and am working on the .cs file!
    I appreciate any help!Thank you again!
    Monday, September 07, 2009 8:18 PM
  • That solution was for windows forms. 
    It draws a red circle.  Click and drag the circle.

    WPF is a bit more complicated than WinForms.
    Which type of solution are you looking for?


    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, September 07, 2009 8:40 PM
  • Thanx for the time Rudedog2!
    Well, I want to do a wpf application!But since I defined the rectangle in the .cs file, I dont think I will implement with xaml!
    My problem is that I dont know how to implement a draggable copy of my rectangle!
    I have defined it in the way i said above and the visual effect I want to achieve is the user to click on this rectangle and drag a copy of it to the position he wants!
    Then if he wants, he should be able to drag more copies of the rectangle on the canvas!

    Thanks again for you time!
    Monday, September 07, 2009 8:46 PM
  • Hi

    Well, I played a bit with your requirement, just a simple sample.

    My XAML:
    <Canvas Grid.Row="0" Background="Orange">
        <Rectangle x:Name="myRect" Canvas.Top="12" Canvas.Left="12" 
            Fill="Red" Stroke="Black" StrokeThickness="1" Width="25" Height="25" 
            MouseMove="myRect_MouseMove" MouseLeftButtonDown="myRect_MouseLeftButtonDown" MouseLeftButtonUp="myRect_MouseLeftButtonUp" />
    </Canvas>

    My xaml.cs:
    bool _isDragging;
    Point _startPos;
    Rectangle _copy;
    
    private void myRect_MouseMove(object sender, MouseEventArgs e)
    {
        if (_isDragging) {
            _startPos = e.GetPosition((Canvas)myRect.Parent);
            _copy.SetValue(Canvas.LeftProperty, _startPos.X);
            _copy.SetValue(Canvas.TopProperty, _startPos.Y);
        }
    }
    
    private FrameworkElement Clone(FrameworkElement e)
    {
        XmlDocument document = new XmlDocument();
        document.LoadXml(XamlWriter.Save(e));
        return (FrameworkElement)XamlReader.Load(new XmlNodeReader(document));
    }
    
    private void myRect_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _isDragging = true;
        ((Rectangle)sender).CaptureMouse();
        _startPos = e.GetPosition((Canvas)myRect.Parent);
    
        _copy = (Rectangle)Clone(myRect);
        ((Canvas)myRect.Parent).Children.Add(_copy);
        _copy.SetValue(Canvas.ZIndexProperty, 1);
    }
    
    private void myRect_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        _isDragging = false;
        ((Rectangle)sender).ReleaseMouseCapture();
    }

    Your code for dragging is probably better than mine, but it demostrates dragging a clone of the original rectangle.

    :)
    Monday, September 07, 2009 9:05 PM
  • Hey,

    thank you so much!It works perfectly!It does exactly what I wanted. I just had to add some references to markup and xml and worked directly!
    Thank you, I was looking for it for a long time! :-)
    Tuesday, September 08, 2009 7:15 AM
  • And by the way,

    trying to understand the code,I would like to make this clear: the clone method creates identical copies that are the same copy in fact?Is there a way to separate these copies by assigning a unique number to each of them? or because each time ,each copy is stored in the _copy variable, this means that they cannot be separated?
    thank you again!I just want to understand it!
    Tuesday, September 08, 2009 9:55 AM
  • Each clone is a separate object. The only reason I had the _copy variable was to retain a reference to the clone in between mouse button down and mouse move.
    You could get rid of it and use a local variable in your MouseLeftButtonDown event

    ...
    Rectangle copy = (Rectangle)Clone(myRect);
    ((Canvas)myRect.Parent).Children.Add(copy);
    copy.SetValue(Canvas.ZIndexProperty, 1);

    And in the MouseMove:
                if (_isDragging) {
                    Canvas canvas = (Canvas)myRect.Parent;
                    _startPos = e.GetPosition(canvas);
                    Rectangle copy = canvas.Children.Cast<Rectangle>().Last();
                    copy.SetValue(Canvas.LeftProperty, _startPos.X);
                    copy.SetValue(Canvas.TopProperty, _startPos.Y);
                }

    Each clone stays in the canvas' Children collection so they are definitely different instances.

    Hope that makes sense.

    :)
    Tuesday, September 08, 2009 12:19 PM
  • Yes thank you!This cleared me out!Althought I get an exception but I understand the point.
    So since every copy is unique, I could assign some events to them also no?
    For example if I would like to be able to move this copies more than once.So after their creation and initial movement, I would like the user to reposition them on the canvas if he wants.
    To do that, I tried to do sth like this:
    _copy.MouseLeftButtonDown += new MouseButtonEventHandler(_copy_MouseLeftButtonDown);

    and then implement the dragging in this way

    which of course is not correct but I dont understand how to solve this...

    Thanx again!I m sorry for the fuss I make!:(
    Tuesday, September 08, 2009 1:37 PM
  • Indeed you can.

    When the mouse button goes down, you need to ensure your original rectangle is the copy you select, no longer myRect

    _isDragging = true;
    Rectangle original = (Rectangle)sender;
    original.CaptureMouse();
    _startPos = e.GetPosition((Canvas)original.Parent);

    Clone the new original and wire up the events like so:
    Rectangle copy = (Rectangle)Clone(original);
    copy.MouseMove += this.myRect_MouseMove;
    copy.MouseLeftButtonUp += this.myRect_MouseLeftButtonUp;
    copy.MouseLeftButtonDown += this.myRect_MouseLeftButtonDown;

    That should work.

    Good luck!
    Tuesday, September 08, 2009 2:25 PM
  • Indeed you can.

    When the mouse button goes down, you need to ensure your original rectangle is the copy you select, no longer myRect

    _isDragging = true;
    Rectangle original = (Rectangle)sender;
    original.CaptureMouse();
    _startPos = e.GetPosition((Canvas)original.Parent);

    Clone the new original and wire up the events like so:
    Rectangle copy = (Rectangle)Clone(original);
    copy.MouseMove += this.myRect_MouseMove;
    copy.MouseLeftButtonUp += this.myRect_MouseLeftButtonUp;
    copy.MouseLeftButtonDown += this.myRect_MouseLeftButtonDown;

    That should work.

    Good luck!

    Just observed that you want to be able to move the clone about NOT create a clone of the clone!

    A little bit of refactoring is required. The mouse move and mouse left button up code can stay the same. However you need to different handlers for the mouse left button down: one which initiates the drag, and one which in addition clones the original rectangle.

    private void myRect_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        Rectangle_MouseLeftButtonDown(sender, e);
        CloneOriginalRectangle((Rectangle)sender);
    }
    
    private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _isDragging = true;
        Rectangle original = (Rectangle)sender;
        original.CaptureMouse();
        _startPos = e.GetPosition((Canvas)original.Parent);
    }
    
    private void CloneOriginalRectangle(Rectangle original)
    {
        Rectangle copy = (Rectangle)Clone(original);
        copy.MouseMove += this.myRect_MouseMove;
        copy.MouseLeftButtonUp += this.myRect_MouseLeftButtonUp;
        copy.MouseLeftButtonDown += this.Rectangle_MouseLeftButtonDown;
        ((Canvas)myRect.Parent).Children.Add(copy);
        copy.SetValue(Canvas.ZIndexProperty, 1);
    }

    • Edited by Wole Ogunremi Tuesday, September 08, 2009 3:03 PM Fixed sentence errors.
    Tuesday, September 08, 2009 2:59 PM
  • Heey,

    Thank you a lot for your help!I almost have it I think!!
    First of all, can you please explain me what this line in the MouseMove does?

    Rectangle copy = canvas.Children.Cast<Rectangle>().Last();

    I get an exception when I run the code and I have difficulty understanding it :-(

    Thank you again!

    Tuesday, September 08, 2009 3:27 PM
  • That's a bug in my code! Sorry!!!
    Replace Cast with OfType

    Based on the original requirement what the code wants to do is obtain the last rectangle added to the the canvas' children collection.

    OfType filters the collection for all items of the specified type.

    Cast on the other hand casts every element in the collection to the specified type and throws an exception if it can't. So, I should have had OfType in there.

    The sample was just meant to demo what you wanted: it's probably not the exact code you need.
    Tuesday, September 08, 2009 3:45 PM
  • As a consequence of that bug you spotted, you will observe that we can only move the last clone. If we create more than one clone, and try to move one of the in betweens the last clone gets moved! Probably not what you wanted.

    Hopefully you can correct that in your version.

    Let's know how you get on.

    Regards
    Wole
    Tuesday, September 08, 2009 3:58 PM
  • Hey, yes I noticed that!
    Thank you a lot or your time!I really appreciated it!Now I think I can try to evolve it on my own!I was searching a long time for these things that you provided me!
    Tuesday, September 08, 2009 4:01 PM