Click here to Skip to main content
Click here to Skip to main content

Drag and Drop files from Windows Explorer to Windows Form

By , 31 Jan 2003
 

Introduction

If we have a Windows Forms application which has File -> Open functionality, adding a few lines of code allows the user to open files dragged from the Windows Explorer. This article describes how to add this feature to your application.

Adding Drag-and-Drop capability to an existing Windows Forms application

Suppose we have simple image viewer program (demo project DropFiles). When tje user selects File -> Open, it shows the 'Open File' dialog:

private void mnuFileOpen_Click(object sender, System.EventArgs e)
{
    // Show Open File dialog
    OpenFileDialog openDlg = new OpenFileDialog();
    openDlg.Filter  = "Jpeg files (*.jpg)|*.jpg|Bitmap files (*.bmp)|"
                      + *.bmp|All Files (*.*)|*.*";

    openDlg.FileName = "" ;
    openDlg.CheckFileExists = true;
    openDlg.CheckPathExists = true;

    if ( openDlg.ShowDialog() != DialogResult.OK )
        return;

    OpenFile(openDlg.FileName);
}
The function OpenFile loads the image file to a class member Bitmap m_Bitmap, and the Paint event handler shows this bitmap on the screen:
private Bitmap m_Bitmap;

private void OpenFile(string sFile)
{
    Bitmap bmp;

    try
    {
        // load bitmap from file
        bmp = (Bitmap)Bitmap.FromFile(sFile, false);

        if ( bmp != null )
        {
            // Keep bitmap in class member
            m_Bitmap = (Bitmap) bmp.Clone();

            // Set Autoscroll properties
            this.AutoScroll = true;

            this.AutoScrollMinSize = new Size (
                    m_Bitmap.Width, 
                    m_Bitmap.Height);
            
            // draw image
            Invalidate();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(
            this,
            ex.Message,
            "Error loading from file");
    }
}

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    if ( m_Bitmap != null )
    {
        e.Graphics.DrawImage(
            m_Bitmap, 
            new Rectangle(this.AutoScrollPosition.X, 
            this.AutoScrollPosition.Y, 
            m_Bitmap.Width, 
            m_Bitmap.Height));
    }
}
To open files dropped from the Windows Explorer we need to set the form AllowDrop property to true. After this add the DragEnter and DragDrop event handlers.

DragEnter handler is simple - program accepts only files:

private void Form1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.FileDrop)) 
        e.Effect = DragDropEffects.Copy;
    else
        e.Effect = DragDropEffects.None;
}

The DragEventArgs.GetData function returns an IDataObject interface that contains the data associated with this DragDrop event. When a file or files are dropped from Explorer to the form, IDataObject contains an array of file names. If one file is dropped, the array contains one element. All the time the DragDrop event handler is working, the Windows Explorer instance is not responding. Therefore, we need to call the OpenFile function asynchronously. This is done using the BeginInvoke function and a delegate pointing to OpenFile. It is a good idea also to move the form to the foreground after dropping file to it.

private delegate void DelegateOpenFile(String s);           // type
private DelegateOpenFile m_DelegateOpenFile;                // instance

private void Form1_Load(object sender, System.EventArgs e)
{
    // create delegate used for asynchronous call
    m_DelegateOpenFile = new DelegateOpenFile(this.OpenFile);
}


private void Form1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
    try
    {
        Array a = (Array)e.Data.GetData(DataFormats.FileDrop);

        if ( a != null )
        {
            // Extract string from first array element
            // (ignore all files except first if number of files are dropped).
            string s = a.GetValue(0).ToString();

            // Call OpenFile asynchronously.
            // Explorer instance from which file is dropped is not responding
            // all the time when DragDrop handler is active, so we need to return
            // immidiately (especially if OpenFile shows MessageBox).

            this.BeginInvoke(m_DelegateOpenFile, new Object[] {s});

            this.Activate();        // in the case Explorer overlaps this form
        }
    }
    catch (Exception ex)
    {
        Trace.WriteLine("Error in DragDrop function: " + ex.Message);

        // don't show MessageBox here - Explorer is waiting !
    }
}
This is all we need to implement Drag-and-Drop capability in Windows Forms application. However, good programming style requires writing the wrapper class which encapsulates this feature.

Using the DragDropManager class

The second demo project DropFiles1 opens files dropped from Explorer using helper class DragDropManager. The project is very simple - it allows you to open one or more files and shows the file names in listbox. It has mnuFileOpen_Click function which shows Open File dialog and calls OpenFiles(Array a) passing array of file names selected by user.

Form that uses DragDropManager should implement IDropFileTarget interface defined in the same file as DragDropManager:

public interface IDropFileTarget
{
    void OpenFiles(System.Array a);
}
So, main form is derived from IDropFileTarget:
public class Form1 : System.Windows.Forms.Form, IDropFileTarget
and has OpenFiles function which opens files selected from File - Open dialog or dropped from Windows Explorer:
public void OpenFiles(Array a)
{
    // If our application can open only one file, we can process
    // here only first element of array or give some error message
    // in the case array contains more than one file.
    //
    // In this sample I allow to open number of files showing 
    // their names in list box.

    string sError = "";
    string sFile;

    lstFiles.Items.Clear();

    // process all files in array
    for ( int i = 0; i < a.Length; i++ )
    {
        sFile = a.GetValue(i).ToString();           // file name

        // Check file name
        // (Let's say we don't accept non-existing files or directories)
        FileInfo info = new FileInfo(sFile);

        if ( ! info.Exists )
        {
            sError += "\nIncorrect file name: " + sFile;
        }
        else
        {
            lstFiles.Items.Add(sFile);
        }
    }

    if ( sError.Length > 0 )
        MessageBox.Show(this, sError, "Open File Error");
}
The Form has the member
private DragDropManager m_DragDropManager;
which is initialized in Load event handler:
private void Form1_Load(object sender, System.EventArgs e)
{
    m_DragDropManager = new DragDropManager();
    m_DragDropManager.Parent = this;
}
So, the steps that should be done for using DragDropManager class in Windows Form are:
- Derive the form from IDropFileTarget interface;
- Implement IDropFileTarget interface adding function OpenFiles(Array a);
- Add member of DragDropManager type to the form;
- Initialize it setting Parent property to form reference.

