SIGN UP MEMBER LOGIN:    
ARTICLE

Drag n Drop an element from one Panel to another in Silverlight 3

Posted by Paru Articles | C# Language August 01, 2009
In this article we see the code to drag and drop an element from one panel to another in Silverlight.
Reader Level:
Download Files:
 


In this application we see the code to drag and drop an element from one panel to another.

Here we use two Stack Panels. One is the containing panel and the other is the dropping panel.

img1.gif

There are four items in the lower panel. We can drag and drop or a single click can also move objects from one panel to the other.

Now let us see how the code can be:

XAML

In the designer we have

The Visual tree of control is as in the figure below. The scroll bar can be used as the requirements and number of items in the Item slider.

img2.gif

The code is:

<
Canvas x:Name="LayoutRoot" Background="White" Height="534" Margin="0,0,-200,0" VerticalAlignment="Top">
<Canvas x:Name="ContainedCanvas" Background="#FFC7F2F6" Height="476" Width="832" Canvas.Left="8" Canvas.Top="8">

<StackPanel x:Name="itemSlider" RenderTransformOrigin="0.5,0.5" Orientation="Horizontal" HorizontalAlignment="Left">

<StackPanel.RenderTransform>

      <TransformGroup>

            <ScaleTransform/>

            <SkewTransform/>

            <RotateTransform/>

            <TranslateTransform/>

      </TransformGroup>

</StackPanel.RenderTransform>

<Image Source="images/Creek.jpg" Stretch="Fill" x:Name="item2" HorizontalAlignment="Left" Tag="draggable" 
VerticalAlignment
="Top"d:LayoutOverrides="HorizontalMargin"/>

<Image HorizontalAlignment="Left" x:Name="item1" Source="images/Autumn-Leaves.jpg" Stretch="Fill" Tag="draggable" VerticalAlignment="Top"/>

<Image Source="Images/Desert-Landscape.jpg" Stretch="Fill" x:Name="item3" Margin="10,0,0,0"  HorizontalAlignment="Left" Tag="draggable"VerticalAlignment="Top"/>

<Image Source="images/Forest-Flowers.jpg" Stretch="Fill" x:Name="item4" Margin="10,0,0,0"  HorizontalAlignment="Left" Tag="draggable"VerticalAlignment="Top"/>

                             

                        </StackPanel>

     

<StackPanel x:Name="DragToStackPanel" HorizontalAlignment="Left" Background="#FFEED6D6" Height="300" Width="830" Orientation="Horizontal"/>

           

            </Canvas>

      </Canvas>

Now you have the look of the application.

Next is the real interesting part the code behind that makes the whole thing possible.

Note:  Please note that all the draggable controls are tagged as "draggable"

Code Behind

The methods to be noted in each event

Event  Method  Functionality  Return
MouseLeftButtonDown  CaptureMouse  Sets mouse capture to a System.Windows.UIElement. Returns true if the object has mouse capture; otherwise, returns false.
MouseMove  No specific method of the UI element related to this event but keeps track of the position of the mouse
MouseLeftButtonUp  ReleaseMouseCapture  Removes mouse capture from a System.Windows.UIElement. After this call, typically no object holds mouse capture. 

Now let us see each event in detail.

MouseLeftButtonDown

public
 void objFrameworkElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
            
//Start Drag
          
FrameworkElement objFrameworkElement = (FrameworkElement)sender;
            objFrameworkElement.CaptureMouse();
            
// Set the starting point for the drag
            StartingDragPoint = e.GetPosition(objFrameworkElement);
            
// Remove the element from it's control and move it to the parent
            
// if it's Tag contains the words [draggable]
            
if (objFrameworkElement.Tag.ToString().Contains("draggable"))
            {
               ContainingParent = objFrameworkElement.Parent 
as Panel;
               ContainingParent.Children.Remove(objFrameworkElement);
                
this.LayoutRoot.Children.Add(objFrameworkElement);
                UpdateElementPosition(objFrameworkElement, e.GetPosition(
this.LayoutRoot));
            }
            objFrameworkElement.MouseMove += 
new MouseEventHandler(objFrameworkElement_MouseMove);
            objFrameworkElement.MouseLeftButtonUp += 
new MouseButtonEventHandler(objFrameworkElement_MouseLeftButtonUp);
}

MouseMove

