来自另一个线程的DoDragDrop()

每次我想让用户拖动一个控件,我调用该控件的DoDragDrop。

拖放工作正常,但我有问题周围的事情:

  1. DoDragDrop完全阻止表单,没有计时器事件跳转,没有处理绘制消息。

  2. DoDragDrop不仅阻塞了拖放操作,而且直到目标程序完成了drop事件(IE explorer.exe的suck代码)。 根据其他程序的代码很糟糕。

我想从一个新线程调用DoDragDrop。

试过这个:

Thread dragThread = new Thread(() => { Form frm = new Form(); frm.DoDragDrop("data", DragDropEffects.All); }); dragThread.SetApartmentState(ApartmentState.STA); dragThread.IsBackground = true; dragThread.Start(); 

但它似乎不起作用。 我的意思是:当从这样的其他线程执行DoDragDrop时,我的程序或其他程序中的其他控件不接收拖放消息。

还有其他方法吗?

DoDragDrop方法停止处理事件,直到第一个鼠标事件(例如鼠标移动 )。 所以我发现的解决方法非常简单 – 你只需要在调用DoDragDrop之前用相同的鼠标位置模拟鼠标事件:

 void XYZControl_MouseDown(object sender, MouseEventArgs e) { var senderControl = (Control) sender; ... Cursor.Position = senderControl.PointToScreen(new Point(eX, eY)); // Workaround! if (DoDragDrop(senderControl, DragDropEffects.Move) == DragDropEffects.Move) { ... } .... } 

你需要忘记使用一个线程,它只会向在该线程上创建的窗口发送D + D通知。 哪个不是你的控件。

对于“代码很糟糕”的诊断,我做不了多少。 DoDragDrop()调用本身确实会阻塞,直到释放鼠标按钮。 COM代码内部的另一个消息循环将接管并传递Windows消息。 定时器和绘图消息应该正常传送。 在发布一些repro代码之前,很难获得诊断。

您可能希望DoDragDrop退出并异步执行该作业。

这是答案。