Thursday, October 28, 2010

How to support drag’n’drop with Silverlight on Mac

Silverlight 4 introduced support for drag and drop. That is, developers have access to files like images or videos that are dropped into Silverlight-based web application.

Unfortunately, as discussed in this thread, this capability does not work very well on a Mac. The issue is described briefly in this MSDN article but this post will provide a easily to implement (and painless) workaround.

These changes only affect the HTML page hosting the Silverlight control.  You do not need to make any change to your Silverlight project.

To start, add the text highlighted below.

<body>
    <form id="form1" runat="server" style="height:100%">
   
<div id="silverlightControlHost">
       
<object id="plugin" data="data:application/x-silverlight-2," ...
            <param name="source" value="..."/>
           
<param name="onError" value="onSilverlightError" />
           
<param name="onLoad" value="onSilverlightLoad" />
           
<param name="background" value="white" />
           
<param name="minRuntimeVersion" value="4.0.50826.0" />
           
<param name="autoUpgrade" value="true" />
           
<a href="http://go.microsoft.com/fwlink/...
               
<img src="http://go.microsoft.com/fwlink/...
           
</a>
       
</object><iframe id="_sl_historyFrame" style=...
   
</form>
</body>
</html>

Next, immediately below the boilerplate “onSilverlightError” JavaScript function, append the following six functions.

function onSilverlightLoad(sender, args) {
    if (window.navigator.userAgent.indexOf('Safari') >= 0) {
        var objControl = document.getElementById('plugin');
        objControl.addEventListener('dragenter',
            onSilverlight_HandleDragEnter, false);
        objControl.addEventListener('drop',
            onSilverlight_handleDropEvent, false);
        objControl.addEventListener('dragover',
            onSilverlight_HandleDragOver, false);
        objControl.addEventListener('dragleave',
            onSilverlight_HandleDragLeave, false);
    }
}
function onSilverlight_HandleDragEnter(oEvent) {
    // Prevent default operations in DOM
    oEvent.preventDefault();
    var flag = oEvent.target.dragEnter(oEvent);
    // If handled, then stop propagation of event in DOM
    if (flag) { oEvent.stopPropagation(); }
}
function onSilverlight_HandleDragOver(oEvent) {
    // Prevent default operations in DOM
    oEvent.preventDefault();
    var flag = oEvent.target.dragOver(oEvent);
    // If handled, then stop propagation of event in DOM
    if (flag) { oEvent.stopPropagation(); }
}
function onSilverlight_HandleDragLeave(oEvent) {
    // Prevent default operations in DOM
    oEvent.preventDefault();
    var flag = oEvent.target.dragLeave(oEvent);
    // If handled, then stop propagation of event in DOM
    if (flag) { oEvent.stopPropagation(); }
}
function onSilverlight_handleDropEvent(oEvent) {
    // Prevent default operations in DOM
    oEvent.preventDefault();

    var newEvent = Silverlight_clone(oEvent);
    newEvent.clientX = 80;
    newEvent.clientY = 80;
    newEvent.x = 80;
    newEvent.y = 80;
    newEvent.offsetX = 80;
    newEvent.offsetY = 80;

    var flag = oEvent.target.dragDrop(newEvent);
    // If handled, then stop propagation of event in DOM
    if (flag) { oEvent.stopPropagation(); }
}
function Silverlight_clone(o) {
    var c = {};
    var p, v;
    for (p in o) {
        if (o.hasOwnProperty(p)) {
            v = o[p];
            c[p] = v;
        }
    }
    return c;
}
 

You are now good to go!

This code is based primarily on the solution provided by Olego in this forum.