Another new feature of Silverlight 4 that will enable developers to build richer UIs is drag-and-drop file support. In Silverlight 3, you had to pop up an OpenFileDialog to allow the user to select files from the local file system and make them available to a Silverlight application. In Silverlight 4, OpenFileDialog still works, but there is an alternative: let the user drag files from the operating system shell and drop them into a Silverlight application. The app can then consume the files in much the same way that it consumes files offered through OpenFileDialog.
To demonstrate the mechanics of Silverlight drop targeting, I built a sample that lets you open image files using drag-and-drop. Here's what the app looked like after I grabbed a bunch of JPEGs from My Pictures and dropped them into the running application:
At startup, the application registers a handler for the new Drop event attached to the UIElement class, making the LayoutRoot Grid a drop target:
// Register a handler for Drop events
LayoutRoot.Drop += new DragEventHandler(LayoutRoot_Drop);
When one or more files are dropped into the Grid, LayoutRoot_Drop inserts the FileInfo objects representing the dropped files into a System.Collections.Generic.Queue:
// Queue the FileInfo objects representing dropped files
if (e.Data != null)
{
FileInfo[] files = e.Data.GetData(DataFormats.FileDrop) as FileInfo[];
foreach (FileInfo fi in files)
{
_files.Enqueue(fi);
}
}
Later, a CompositionTarget.Rendering event handler dequeues the FileInfo objects and processes them one at a time (one FileInfo object per CompositionTarget.Rendering event), turning them into XAML Image objects with Borders around them:
if (_files.Count != 0)
{
// Create a photo
FileInfo fi = _files.Dequeue();
CreatePhoto(fi);
}
The reason for using CompositionTarget.Rendering is that images have to be decoded and created on the application's UI thread. By processing one FileInfo object and returning, the event handler hands control back to Silverlight so the rendering engine can render the photo that was just added to the scene.
To enable applications to support drag-and-drop, Silverlight 4 adds four new events named DragEnter, DragOver, Drop, and DragLeave to the UIElement class. Therefore, any visual element can be a drop target. In non-Silverlight applications, you can use the IDataObject passed to these event handlers to determine what type of data is being offered. In Silverlight, however, you can only query the IDataObject in handlers for Drop events. Still, you could use the other events to perform drop-target highlighting or other UI-related chores when a cursor carrying a payload enters a drop target.
Another facet of the drag-and-drop story is the new UIElement.AllowDrop property. In order for an object to accept drops, this property must be set to true. That's why my sample application declares the LayoutRoot grid this way:
<Grid x:Name="LayoutRoot" AllowDrop="True">
You can download the source code and try it for yourself. Have fun dropping files!
On Nov 26 2009 6:26 AMBy jprosise
Jeff, great example. Just a quick note: Drag and Drop support is available even on sandboxes applications (in-browser).
Cheers!
AFAIK Drag & Drop is not limited to OOB applications nor it requires permissions elevation.
You are so right! I've updated the text (and the download) accordingly.
Introduction Some years ago (pre-silverlight times) a client ask me for a weird requirement…he wanted
Thank you for sharing all this great information
good tutorial
Thanks for the demo Jeff, this is a great new feature of Silverlight 4!
Very Nice Sample
Can you give a sample code for Drag Drop Files from Silverlight to Filesystem too?
It's the way reverse
What`s right way to do this, if I have Navigation Silverlight 4 App and I don`t want that whole application has drag and drop feature.
I have only one page that could be drop area. Problem is that only mainpage is getting drop event even I enabled it in contained page and grid inside that page.
Thanks for the great post and demo app.
Great article, Please add google Plus icon to plus one it publicly. Very illustrative and working demo. Nice...
In my application I am invoking a PopUp by
Popup pop = new Popup; then i add this:: pop.child(page); where "page" is the instance of a XAML page which is of type ChildWindow. Now when the popup shows up on my MainPage, it becomes Non-Modal just like I want it to be!! But the problem is, the popup window is not draggable through out the Mainpage. I know that the popup appears within the Boundaries of a Silverlight control hosted in a browser. And It's not a true window. But still my popup is not draggable within its boundaries.. Am i missing some declarations which define the draggable region of a popup control OR is it the ChildWindow which needs to be configured ??
I am having a fair degree of difficulty playing video off of the client's machine. I thought maybe you would know how to do this given your ability to do it with pictures. Here is my code that appears to fail:
http://stackoverflow.com/questions/9649164/silverlight-dynamically-play-video-from-clients-machine
I believe that it may be a problem with video needing to be "resourced" before it can be played.
Thank you very much in advance.