2

I have successfully created DragDrop functionality with user controls. Now I am trying to allow DragDrop functionality on some components such as ToolStripButton.

The base class, ToolStripItem, supports AllowDrop and the DragEnter/DragDrop events...

ToolStripButton hides these properties in the designer, but they are publicly accessable.

Originally I tried doing the following for each ToolStripButton:

button.AllowDrop = true;
button.DragEnter += new DragEventHandler(button_DragEnter);
button.DragDrop += new DragEventHandler(button_DragDrop);

However, the events were not ever firing. These buttons are contained within a MenuStrip, so I changed the MenuStrip.AllowDrop to true. Then I started getting DragEnter and DragDrop events, but the DragDrop event would fail due to a threading/invoke problem when accessing the Tag property of the ToolStripItem.

The ToolStripItems cannot be invoked upon. So I have tried invoking their container, the MenuStrip, with the same function. I am still getting a threading/invoke problem where the thread stops running as soon as I try to access the ToolStripItem.

Here is the code I'm using to retrieve the Tag information after invoke:

void button_DragDrop(object sender, DragEventArgs e)
{
    menuStrip.Invoke(new DragEventHandler(MyDragFunction), new object[] { sender, e });
}

void MyDragFunction(object sender, DragEventArgs e)
{
    int id = (int)((ToolStripButton)sender).Tag;
    // Debugging never reaches this line
    int dragId = (int)e.Data.GetData(DataFormatName, false);

    MoveItem(id, dragId);
}

Is Drag and Drop to a component like a ToolStripItem simply not possible? Or am I doing something wrong?

Trevor Elliott
  • 11,292
  • 11
  • 63
  • 102
  • 1
    Drag/Drop to a ToolStripItem works. I'm curious why invoke is required in your case. Regardless, would need to see the code that "still gets a thread/invoke problem where the thread stops running." I think you'd benefit from reading up on what Invoke does and why it's needed. – John Arlen Dec 09 '11 at 21:36
  • 2
    D+D for toolstrip items is already used for another purpose. The biggest reason the properties are hidden in the Properties window. Review the docs for the ToolStripItem.AllowItemReorder property. – Hans Passant Dec 09 '11 at 22:05
  • Not sure if it qualifies as an "answer" but I did figure out what was wrong. The first problem was that the "Tag" property was not an int, but a string with an int in it. I never got an exception for it. I'm not exactly sure why that happens with events sometimes (events running on a separate thread?). In the future I must remember to wrap all events in try/catch loops until I debug them. – Trevor Elliott Dec 10 '11 at 17:17
  • The second problem I was having with DragDrop was that as shown in my code I was only subscribing to DragEnter and DragDrop events. The way that ToolStripItems behave as components of their parent MenuStrip, I needed to also use the DragOver event to set the DragDropEffects. Otherwise, I would get erratic behavior with the transition from one DragDropEffect to another, and I sometimes would not be able to drop. – Trevor Elliott Dec 10 '11 at 17:18

1 Answers1

1

Here is the code I got to work for me.

I assign the DragDrop properties in the form constructor since they are hidden in the designer.

foreach (object o in menuStrip.Items)
{
    if (o is ToolStripButton)
    {
        ToolStripItem item = (ToolStripItem)o;

        item.AllowDrop = true;
        item.DragEnter += new DragEventHandler(item_DragEnter);
        item.DragOver += new DragEventHandler(item_DragOver);
        item.DragDrop += new DragEventHandler(item_DragDrop);
    }
}

private void item_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormatName, false))
    {
        e.Effect = DragDropEffects.Move;
    }
}

private void item_DragOver(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormatName, false))
    {
        e.Effect = DragDropEffects.Move;
    }
}

private void item_DragDrop(object sender, DragEventArgs e)
{
    int id = (int)e.Data.GetData(DataFormatName, false);
    int category = Convert.ToInt32((sender as ToolStripButton).Tag);

    MyFunction(category, id);
}
Trevor Elliott
  • 11,292
  • 11
  • 63
  • 102