Silverlight Drag, Drop, Import , and Export: By Michael Washington 17

Note: This article is submitted by Michael for Silverlight 2 Beta 2 – Articles Competition.Thanks a lot, Michael!
Hello All, I would like to remind you that our contest will be closed on 25th July, 2008 so please get writing and submit your great article as soon as possible. You will get a chance to win cool prizes. Your articles will be read by a lot of Silverlight fans and you will be recognized by our Silverlight community. Plus, we will drive some traffic to your site. This contest is sponsored by SilverlightShow.net and Silverlight 2 in Action.

Contents

  • Silverlight Drag, Drop, Import , and Export
  • The Code
  • Creating the Windows
  • The ImportContent Method
  • Summary
  • Author Bio

Download ~

UPDATE: SourceCode: SilverlightDragAndDrop_new.zip(627 KB)

SourceCode: SilverlightDragDropImportAndExport.zip (618 KB)
Live Demo : Silverlight Drag and Drop/Import and Export Demo

Silverlight Drag, Drop, Import , and Export

The example is based on an earlier drag and drop code sample that was based on an example created by Keith Mahoney. In his example he shows how to drag and drop various types of elements into various types of Panels. In this example we only cover dragging and dropping an element onto a Canvas. We also cover importing and exporting content from one user control into another.

When you view the sample you see three movable windows (you grab the colored bar on the top of the window to drag it) with three boxes in the first window.

The “Drag Me” box can only be dragged inside the window, but the blank box and the “Drag Me Outside” box can be dragged anywhere on the screen.

To determine the different behavior of the boxes, the word “[draggable]” is added to the Tag property of the element that will be draggable outside the window. When an element with that Tag is detected, the element is removed from the Canvas it is currently on and placed on the root Canvas of the application while it is being dragged.

When the element is dropped a HitTest is performed to see if the mouse is currently in the bounds of a Canvas element that is in one of the windows. If it is in the bounds, the element is removed from the root Canvas and placed onto the Canvas that is in the respective window.

If the boxes are dragged inside another window, they will remain in the window and move with that window when that window is moved.

The window labeled “Drop Items Here” implements a “ImportContent” interface that allows content to be possibly imported and parsed rather than simply added to the window. When the blank box is dragged onto the window labeled “Drop Items Here”, the box is simply added to the window.

However, when the box labeled “Drag Me Outside and Export Me” is dragged onto the window labeled “Drop Items Here”, the TextBlocks in the box are parsed and their content is added to the TextBlock in the window.

The Code

The solution file contains a Silverlight project and a web project to display the Silverlight project output. The following describes the files in the SilverlightDragAndDrop project:

  • Page.xaml – This is the main control that is displayed by the web project. This control creates windows using the SilverlightWindowControl control and inserts the contents of the SilverlightCanvas controls. It also create handlers to handle the drag and drop of the elements and calls the ImportContent method if it exists on the panel an element is being dropped on.
  • SilverlightCanvas1.xaml -  This control implements an ImportContent interface and a TextBox to display any imported content.
  • SilverlightCanvas2.xaml -  This control simply contains a blank Canvas that elements can be placed on.
  • SilverlightObjects.xaml -  This control contains three elements that can be dragged and dropped.
  • SilverlightWindowControl.xaml – This control is used by the Page.xaml control to create the windows the other controls are placed into.
  • Interfaces.cs – This contains an interface called ImportContent that the SilverlightCanvas1.xaml control implements to import content.

Creating the Windows

The Page.xaml control creates the three windows and a list of panels that elements can possibly be dragged onto. It will perform a HitTest to determine if an element is being dragged onto one of the panels.


