Nov 28, 2009

Silverlight Drag and Drop API

Introduction

Drag and drop is a common UX paradigm and a top requested feature. In Silverlight 4 Beta, we introduced a basic set of API to enable the most common scenario of dragging pictures files and dropping them to Silverlight applications, and we designed the API to allow us to expose more drag and drop functionalities down the road without API change, hopefully.

API

Below is the core of the new API:

namespace System.Windows
{
public abstract class UIElement : DependencyObject
{
// Fields
public static readonly DependencyProperty AllowDropProperty;

// Events
public event DragEventHandler DragEnter;
public event DragEventHandler DragLeave;
public event DragEventHandler DragOver;
public event DragEventHandler Drop;

// Properties
public bool AllowDrop { get; set; }
}

public delegate void DragEventHandler(object sender, DragEventArgs e);

public sealed class DragEventArgs : RoutedEventArgs
{
// Methods
public Point GetPosition(UIElement relativeTo);

// Properties
public IDataObject Data { [SecuritySafeCritical] get; }
public bool Handled { get; set; }
}
}

namespace System.Windows.Controls
{
public abstract class Control : FrameworkElement
{
protected virtual void OnDragEnter(DragEventArgs e);
protected virtual void OnDragLeave(DragEventArgs e);
protected virtual void OnDragOver(DragEventArgs e);
protected virtual void OnDrop(DragEventArgs e);
}
}

  • AllowDrop: this is dependency property, indicating whether an element is a drop target.
  • DragEnter, DragLeave, DragOver & Drop: these are routed events. They bubble up, and fire only on elements with AllowDrop set to true.
  • OnDragEnter, OnDragLeave, OnDragOver & OnDrop: these are protected virtual functions for subclasses to override. 
  • DragEventArgs: this class allows drop target event handlers or method overrides to access the data being dragged or dropped.

Usage

There are primarily two ways to use Silverlight’s drag and drop API:

  • Silverlight applications can handle those drop target events and process the files dropped in the event handlers.
  • Silverlight controls can override those drop target virtual functions to process the data being dragged and dropped, and enable themselves to be drop targets.

Limitations

The drag and drop functionality shipped in Silverlight 4 Beta only enables the most common scenario: Silverlight plugin as a file drop target. Please notice the following limitations with current implementation:

  • there is no drop source support (QueryContinueDrag & GiveFeedback).
  • there is no DragDropEffects or DragDropKeyStates in DragEventArgs.
  • there is no visual for the dragged object or DragDropEffects.
  • only file drag and drop is supported:
    • all drop target events fire only when files are being dragged and dropped.
    • IDataObject, DataObject and DragEventArgs.Data support only one format: “FileDrop”, and the data is of type FileInfo[].
  • most of IDataObject methods throw NotImplementedException.
  • for drag and drop to work on Windows, Silverlight plugin must be windowed. In another word, if <param name="windowless" value="true"/> is specified, drop events won’t fire.
  • since Silverlight plugin on Mac is always windowless, you need to hook up JavaScript drop events to trigger Silverlight drop events. In another word, if you want your Silverlight application to support file drop on Mac as well as Windows, you will need to add following script and Silverlight plugin attributes to the hosting html or aspx page:
    <!-- add following script before end of HEAD tag -->
    <script type="text/javascript">
    function handleDragEnter(oEvent) {
    // Prevent default operations
    oEvent.preventDefault();

    var flag = silverlightControl.dragEnter(oEvent);

    // If we handled it successfully then stop propagation of the event
    if (flag)
    oEvent.stopPropagation();
    }

    function handleDragLeave(oEvent) {
    // Prevent default operations
    oEvent.preventDefault();

    var flag = silverlightControl.dragLeave(oEvent);

    // If we handled it successfully then stop propagation of the event
    if (flag)
    oEvent.stopPropagation();
    }

    function handleDragOver(oEvent) {
    // Prevent default operations
    oEvent.preventDefault();

    var flag = silverlightControl.dragOver(oEvent);

    // If we handled it successfully then stop propagation of the event
    if (flag)
    oEvent.stopPropagation();
    }

    function handleDropEvent(oEvent) {

    // Prevent default operations
    oEvent.preventDefault();

    var flag = silverlightControl.dragDrop(oEvent);

    // If we handled it successfully then stop propagation of the event
    if (flag)
    oEvent.stopPropagation();
    }
    </script>
    <!-- use JavaScript drop target events to trigger Silverlight's drop target events -->
    <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"
    id="silverlightControl" ondragenter="handleDragEnter(event)" ondragover="handleDragOver(event)"
    ondragleave="handleDragLeave(event)" ondrop="handleDropEvent(event)" >


  • DragEventArgs.Data is only accessible in Drop event. Accessing DragEventArgs.Data in DragEnter, DragOver and DragLeave may cause SecurityException. And accessing Directory, DirectoryName or FullName property of the FileInfo object from DragEventArgs.Data may cause ArgumentNullException. 

    Demo App

    Below is a demo app:
  • the top left nested grids use drop target event handler to display DragEventArgs info.
  • the top right nested grids contain an ImageDropTarget user control, which overrides OnDrop method to render the dropped file if it is an image.
  • the bottom listbox shows the sequence of drop target events, their bubbling up, and DragEventArgs info.
    DragDropDemo

    you can find the complete source here.

    Feedback

    While we are excited to add drag and drop to Silverlight, we know there are a lot to finish/improve, and what we released is just a Beta. As always, your feedback is highly appreciated, and will be used as an important data point to help us prioritize the work. Thanks!

     

    Technorati Tags: ,