Wednesday, June 20, 2012

Drag and drop files from WPF to desktop using C#.Net

This is not only applicable to WPF but also to Windows forms applications. When I meant desktop it applies to any folder opened in windows explorer. ie the folders which we interact with for drag and drop. The scenario here is simple. We have a remote file system accessible via WCF services and showing the files and folders in the front end WPF app. It has options to upload ,download,check-out, check in etc…As part of improving usability we decided to give drag and drop facility to the screens.

Some facts about .Net drag and drop
Here are the facts about .Net file drag and drop. We cannot manipulate the file contents during the drag operation. It works only with physical files. ie we should give the drag and drop system a physical file name to start drag and drop into windows explorer or desktop. May be one reason is once the dragging mouse leaves the .Net application it is controlled by the native system ie the windows.


The drag and drop design
The above facts tells us that we can only imitate a file drag start just like it is started from windows explorer. So we should design accordingly and it is simple. As long as the .Net file drag and drop works only with the files, we should download the file before we call the DoDragAndDrop method. Is it good to download when the user starts dragging? No.So give an indication that the file is being downloaded to the client side repository /cache /temp location and allow dragging on the files which are downloaded fully.
The attached sample contains code which puts a in-memory file entity to temp folder when the dragging starts and routes the source of dragging to the file which is created in temp.

When should I call DoDragDrop
I had tried from so many places and succeeded when I called from PreviewLeftMouseButtonDown. This will block all the other operations on the mouse down operation context.


Code to drag and drop to explorer
If you look at the same you will get a clear idea how I achieved this .The FileEntry is just a class to hold the data and file name. Upon mouse event I wrote to a temp location and starts dragging using that file path. ie simply initiating a drag which we do among normal windows explorer windows.
private void Grid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    FrameworkElement senderElement = (sender as FrameworkElement);
    if (senderElement != null)
    {
        FileEntry file = senderElement.DataContext as FileEntry;
        if (file != null)
        {
            string fullPath = Write2TempAndGetFullPath(file);
            //TODO : If you want to delete you need to use FileWatchers to catch the drop events and delete from temp.
            //But as long as it is temp the users/admins can delete it when required.
            DataObject dragObj = new DataObject();
            dragObj.SetFileDropList(new System.Collections.Specialized.StringCollection() { fullPath });
            DragDrop.DoDragDrop(senderElement, dragObj, DragDropEffects.Copy);
        }
    }
}
private string Write2TempAndGetFullPath(FileEntry file)
{
    string tempFilePath=System.IO.Path.Combine(_tempFolder,file.FileName);
    Stream fs=File.Create(tempFilePath);
    new StreamWriter(fs).WriteLine(file.FileContents);
    fs.Close();
    return tempFilePath;
}



Clearing temp
If you respect the word TEMP ,there is no need to worry about clearing the temp folder because that is temporary and users or admins are allowed or trained to clean that folder whenever they need more hard disk space . If you agree with me go ahead and concentrate on your application and leave the temp to users. Else ie if you are particular about cleaning temp follow the below link which employees a file watcher to clean the temp immediately after the file is dropped.

http://www.codeproject.com/Articles/23207/Drag-and-Drop-to-Windows-Folder-C

Sample
Download the sample from this link