Reputation: 9100
Is there a way to allow Drag and Drop anywhere in a form full of controls?
The idea is to allow user to drag a file anywhere in a form in order to "load" it. I will not need any other DragDrop behavior but this.
By setting AllowDrop=True
to the form only, I get DragEnter
events but not DragDrop
ones.
An idea would be to make a topmost panel visible on DragEnter
and handle DragDrop
events there, but I wonder if I miss something obvious here since I have little experience in the field.
Another Idea would be to iterate through all controls and subscribe to Drag-related events. I really don't like this approach, though.
Upvotes: 1
Views: 2667
Reputation: 63387
I'm not sure what kinds of control you have on your form. But I've tested with a Button, a GroupBox, a PictureBox and a TextBox. All these controls have AllowDrop = false
by default. And I can drag-n-drop something from outside onto the form OK. The DragDrop
is fired OK. Everything is OK. What is actually your problem? I guess your controls have AllowDrop = true
.
In the case the DragDrop
event is not fired (which I think only happens if the target is one of your Control with AllowDrop = true
). I think the following may work. But if the target is one of your Control with AllowDrop = true
, the effect icon is gone away.
public Form1(){
InitializeComponents();
t.Interval = 1;
t.Tick += Tick;
}
IDataObject data;
Timer t = new Timer();
int i = 0;
private void Tick(object sender, EventArgs e)
{
Text = (i++).ToString();
if (ClientRectangle.Contains(PointToClient(new Point(MousePosition.X, MousePosition.Y))) && MouseButtons == MouseButtons.None)
{
t.Stop();
if (data != null)
{
//Process data here
//-----------------
data = null;
}
}
else if (MouseButtons == MouseButtons.None)
{
data = null;
t.Stop();
}
}
private void Form1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.AllowedEffect;
if (data == null)
{
data = e.Data;
t.Start();
}
}
And I think you may have to use the loop through all the Controls to add appropriate event handlers. There is no other better way.
Upvotes: 1
Reputation: 11
In the Drop
event.
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
foreach (string file in files) Console.WriteLine(file);
In the DragEnter
event.
if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effects = DragDropEffects.Copy;
Upvotes: -1
Reputation: 942408
Sure, iterating the controls will work, it doesn't take much code:
public Form1() {
InitializeComponent();
WireDragDrop(this.Controls);
}
private void WireDragDrop(Control.ControlCollection ctls) {
foreach (Control ctl in ctls) {
ctl.AllowDrop = true;
ctl.DragEnter += ctl_DragEnter;
ctl.DragDrop += ctl_DragDrop;
WireDragDrop(ctl.Controls);
}
}
void ctl_DragDrop(object sender, DragEventArgs e) {
// etc..
}
void ctl_DragEnter(object sender, DragEventArgs e) {
// etc..
}
If you still don't like the approach then use a recognizable single drop target that the user will always hit. Could be as simple as a label that says "Drop here".
Upvotes: 3