none
Control dragging with mouse

    Dotaz

  • Hello,

    I am trying to make all the labels on my WPF form draggable(move them around the form).

    I can get the position of the mouse relatively to the screen with no problem.

    The problem is that I cannot figure out how to make the labels properly draggable.

    Can someone help me out?

    Thanks.

    23. března 2012 12:55

Odpovědi

  • Good to hear you found a fitting solution. Even despite that 22+ thing. :-)

    After reading your newly found sample, i had a little idea as to how you could set it up as well. By the way, are you using WindowForms or WPF ?

    Anyway, here is the sample i figured in the end. :-)

        public class DraggingCanvas : Canvas
        {
            int startingPointX, startingPointY;
    
            protected override void OnMouseDown(MouseButtonEventArgs e)
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    startingPointX = (int)e.GetPosition(null).X - (int)Canvas.GetLeft(e.Source as UIElement);
                    startingPointY = (int)e.GetPosition(null).Y - (int)Canvas.GetTop(e.Source as UIElement);
                }
       
                base.OnMouseDown(e);
            }
    
            protected override void OnMouseUp(MouseButtonEventArgs e)
            {
                Mouse.Capture(null);
                base.OnMouseUp(e);
            }
    
            protected override void OnMouseMove(MouseEventArgs e)
            {
                if (e.LeftButton == MouseButtonState.Pressed && e.Source is UIElement)
                {
                    Mouse.Capture(e.OriginalSource as UIElement);
    
                    Canvas.SetLeft(e.Source as UIElement, Mouse.GetPosition(null).X - startingPointX);
                    Canvas.SetTop(e.Source as UIElement, Mouse.GetPosition(null).Y - startingPointY);
                }
    
                base.OnMouseMove(e);
            }
        }

    This will mean that all the UIElements are dragable in your Canvas. And will react to the initial mouse position. :-)


    Developing is part of being a developer.



    24. března 2012 0:12