Class DragDropManager

This class keeps reference to owner form in class member and has delegate used for asynchronous call to the form:
private Form m_parent;          // reference to owner form

private delegate void DelegateOpenFiles(Array a);           // type
private DelegateOpenFiles m_DelegateOpenFiles;              // instance
Initialization is done when client sets Parent property:
public Form Parent
{
    set
    {
        m_parent = value;               // keep reference to owner form

        // Check if owner form implements IDropFileTarget interface
        if ( ! ( m_parent is IDropFileTarget ) )
        {
            throw new Exception(
                "DragDropManager: Parent form doesn't implement IDropFileTarget interface");
        }

        // create delegate used for asynchronous call
        m_DelegateOpenFiles = new DelegateOpenFiles(((IDropFileTarget)m_parent).OpenFiles);

        // ensure that owner form allows dropping
        m_parent.AllowDrop = true;

        // subscribe to owner form's drag-drop events
        m_parent.DragEnter += new System.Windows.Forms.DragEventHandler(this.OnDragEnter);
        m_parent.DragDrop += new System.Windows.Forms.DragEventHandler(this.OnDragDrop);
    }
}
OnDragEnter and OnDragDrop are subscribed to owner form DragEnter and DragDrop events:
private void OnDragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.FileDrop)) 
        e.Effect = DragDropEffects.Copy;
    else
        e.Effect = DragDropEffects.None;
}

private void OnDragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
    try
    {
        Array a = (Array)e.Data.GetData(DataFormats.FileDrop);

        if ( a != null )
        {
            // Call owner's OpenFiles asynchronously.

            m_parent.BeginInvoke(m_DelegateOpenFiles, new Object[] {a});

            m_parent.Activate();        // in the case Explorer overlaps owner form
        }
    }
    catch (Exception ex)
    {
        Trace.WriteLine("Error in DragDropManager.OnDragDrop function: " + ex.Message);
    }
}

Acknowledgements

  1. Using helper class with subscribing to owner form events. Joel Matthias.
    http://www.codeproject.com/csharp/restoreformstate.asp
  2. Using form AutoScroll properties. Christian Graus.
    http://www.codeproject.com/cs/media/csharpgraphicfilters11.asp

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Alex Fr
Software Developer
Israel Israel
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5membermanoj kumar choubey28 Nov '12 - 18:31 
nice
QuestionWindows Explorer lock, freezes even if using BeginInvokememberRolf Kristensen5 Oct '11 - 9:22 
Discovered a strange problem where the Windows Explorer would lock, eventhough I deferred the actual DragDrop operation using BeginInvoke().
 
The solution was to create a thread, that slept for 100 ms and then invoked the wanted method. If I removed the sleep from the new thread, then Windows Explorer would lock again. Very strange indeed.
 
private void MainForm_DragDrop(object sender, DragEventArgs e)
{
   ...
 
   ThreadPool.QueueUserWorkItem(new WaitCallback(worker_DoWork), filenames.ToArray());
}
 
void worker_DoWork(object param)
{
   System.Threading.Thread.Sleep(100);
   this.BeginInvoke(new Action<string[]>(OpenFileSelection), new object[] { param });
}

QuestionNot working when start my application As administrator?memberdejan19dejan1921 Sep '11 - 4:55 
Hi,
 
i used your DragDropManager.cs in my application,
and it works fine,
but when start my application As Administrator, Drag and Drop is disabled.
I test it on Windows7.
 
Please for any help.
 
BR,
Dejan
AnswerRe: Not working when start my application As administrator?memberRolf Kristensen5 Oct '11 - 9:18 
This is caused by Win7 security feature (UAC) that prevents drag drop between standard-user-apps and admin-user-apps.
GeneralMy vote of 5memberzoli7712310 Aug '11 - 11:54 
Thanks
GeneralMy vote of 5memberMember 791404411 Jul '11 - 23:16 
excellent work
GeneralMy vote of 4memberRolf Kristensen13 Apr '11 - 10:55 
Easy to follow guidelines, and good explanation of why one should use BeginInvoke.
GeneralThanks, man, really gj...memberJan Kurbanaliev2 Aug '10 - 19:31 
I was breakin my head wondering why my drag and drop function doesn't work xD. Urs one seems to be wrkng.
QuestionThank's manmemberAlireza Hajihasani19 Jul '10 - 22:39 
Hi dear Alex.
Thank's for this article. It was so usefull to me. May I ask about another problem to open files? Assume that an application with a main MDIContainer form which is used to work on some associated files. How can I open the main form application starting-up a file as a child when I double click the file?
 
Thank's for help.
a.hajihasani@gmail.com
GeneralDrag and Drop files from OutlookmemberDmitry Kikhtev1 Nov '09 - 16:49 
I am writing simila app based on your example.
All work perfect from Windows Explorer
 
But from MS Outlook it does not
 
here
Array a = (Array)e.Data.GetData(DataFormats.FileDrop);
a = null

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 1 Feb 2003
Article Copyright 2003 by Alex Fr
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid