Odys
Odys

Reputation: 9100

Allow DragDrop anywhere in a form

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

Answers (3)

King King
King King

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

Michael Sutherland
Michael Sutherland

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

Hans Passant
Hans Passant

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

Related Questions