public Page()
{
InitializeComponent();

// Window #1 - Contains objects
SilverlightWindowControl objSilverlightWindowControl = new SilverlightWindowControl(50);
// Pass an instance of this control to the child control. This will allow the child to
// wire-up mouse events to the parent.
SilverlightObjects SilverlightObjects = new SilverlightObjects(this);
objSilverlightWindowControl.Window.Content = SilverlightObjects;
Canvas.SetLeft(objSilverlightWindowControl, (double)50);
Canvas.SetTop(objSilverlightWindowControl, (double)50);

// SilverlightCanvas1 - Implements the "ImportContent" Interface
SilverlightWindowControl objBlankSilverlightWindowControl1 = new SilverlightWindowControl(60);
SilverlightCanvas1 objSilverlightCanvas1 = new SilverlightCanvas1();
objBlankSilverlightWindowControl1.Window.Content = objSilverlightCanvas1;
Canvas.SetLeft(objBlankSilverlightWindowControl1, (double)300);
Canvas.SetTop(objBlankSilverlightWindowControl1, (double)50);

// SilverlightCanvas2 - Does NOT implement the "ImportContent" Interface
SilverlightWindowControl objBlankSilverlightWindowControl2 = new SilverlightWindowControl(60);
SilverlightCanvas2 objSilverlightCanvas2 = new SilverlightCanvas2();
objBlankSilverlightWindowControl2.Window.Content = objSilverlightCanvas2;
Canvas.SetLeft(objBlankSilverlightWindowControl2, (double)300);
Canvas.SetTop(objBlankSilverlightWindowControl2, (double)310);

// Add Canvases to a collection that will be checked as possible drop points
colPanels.Add(SilverlightObjects.LayoutRoot);
colPanels.Add(objSilverlightCanvas1.LayoutRoot);
colPanels.Add(objSilverlightCanvas2.LayoutRoot);

// Add Windows to the Page
this.LayoutRoot.Children.Add(objSilverlightWindowControl);
this.LayoutRoot.Children.Add(objBlankSilverlightWindowControl1);
this.LayoutRoot.Children.Add(objBlankSilverlightWindowControl2);
}

The SilverlightObjects.xaml control uses an instance of the parent control to wire-up the mouse events to detect when an element is being dragged.


public SilverlightObjects(Page objPage)
{
InitializeComponent();

// Add delegates to the parent to allow it to handle the drag and drop
FrameworkElement objFrameworkElement1 = (FrameworkElement)this.DragElement1;
objFrameworkElement1.MouseLeftButtonDown +=
new MouseButtonEventHandler(objPage.objFrameworkElement_MouseLeftButtonDown);
FrameworkElement objFrameworkElement2 = (FrameworkElement)this.DragElement2;
objFrameworkElement2.MouseLeftButtonDown +=
new MouseButtonEventHandler(objPage.objFrameworkElement_MouseLeftButtonDown);
FrameworkElement objFrameworkElement3 = (FrameworkElement)this.DragElement3;
objFrameworkElement3.MouseLeftButtonDown +=
new MouseButtonEventHandler(objPage.objFrameworkElement_MouseLeftButtonDown);
}

Note, the only way to get an instance of the parent control when a control has been dynamically added is to pass an instance of that parent to the control when the control is added. The mouse events must be attached to, and handled by, the parent not the child control for the communication between windows to work.

When the mouse starts to drag an element, the element is checked to see if it’s tag contains “[draggable]“. If it does, the element is removed from the Canvas it is on and placed on the main Canvas.


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]"))
{
Panel objParent = objFrameworkElement.Parent as Panel;
objParent.Children.Remove(objFrameworkElement);

this.LayoutRoot.Children.Add(objFrameworkElement);
MoveToTop(objFrameworkElement);
UpdateElementPosition(objFrameworkElement, e.GetPosition(this.LayoutRoot));
}

objFrameworkElement.MouseMove += new MouseEventHandler(objFrameworkElement_MouseMove);
objFrameworkElement.MouseLeftButtonUp += new MouseButtonEventHandler(objFrameworkElement_MouseLeftButtonUp);
}

The code to move an element being dragged is the same whether or not the element has been moved to the main Canvas or not.


#region 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);
}
#endregion

When an element is dropped, this code is used to determine if the element will simply be placed inside a control, or if the ImportContent method will be called:


