Click here to Skip to main content
15,884,473 members
Please Sign up or sign in to vote.
4.00/5 (2 votes)
See more:
Hello,

i googled to check how to drag and drop usercontrols in the same form in wpf but didnt get any perfect one.

i have 3 usercontrols in the wpf form.
i want to drag and drop these usercontrols on a canvas in the same form.
Iam new to WPF and confused with these mousemove, mouseleftbuttondown,and other event handlers.

what exactly to write in these eventhandlers. how can be dataobject created and captured in drop eventhandler.

can any one help me out with a good example.plz provide me the source code so that i can understand.


thanks,
Posted

My other "solution" implements a usercontrol which can be dragged around the same canvas it's originally placed on.

If you meant you need to drag the user controls from another element on TO a Canvas, then here's an example using WPF drag and drop...

First, implement a custom Canvas class which is a drop target and a drag/drop data class to pass info from the drag/drop source to the drop target:
public class DropableCanvas : Canvas
{
    public DropableCanvas()
        : base()
    {
        this.AllowDrop = true;
        this.Drop += new DragEventHandler(DropableCanvas_Drop);
    }

    void DropableCanvas_Drop(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent(typeof(DropableCanvasDragDropData)))
        {
            DropableCanvasDragDropData dragdropdata = e.Data.GetData(typeof(DropableCanvasDragDropData)) as DropableCanvasDragDropData;

            // Remove usercontrol from its starting panel
            dragdropdata.SourcePanel.Children.Remove(dragdropdata.UserControl);

            // Position the usercontrol on this canvas at the drop point
            Point dropPoint = e.GetPosition(this);
            Canvas.SetLeft(dragdropdata.UserControl, dropPoint.X - dragdropdata.OffsetPoint.X);
            Canvas.SetTop(dragdropdata.UserControl, dropPoint.Y - dragdropdata.OffsetPoint.Y);

            // Add the usercontrol to this canvas
            this.Children.Add(dragdropdata.UserControl);
        }
        e.Handled = true;
    }
}

public class DropableCanvasDragDropData
{
    public DropableCanvasDragDropData(Panel srcpanel, UserControl control, Point pt)
    {
        this.SourcePanel = srcpanel;
        this.UserControl = control;
        this.OffsetPoint = pt;
    }

    public Panel SourcePanel { get; protected set; }
    public UserControl UserControl { get; protected set; }
    public Point OffsetPoint { get; protected set; }
}

Next,implement a dragable user control by making it a drag source:
public partial class DragableUserControl : UserControl
{
    public DragableUserControl()
    {
        InitializeComponent();
    }

    private void UserControl_MouseMove(object sender, MouseEventArgs e)
    {
        DragableUserControl dragableusercontrol = sender as DragableUserControl;
        if (dragableusercontrol != null && e.LeftButton == MouseButtonState.Pressed)
        {
            DragDrop.DoDragDrop(dragableusercontrol,
                            new DropableCanvasDragDropData(dragableusercontrol.Parent as Panel, dragableusercontrol, e.GetPosition(dragableusercontrol)),
                            DragDropEffects.All);
        }
    }
}

<UserControl x:Class="WPFTester.DragableUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             MouseMove="UserControl_MouseMove"
             >
    <Grid Width="100" Height="100" >
        <Border Background="SteelBlue" />
    </Grid>
</UserControl>

And finally, test it all:
<UserControl x:Class="WPFTester.DragControlTestPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFTester"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="450"
             >
    <Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <local:DropableCanvas Grid.Column="0" Background="LightSteelBlue" Height="200" Width="200" Margin="10" >
            <local:DragableUserControl Canvas.Left="10" Canvas.Top="10" />
        </local:DropableCanvas>
        <local:DropableCanvas Grid.Column="1" Background="LightSteelBlue" Height="200" Width="200" Margin="10" >
            <local:DragableUserControl Canvas.Left="10" Canvas.Top="10" />
        </local:DropableCanvas>
    </Grid>
</UserControl>

You should be able to drag and drop the two dragable usercontrols between the two canvases.

*Edit* 7/5/2011 Removed a couple unused fields from the DragableUserControl class...oops.

*Edit* 7/6/2011 Here's an example of dropping a new usercontrol of the same type as the dragged usercontrol instead of moving the dragged control. Just change the DropableCanvas.DropableCanvas_Drop method to this:
void DropableCanvas_Drop(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(typeof(DropableCanvasDragDropData)))
    {
        DropableCanvasDragDropData dragdropdata = e.Data.GetData(typeof(DropableCanvasDragDropData)) as DropableCanvasDragDropData;

        //// Remove usercontrol from its starting panel
        //dragdropdata.SourcePanel.Children.Remove(dragdropdata.UserControl);

        // Make a new usercontrol to drop
        UserControl newcontrol;
        try
        {
            newcontrol = Activator.CreateInstance(dragdropdata.UserControl.GetType()) as UserControl;
        }
        catch (Exception)
        {
            //**TODO** Handle this! For now, silent fail.
            newcontrol = null;
        }

        if (newcontrol != null)
        {
            // Position the usercontrol on this canvas at the drop point
            Point dropPoint = e.GetPosition(this);
            Canvas.SetLeft(newcontrol, dropPoint.X - dragdropdata.OffsetPoint.X);
            Canvas.SetTop(newcontrol, dropPoint.Y - dragdropdata.OffsetPoint.Y);

            // Add the usercontrol to this canvas
            this.Children.Add(newcontrol);
        }
    }
    e.Handled = true;
}
 
