I've seen this done in Borland's Turbo C++ environment, but I'm not sure how to go about it for a C# app I'm working on. Are there best practices or gotchas to look out for?
In Windows Forms, set the control's AcceptDrop property, then listen for DragEnter event and DragDrop event.
When the DragEnter event fires, set the argument's AllowedEffect to something other than none (e.g. e.Effect = DragDropEffects.Move).
When the DragDrop event fires, you'll get a list of strings. Each string is the full path to the file being dropped.
In addition to need to be aware of a gotcha. Any class that you pass around as the DataObject in the drag/drop operation has to be Serializable. So if you try and pass an object and it is not working ensure it can be serialized as that is almost certainly the problem. This has caught me out a couple of times!
Another common gotcha is thinking you can ignore the Form DragOver (or DragEnter) events. I typically use the Form's DragOver event to set the AllowedEffect, and then a specific control's DragDrop event to handle the dropped data.
Some sample code:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.AllowDrop = true;
this.DragEnter += new DragEventHandler(Form1_DragEnter);
this.DragDrop += new DragEventHandler(Form1_DragDrop);
}
void Form1_DragEnter(object sender, DragEventArgs e) {
if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
}
void Form1_DragDrop(object sender, DragEventArgs e) {
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
foreach (string file in files) Console.WriteLine(file);
}
}
Yet another gotcha:
The framework code that calls the Drag-events swallow all exceptions. You might think your event code is running smoothly, while it is gushing exceptions all over the place. You can't see them because the framework steals them.
That's why I always put a try/catch in these event handlers, just so I know if they throw any exceptions. I usually put a Debugger.Break(); in the catch part.
Before release, after testing, if everything seems to behave, I remove or replace these with real exception handling.