void
 objFrameworkElement_MouseMove(object sender, MouseEventArgs e)
        {
            
FrameworkElement objFrameworkElement = (FrameworkElement)sender;
            
Canvas objCanvas = (Canvas)objFrameworkElement.Parent;
            
Point Point = e.GetPosition(objCanvas);
            UpdateElementPosition(objFrameworkElement, Point);

        }

Update-element-position method

private
 void UpdateElementPosition(FrameworkElement objFrameworkElement, Point Point)
        {
            
Canvas.SetLeft(objFrameworkElement, Point.X - StartingDragPoint.X);
            
Canvas.SetTop(objFrameworkElement, Point.Y - StartingDragPoint.Y);        }

MouseLeftButtonUp

void
 objFrameworkElement_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            
//Stop Drag
            
FrameworkElement objFrameworkElement = (FrameworkElement)sender;
            objFrameworkElement.ReleaseMouseCapture();
                  objFrameworkElement.Width=300;
                        objFrameworkElement.Height=300;
            objFrameworkElement.MouseMove -=
                
new MouseEventHandler(objFrameworkElement_MouseMove);
            objFrameworkElement.MouseLeftButtonUp -=
                
new MouseButtonEventHandler(objFrameworkElement_MouseLeftButtonUp);
            
// If it is an element marked [draggable]
            
// try to drop it on a panel stored in the colPanels collection
            
if (objFrameworkElement.Tag.ToString().Contains("draggable"))
            {
                
if (ContainingParent == itemSlider)
                {
                    DraggedToParent = DragToStackPanel;
                    objFrameworkElement.Width = 300;
                    objFrameworkElement.Height = 300;
                }
                
else
                {
                    DraggedToParent = itemSlider;
                    objFrameworkElement.Width = 200;
                    objFrameworkElement.Height = 150;
                }
                
// Grab the position of the element being dragged in relation to it's position on the
               
// main canvas and it's position in relation to the panel it may be dropped on
                
Point mousePos1 = e.GetPosition(DraggedToParent);
                
Point mousePos2 = e.GetPosition(objFrameworkElement);
                
// Remove the element from the main canvas
                
this.LayoutRoot.Children.Remove(objFrameworkElement);
                DraggedToParent.Children.Add(objFrameworkElement);
                
Canvas.SetLeft(objFrameworkElement, mousePos1.X - mousePos2.X);
                
Canvas.SetTop(objFrameworkElement, mousePos1.Y - mousePos2.Y);
            }
        }

By implementing these we can achieve the dragging of a UI element into a different panel.

Happy Coding!

Login to add your contents and source code to this article
share this article :
post comment
 

Hey,

I wanted to download the zip file but it is currupted.

Could you upload it again?

Thanks

Posted by Mateo yeye Oct 20, 2010

unable to extract as zip file is corrupted

Posted by sen eth Oct 12, 2010

what i need is to add a line or fade element between two elements to show the position that i'll drop to.
Here is the class

using System;

using System.Collections.Generic;

using System.Linq;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using System.Windows.Controls.Primitives;

using System.Diagnostics;

//////////////////////////////////////////////////////////////////

// //

//This code is provided As-Is and confers no rights. //

// //

//////////////////////////////////////////////////////////////////

namespace DragDropApplication

{

//This class allows UIElements to be dragged around and to be dropped into another Panel.

//Elements which need to able to be dragged should be registered as draggable by calling the

//RegisterDraggable method. Panels which are to have elements dragged into them should be

//registered as drop targets by calling RegisterDropTarget.

//As it stands, there are a number of limitations with this implementation:

//1. The logic does not take into account RenderTransforms applied to either elements or Panels.

//2. If multiple drop target panels overlap at a point where an element is dropped, the DragDropManager

// will drop the element into the first Panel it finds, which may or may not be the Panel which is

// rendered above the others.

//3. Most Controls will be unusable while they are registered as draggable, since the

// MouseLeftButtonDown event handler removes the element from the tree and re-adds it. Controls

// should be unregistered for normal use.

//4. All draggable elements must be inside Panels (not UserControls, Broders, ListBoxes, etc).

//All of the above limitations could be fixed reasonably easily with modifications to be below code.

public class DragDropManager

{

public delegate void DragComplete(object sender, object target, EventArgs e, bool registerEvent);

public event DragComplete DragSuccessful;

//A list of Panels which can have elements dragged into them

private List<Panel> dropTargets = new List<Panel>();

//This Canvas is used to hold elements while they are being dragged.

private Canvas topCanvas;

//This is the point on the element by which it is being dragged

private Point grabPoint;

//if the element is not dragged into a valid drop target, then it is

//placed back to where it was originally. These variables are required

//to restore the element to its previous location.

private double backupCanvasLeft, backupCanvasTop;

private int backupChildIndex;

private Panel backupParent;

public DragDropManager(Canvas topCanvas)

{

this.topCanvas = topCanvas;

}

public void RegisterDraggable(UIElement element)

{

element.MouseLeftButtonDown += ElementMouseLeftButtonDown;

}

public void UnRegisterDraggable(UIElement element)

{

element.MouseLeftButtonDown -= ElementMouseLeftButtonDown;

}

public void RegisterDropTarget(Panel panel)

{

dropTargets.Add(panel);

}

public void UnRegisterDropTarget(Panel panel)

{

if (dropTargets.Contains(panel))

{

dropTargets.Remove(panel);

}

}

//Start draqgging the element

private void ElementMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

{

FrameworkElement element = sender as FrameworkElement;

Panel parent = element.Parent as Panel;

if (parent!= null && element.CaptureMouse())

{

element.MouseLeftButtonUp += ElementMouseLeftButtonUp;

element.MouseMove += ElementMouseMove;

backupChildIndex = parent.Children.IndexOf(element);

backupCanvasLeft = Canvas.GetLeft(element);

backupCanvasTop = Canvas.GetTop(element);

backupParent = parent;

parent.Children.Remove(element);

topCanvas.Children.Add(element);

topCanvas.UpdateLayout();

grabPoint.X = element.ActualWidth /2;

grabPoint.Y = element.ActualHeight /2;

UpdateElementPosition(element, e.GetPosition(topCanvas));

}

}

private void ElementMouseMove(object sender, MouseEventArgs e)

{

Point point = e.GetPosition(topCanvas);

UpdateElementPosition(sender as FrameworkElement, point);

}

private void UpdateElementPosition(FrameworkElement element, Point mousePoint)

{

Canvas.SetLeft(element, mousePoint.X - grabPoint.X);

Canvas.SetTop(element, mousePoint.Y - grabPoint.Y);

}

//End the dragging operation.

private void ElementMouseLeftButtonUp(object sender, MouseButtonEventArgs e)

{

FrameworkElement element = sender as FrameworkElement;

element.ReleaseMouseCapture();

element.MouseLeftButtonUp -= ElementMouseLeftButtonUp;

element.MouseMove -= ElementMouseMove;

//Try to find a Panel to insert the element into.

//The following code is the source of limitation #2 listed above.

//Instead of checking the ActualWidth and ActualHeight of the Panel,

//the UIElement.HitTest method could be used, which can be used to determine

//which Panel is above all others at the specified point.

//However, this method would require all targets to have a non-null Background set;

//the hit-test works against the visuals in the tree.

bool foundTargetPanel = false;

int index = 0;

while (index < dropTargets.Count && !foundTargetPanel)

{

Panel panel = dropTargets[index];

//Get the moue position relative to the Panel:

Point mousePos = e.GetPosition(panel);

if (mousePos.X >= 0 && mousePos.Y >= 0

&& mousePos.X <= panel.ActualWidth && mousePos.Y <= panel.ActualHeight)

{

topCanvas.Children.Remove(element);

AddElementToPanel(element, panel, mousePos);

foundTargetPanel = true;

DragSuccessful(element, panel, new EventArgs(), false);

}

index++;

}

//if valid drop target Panel is not found, restore the element to its original location

if (!foundTargetPanel)

{

topCanvas.Children.Remove(element);

Canvas.SetLeft(element, backupCanvasLeft);

Canvas.SetTop(element, backupCanvasTop);

backupParent.Children.Insert(backupChildIndex, element);

}

}

private void AddElementToPanel(FrameworkElement element, Panel panel, Point point)

{

if (panel is StackPanel)

{

AddElementToStackPanel(element, panel as StackPanel, point);

}

else if (panel is Grid)

{

AddElementToGrid(element, panel as Grid, point);

}

else if (panel is Canvas)

{

AddElementToCanvas(element, panel as Canvas, point);

}

else

{

panel.Children.Add(element);

}

}

private void AddElementToCanvas(FrameworkElement element, Canvas canvas, Point point)

{

Canvas.SetLeft(element, point.X - grabPoint.X);

Canvas.SetTop(element, point.Y - grabPoint.Y);

canvas.Children.Add(element);

}

private void AddElementToGrid(FrameworkElement element, Grid grid, Point point)

{

//Determine the correct Row and Column to insert the element into.

int column = 0;

int row = 0;

double y = 0;

double x = 0;

while (column < grid.ColumnDefinitions.Count)

{

x += grid.ColumnDefinitions[column].ActualWidth;

if (x > point.X)

{

break;

}

column++;

}

while (row < grid.RowDefinitions.Count)

{

y += grid.RowDefinitions[row].ActualHeight;

if (y > point.Y)

{

break;

}

row++;

}

grid.Children.Add(element);

Grid.SetColumn(element, column);

Grid.SetRow(element, row);

}

private void AddElementToStackPanel(FrameworkElement element, StackPanel stackPanel, Point point)

{

//Determine the correct index to insert the element into the StackPanel

int index = 0;

if (stackPanel.Orientation == Orientation.Vertical)

{

double y = 0;

while (index < stackPanel.Children.Count)

{

var child = stackPanel.Children[index];

var slot = LayoutInformation.GetLayoutSlot(child as FrameworkElement);

y = slot.Bottom - (child as FrameworkElement).Margin.Bottom;

if (y > point.Y)

{

break;

}

index++;

}

}

else

{

double x = 0;

while (index < stackPanel.Children.Count)

{

var child = stackPanel.Children[index];

var slot = LayoutInformation.GetLayoutSlot(child as FrameworkElement);

x = slot.Right - (child as FrameworkElement).Margin.Right;

if (x > point.X)

{

break;

}

index++;

}

}

stackPanel.Children.Insert(index, element);

}

private void AddElementToStackPanel2(FrameworkElement element, StackPanel stackPanel, Point point)

{

//Determine the correct index to insert the element into the StackPanel

int index = 0;

if (stackPanel.Orientation == Orientation.Vertical)

{

double y = 0;

while (index < stackPanel.Children.Count-1)

{

var child = stackPanel.Children[index];

var slot = LayoutInformation.GetLayoutSlot(child as FrameworkElement);

y = slot.Bottom - (child as FrameworkElement).Margin.Bottom;

if (y > point.Y)

{

break;

}

index++;

}

}

else

{

double x = 0;

while (index < stackPanel.Children.Count)

{

var child = stackPanel.Children[index];

var slot = LayoutInformation.GetLayoutSlot(child as FrameworkElement);

x = slot.Right - (child as FrameworkElement).Margin.Right;

if (x > point.X)

{

break;

}

index++;

}

}

//stackPanel.Children.Insert(index, element);

}

}

}




thank you so much

Posted by Bashar Belbeisi Oct 08, 2009

Thank you for the comments.
I have for the time being only tracking the position of the of the mouse on the canvs and reseting the position of the dragging object as well.

If you need to set the dragg toParent at the mouse move then please  include the code

if (ContainingParent == itemSlider)
                {
                    DraggedToParent = DragToStackPanel;
                    objFrameworkElement.Width = 300;
                    objFrameworkElement.Height = 300;
                }
                
else
                {
                    DraggedToParent = itemSlider;
                    objFrameworkElement.Width = 200;
                    objFrameworkElement.Height = 150;
                }
                
// Grab the position of the element being dragged in relation to it's position on the
               
// main canvas and it's position in relation to the panel it may be dropped on
                
Point mousePos1 = e.GetPosition(DraggedToParent);
                
Point mousePos2 = e.GetPosition(objFrameworkElement);
                
// Remove the element from the main canvas
                
this.LayoutRoot.Children.Remove(objFrameworkElement);
                DraggedToParent.Children.Add(objFrameworkElement);
                
Canvas.SetLeft(objFrameworkElement, mousePos1.X - mousePos2.X);
                
Canvas.SetTop(objFrameworkElement, mousePos1.Y - mousePos2.Y);

In the mouse move it self....
Dont get worried once your click on the object in the irst panel itself it moves to the second panel. If yu need the dragging effect then mouse move can help.

Please let me know if you are answered.

Posted by Paru Oct 08, 2009

on mousemove how can i mark the dropping place while dragging before dropping to show where am gonna drop the item?

Posted by Bashar Belbeisi Oct 08, 2009
Become a Sponsor
PREMIUM SPONSORS
  • ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
    The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
Nevron Gauge for SharePoint
Become a Sponsor