Share this answer
 
v5
Comments
KiranBabu M 6-Jul-11 9:43am    
Hi Mark Salsbery,
thats great..! both your solutions working perfectly.
thank u very much.
According to your solution we can able to drag and drop usercontrols between two canvases.
i just tried to remove this line
dragdropdata.SourcePanel.Children.Remove(dragdropdata.UserControl);
and changed Dragdropeffects.copy;
so that when we drag and drop it will copy the usercontrol to canvas(should not remove from source). its showing following error
" An exception of type System.invalidoperationException was thrown:\n Specified element is already the logical child of another element. Disconnect it first."
how can we drag and drop so that after drop usercontrol should be copied but not removed.

thanku once again
Mark Salsbery 6-Jul-11 17:03pm    
Yes, one control can't exist as the child of more than one element, so you'll need to provide a way to create a new usercontrol object on the drop target. How you do that is up to you depending on your implementation. You can add necessary info to the DropableCanvasDragDropData class if needed. For example, you could pass the usercontrol's type, and on drop, use Activator.CreateInstance() to create a new object of that type.
Mark Salsbery 6-Jul-11 17:14pm    
Actually the information is there in the example solution to create a new usercontrol easily. I've appended a modified version of the one method that needs to be changed to this solution - the drop event handler on the dropable canvas.
VK k 7-Jul-11 8:32am    
I started working with wpf nearly 2 months ago. I want to drag and drop multiple video clips from one control to another control in the sme window in WPF. i dont know how to do this and there is nop perfect solution in google on drag and drop for multiple video clips,
My requirement is on one control i have a button(for importing videos through openfile dialog box and displays in the control). after importing i want to drag and drop video clips on othercontrol.if i click on any video it should be able to ply in a mediaelement in the same window.

can u help me by posting similar solution.

thanks in advance,
Venkat



Mark Salsbery 8-Jul-11 13:11pm    
The built-in drag and drop functionality I used above is pretty generic. WPF doesn't care what's being dragged and dropped (unless you're using built-in dropdata types) so you're free to use what you want. If you take the above sample and understand how it works, then you can easily pass a collection of selected media objects in the DropableCanvasDragDropData class. THe drop target can do whatever with these - create mediaelements, put them in a listbox, etc...

Also see the link SA provided... Drag and Drop Overview[^]
Or start from the very very beginning....learning WPF fundamentals...

Windows Presentation Foundation[^]

Here's a simple example of a usercontrol that can be dragged on a canvas...
public partial class DragableUserControl : UserControl
{
    public DragableUserControl()
    {
        InitializeComponent();
    }

    bool inDrag = false;
    Point anchorPoint;

    private void UserControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (!inDrag)
        {
            anchorPoint = e.GetPosition(null);
            CaptureMouse();
            inDrag = true;
            e.Handled = true;
        }
    }

    private void UserControl_MouseMove(object sender, MouseEventArgs e)
    {
        if (inDrag)
        {
            Point currentPoint = e.GetPosition(null);
            Canvas.SetLeft(this, Canvas.GetLeft(this) + (currentPoint.X - anchorPoint.X));
            Canvas.SetTop(this, Canvas.GetTop(this) + (currentPoint.Y - anchorPoint.Y));
            anchorPoint = currentPoint;
            e.Handled = true;
        }
    }

    private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (inDrag)
        {
            ReleaseMouseCapture();
            inDrag = false;
            e.Handled = true;
        }
    }
}
<UserControl x:Class="WPFTester.DragableUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             MouseLeftButtonDown="UserControl_MouseLeftButtonDown"
             MouseMove="UserControl_MouseMove"
             MouseLeftButtonUp="UserControl_MouseLeftButtonUp"
             >
    <Grid Width="100" Height="100" >
        <Border Background="SteelBlue" />
    </Grid>
</UserControl>


*Edit* Here's an example to test the dragable usercontrol...
<UserControl x:Class="WPFTester.DragControlTestPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFTester"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             Height="300" Width="300" >
    <Grid >
        <Canvas Background="LightSteelBlue" >
            <local:DragableUserControl Canvas.Left="10" Canvas.Top="10" />
        </Canvas>
    </Grid>
</UserControl>
 
Share this answer
 
v4
Comments
KiranBabu M 5-Jul-11 3:00am    
hello Mark Salsbery,

thanks for ypur reply,i tried your simple example but it is not working!!!
Mark Salsbery 5-Jul-11 14:13pm    
Works fine for me. You have to actually put the control on a canvas....I have appended that sample usage code in my solution above...
Pete O'Hanlon 5-Jul-11 6:57am    
Rather than starting off a new thread, just explain what didn't work for you. I will delete the new question because it is adding no value - please amend the question here instead.
Perhaps you face a problem because you're trying to find the solution fitting your case exactly. This is not a very fruitful way because each design has its unique features; so perhaps all developers solve their own problem and share the result, no one may be solving exact your problem. In such cases, you need to start with basics.

You're not reporting any particular problem, just ask how to write this and that. This is all well known and documented, not like some other WPF aspects which can be documented obscurely.

I think there is no lack of documentation on the topic. Start from the very beginning: http://msdn.microsoft.com/en-us/library/ms742859.aspx[^].

—SA
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900