Všechny reakce

  • You can do like this.

    Label label = new Label();
                label.MouseMove += (s, e) => 
                {
                    if(e.LeftButton == MouseButtonState.Pressed)
                        //Reposition.
                };

    All depending on what surface your controls are on, you can drag it around, by using margins or Top/Left properties on Canvas.
    Good luck.


    Developing is part of being a developer.

    23. března 2012 13:16
  • Actually the part you wrote is clear to me but the "reposition" part is where i have the trouble.

    I can't figure out how to get it to move properly, I can move it just very bad.

    Thanks .

    23. března 2012 13:18
  • What parent control do you have for the labels ? :)

    Developing is part of being a developer.

    23. března 2012 13:30
  • Forgot to mention it, Canvas.

    Thanks !


    I can change it if its necessary, though.
    • Upravený Igor_abc 23. března 2012 14:16
    23. března 2012 14:07
  • In my opinion Canvas is the easiest one to move objects on, so this is great.

    The missing code is

    Label.SetValue(Canvas.TopProperty, YValue);
    Label.SetValue(Canvas.LeftProperty, XValue);


    Developing is part of being a developer.

    23. března 2012 14:19
  • What is YValue and XValue ?
    • Upravený Igor_abc 23. března 2012 14:31
    23. března 2012 14:31
  • Try this.

                Label label = new Label();
                label.MouseMove += (s, e) => 
                {
                    if(e.LeftButton == MouseButtonState.Pressed)
                    {
                        label.SetValue(Canvas.TopProperty,e.GetPosition(MyCanvas).Y);
                        label.SetValue(Canvas.LeftProperty, e.GetPosition(MyCanvas).X);
                    }
                };

    That should work, just use the Name of your canvas instead of the name written here :)


    Developing is part of being a developer.

    23. března 2012 14:34
  • That works but it has the same problem my code has.

    No matter where I click on the label, the cursor ends up at the top of the label(the label positions itself there).

    That is the problem I'm actually having here.

    Any ideas?

    Thanks !

    23. března 2012 14:47
  • That works but it has the same problem my code has.

    No matter where I click on the label, the cursor ends up at the top of the label(the label positions itself there).

    ...

    Hi,

    you somehow have to keep track of the offset (from the label's origin to the point on the label you clicked)...:

        public partial class MainWindow : Window
        {
            private bool _tracking;
            private Point _pt;
    
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Label_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                Control l = sender as Control;
                _pt = e.GetPosition(l);
                l.CaptureMouse();
                _tracking = true;
            }
    
            private void Label_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
            {
                Control l = sender as Control;
                _tracking = false;
                l.ReleaseMouseCapture();
            }
    
            private void Label_MouseMove(object sender, MouseEventArgs e)
            {
                if (_tracking)
                {
                    Control l = sender as Control;
                    l.SetValue(Canvas.LeftProperty, e.GetPosition(canvas1).X - _pt.X);
                    l.SetValue(Canvas.TopProperty, e.GetPosition(canvas1).Y - _pt.Y);
                }
            }
        }

    ...

    Xaml:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Canvas Name="canvas1" Background="{x:Static SystemColors.ControlDarkDarkBrush}">
            <Label Name="label1" Background="White" 
                   MouseLeftButtonDown="Label_MouseLeftButtonDown" 
                   MouseLeftButtonUp="Label_MouseLeftButtonUp" 
                   MouseMove="Label_MouseMove" Cursor="Hand">Hello</Label>
            <Label Name="label2" Background="White" 
                   MouseLeftButtonDown="Label_MouseLeftButtonDown" 
                   MouseLeftButtonUp="Label_MouseLeftButtonUp" 
                   MouseMove="Label_MouseMove" Cursor="Hand" Canvas.Left="84" Canvas.Top="27">Hello</Label>
        </Canvas>
    </Window>

    Regards,

      Thorsten

    23. března 2012 17:04
  • Unfortunately, the same problem exists within your code..

    23. března 2012 17:16
  • Hi Igor.

    Could you possibly use a drag behavior in your project?

    You'd need the Mircoroft.Expression.Interaction.dll for it to work.

    <Window
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
    	x:Class="WpfApplication1.MainWindow"
    	x:Name="Window"
    	Title="MainWindow"
    	Width="640" Height="480">
    
    	<Canvas x:Name="LayoutRoot">
    		<Label Content="Label">
    			<i:Interaction.Behaviors>
    				<ei:MouseDragElementBehavior ConstrainToParentBounds="True"/>
    			</i:Interaction.Behaviors>
    		</Label>
    	</Canvas>
    </Window>

    ~Christine
    23. března 2012 17:45
  • For me, it works as expected.

    Did you notice that to the Point _pt the relative offset to label1 is assigned?

    _pt = e.GetPosition(label1); //In the mousedown

    And later in the mousemove the position relative to the canvas is used?

    e.GetPosition(canvas1)...

    Regards,

      Thorsten

    23. března 2012 17:51
  • Everything you ever needed to undertand WPF drag and drop:

    http://www.codeproject.com/Articles/37161/WPF-Drag-and-Drop-Smorgasbord

    http://wpftutorial.net/DragAndDrop.html


    JP Cowboy Coders Unite!

    23. března 2012 17:53
  • Oh yes one other thing the ReactiveExtensions framwork probably does it best.

    http://blogs.msdn.com/b/wesdyer/archive/2009/11/18/a-brief-introduction-to-the-reactive-extensions-for-net-rx.aspx


    JP Cowboy Coders Unite!

    23. března 2012 17:54
  • I cant seem to get the code to work, I referenced the dll(from COM) and this code is still giving errors.

    (The attachable property 'Behaviors' was not found in type 'Interaction'. )

    edit: this responce was for Christine L.

    • Upravený Igor_abc 23. března 2012 18:35
    23. března 2012 17:58
  • Mr. Javaman II,

    I require very accurate dragging, and it is all done in the same control(in the canvas) and just being dragged around, not anywhere else.

    23. března 2012 18:38
  • Yes, and the reactive extension example given above meets all those requirements.

    JP Cowboy Coders Unite!

    23. března 2012 18:45
  • Sorry, that responce was for your first message :)

    I still need to check out the reactive extension.

    23. března 2012 19:34
  • I cant seem to get the code to work, I referenced the dll(from COM) and this code is still giving errors.

    (The attachable property 'Behaviors' was not found in type 'Interaction'. )

    edit: this responce was for Christine L.

    Sorry about that Igor.

    I used Blend to do it.  I've uploaded the sample to my SkyDrive so all the dll's are in there...

    https://skydrive.live.com/redir.aspx?cid=513b70517e544edb&resid=513B70517E544EDB!245&parid=513B70517E544EDB!134&authkey=!AOX_2NdmlSr1H-s

    Sometimes Blend and VS don't play nice together.

    But it looks like the guys have you headed on the right path already.

    Best of luck with your project!

    ~Christine


    23. března 2012 20:43
  • I've solved this problem after a bit of testing..

    I'll add some code

    static int startingPointX; static int startingPointY; static bool dragging=false; void y_MouseDown(object sender, MouseButtonEventArgs e) { if (!dragging) { startingPointX = System.Windows.Forms.Control.MousePosition.X - (int)Canvas.GetLeft(sender as UIElement); startingPointY = System.Windows.Forms.Control.MousePosition.Y - (int)Canvas.GetTop(sender as UIElement); } if (sender is Label) { dragging = true; } void y_MouseUp(object sender, MouseButtonEventArgs e) { dragging = false; Mouse.Capture(null); } void y_MouseMove(object sender, MouseEventArgs e) { if (dragging && sender is Label) { Mouse.Capture(sender as UIElement);//I use this so that I can drag the element around fast(without this it just stops dragging if you move it too fast) Canvas.SetLeft(sender as UIElement, Mouse.GetPosition(null).X - startingPointX ); Canvas.SetTop(sender as UIElement,22+ Mouse.GetPosition(null).Y - startingPointY ); } }


    Thank you everyone for your help !

    This code might not work for anyone but me because if the window is moved the dragging gets bad again(on the last line i used the number 22 because my control was 22 pixels below the form top).

    23. března 2012 21:50
  • Good to hear you found a fitting solution. Even despite that 22+ thing. :-)

    After reading your newly found sample, i had a little idea as to how you could set it up as well. By the way, are you using WindowForms or WPF ?

    Anyway, here is the sample i figured in the end. :-)

        public class DraggingCanvas : Canvas
        {
            int startingPointX, startingPointY;
    
            protected override void OnMouseDown(MouseButtonEventArgs e)
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    startingPointX = (int)e.GetPosition(null).X - (int)Canvas.GetLeft(e.Source as UIElement);
                    startingPointY = (int)e.GetPosition(null).Y - (int)Canvas.GetTop(e.Source as UIElement);
                }
       
                base.OnMouseDown(e);
            }
    
            protected override void OnMouseUp(MouseButtonEventArgs e)
            {
                Mouse.Capture(null);
                base.OnMouseUp(e);
            }
    
            protected override void OnMouseMove(MouseEventArgs e)
            {
                if (e.LeftButton == MouseButtonState.Pressed && e.Source is UIElement)
                {
                    Mouse.Capture(e.OriginalSource as UIElement);
    
                    Canvas.SetLeft(e.Source as UIElement, Mouse.GetPosition(null).X - startingPointX);
                    Canvas.SetTop(e.Source as UIElement, Mouse.GetPosition(null).Y - startingPointY);
                }
    
                base.OnMouseMove(e);
            }
        }

    This will mean that all the UIElements are dragable in your Canvas. And will react to the initial mouse position. :-)


    Developing is part of being a developer.



    24. března 2012 0:12
  • I am using WPF, in winforms it was easier !( I switched to WPF because winforms didn't support transparent controls)
    24. března 2012 14:21