#region MouseLeftButtonUp
void objFrameworkElement_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
//Stop Drag
FrameworkElement objFrameworkElement = (FrameworkElement)sender;
objFrameworkElement.ReleaseMouseCapture();

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]"))
{
Point tmpPoint = e.GetPosition(null);
// Build a list of elements at the current mouse position
List<UIElement> hits = (List<UIElement>)this.HitTest(tmpPoint);
// Loop through all the Panels in the colPanels collection
foreach (Panel objPanel in colPanels)
{
if (hits.Contains(objPanel))
{
// Grab the position of the element being dragged in relation to it's                position on the
// main canvas and its position in relation to the panel it may be dropped on
Point mousePos1 = e.GetPosition(objPanel);
Point mousePos2 = e.GetPosition(objFrameworkElement);

// Remove the element from the main canvas
this.LayoutRoot.Children.Remove(objFrameworkElement);

// Import content
// Get a reference to the parent of the current panel
UserControl objUserControl = (UserControl)objPanel.Parent;
// See if that parent implements an interface called "ImportContent"
object objObject = objUserControl.GetType().GetInterface("ImportContent", true);

// If the object is not null then the parent object has a method             called "ImportContent"
if (!(objObject == null))
{
// Create a parmeters array
object[] parameters = new object[1];
// Add the elemnt that is being dragged to the array
parameters.SetValue(objFrameworkElement, 0);
// invoke the "ImportContent" on the parent object passing the parameters array that
// contains the element being dragged
bool boolImport = (bool)objUserControl.GetType().InvokeMember("ImportContent",
BindingFlags.InvokeMethod, null, objUserControl, parameters);

// If the import was not successful simply add the element to the panel
if (!boolImport)
{
// Add the element to the panel
objPanel.Children.Add(objFrameworkElement);
Canvas.SetLeft(objFrameworkElement, mousePos1.X - mousePos2.X);
Canvas.SetTop(objFrameworkElement, mousePos1.Y - mousePos2.Y);
}
}
else
{
// The parent object does not implement the "ImportContent" Interface
// Add the element to the panel
objPanel.Children.Add(objFrameworkElement);
Canvas.SetLeft(objFrameworkElement, mousePos1.X - mousePos2.X);
Canvas.SetTop(objFrameworkElement, mousePos1.Y - mousePos2.Y);
}
break;
}
}
}
}
#endregion

The ImportContent Method

Each control determines what content it will import. The control must implement an interface called ImportContent that accepts a FrameworkElement as a single parameter and returns a bool:


interface ImportContent
{
bool ImportContent(FrameworkElement objFrameworkElement);
}

In this example the SilverlightCanvas1.xaml control is coded to only import text from any TextBlocks.


#region ImportContent
public bool ImportContent(FrameworkElement objFrameworkElement)
{
// This import method will only import text content contained
// in TextBlocks that are placed on a Canvas

StringBuilder StringBuilder = new StringBuilder();
Canvas objCanvas = objFrameworkElement as Canvas;

// If the element being imported is not a canvas return false
if (objCanvas == null)
{
return false;
}

try
{
// Loop through all the UIElements in the Canvas
foreach (UIElement objUIElement in objCanvas.Children)
{
// Try to cast the UIElement as a TextBlock
TextBlock objTextBlock = objUIElement as TextBlock;
if (objTextBlock != null)
{
// Add the contents of the TextBlock to the output
StringBuilder.Append(String.Format(" {0}", objTextBlock.Text));
}
}
}
catch
{
return false;
}

// Was content in the output ?
if (StringBuilder.Length > 0)
{
// Add output to the Textbox display
this.txtContent.Text = StringBuilder.ToString();
return true;
}
else
{
return false;
}
}
#endregion

Summary

This example demonstrates a method for dealing with the “unknown”. With SilverlightDesktop, modules can be created by different developers that have no knowledge of each other, yet using a method such as this, content can be exported and imported between them.

Author: Michael Washington

Michael Washington is a website developer and an ASP.NET, C#, and Visual Basic programmer. He is has been named Microsoft MVP in ASP.NET for two straight years. He is a DotNetNuke Core member and has served for over three years. He is the author of the module development chapter in Building Websites with VB.NET and DotNetNuke 4 (Packt Publishing).

He has a son, Zachary and resides in Los Angeles with his wife Valerie.

17 thoughts on “Silverlight Drag, Drop, Import , and Export: By Michael Washington

  1. Reply ImportChina Jul 20,2008 8:32 am

    Great info – keep up the great work.

  2. Pingback: Post: 147 - Mirrored Blogs

  3. Reply Rick Jul 24,2008 2:56 pm

    hello,

    Thank you for a really nice piece of code. One question though; where is picture.jpg (SilverlightWindowControl.xaml tag) coming from? I can’t seem to figure this part out?

    I am getting a “4001 Image Error” which I suspect is because this resource is missing.

    Thanks,

    Rick

  4. Reply MIchael Washington Jul 24,2008 7:03 pm

    The picture.jpg that is in the SilverlightWindowControl.xaml is an error because I copied code from another one of my projects. Simply remove this tag.

  5. Reply Kate Jul 28,2008 8:55 am

    Thanks for sharing, this was exactly what I needed.

  6. Reply nirav Aug 20,2008 4:33 am

    Hi Nice Control.
    Its really very finest of work i have seen in SL.I am currently developing a application in MVC.I want to use this drag & drop control of yours.Plz brief me how can i use it without complicancy.
    Hope you wud reply soon.Bye.

  7. Reply Michael Washington Aug 20,2008 8:14 am

    Thank you for te feedback. There should be nothing that you would have to change to make this work with MVC.

  8. Reply nirav Aug 22,2008 2:48 am

    Thanks for that.
    Can you tell me if you have any idea or have writen any blog/article on HttpWebRequest in C# SilverLIght Application.As I had to do a app,in which task is to post data to server through C# helper class.Please reply if you hv any idea.Have a nice time there.

  9. Reply Keith Yerian Oct 1,2008 6:57 am

    This is a really nice piece of work if you are trying to understand dragging and dropping componenets in Silverlight.

    I converted the example to VB.Net for those of you interested.

  10. Reply Stephen Korow Nov 6,2008 6:01 pm

    keith,

    I would be interested in getting the VB.Net version. Can you please send me a zip of it. Thanks.

    Stephen
    skorow@pixi.com

  11. Reply Ted.o Nov 23,2008 3:14 am

    nice of work! Thank you, just what i needed (-: !!!

  12. Reply Michael Sync Nov 23,2008 3:27 am

    The new sample has been uploaded.

  13. Reply scrumwall Feb 5,2009 3:14 pm

    Take a look at the Scrumwall app at http://www.scrumwall.com/scrumwall.aspx for drag and drop. The application demonstrates other silverlight features such as custom datagrid header and event callback.

  14. Reply brenden Jun 3,2009 6:29 am

    I get a build error:

    Error 1 ‘SilverlightDragAndDrop.Page’ does not contain a definition for ‘HitTest’ and no extension method ‘HitTest’ accepting a first argument of type ‘SilverlightDragAndDrop.Page’ could be found (are you missing a using directive or an assembly reference?) C:\QMS_ROOT\VS_PROJECTS\SilverDragDrop\SilverlightDragAndDrop\Page.xaml.cs 132 62 SilverlightDragAndDrop

  15. Reply Michael Washington Jun 5,2009 9:28 am

    If you are using Silverlight 3 you may get errors. this was never tested on Silverlight 3

  16. Reply Ramesh Jul 2,2010 12:07 am

    Hi michael,

    its very use full to my project. can you explain me i have one scanario.

    if the user will drag and drop some where in the page. i have to store the position like Top,Left,width,height.
    can you give me the suggestion how can do it.

    i have regenerate page what are the dragged item by user with top,left,height,width. (This is solved).

Leave a Reply