DragDrop.DoDragDrop 在 Excel 中执行拖放操作时不返回

本文关键字:操作 返回 拖放 执行 DoDragDrop Excel DragDrop | 更新日期: 2023-09-27 18:32:57

我的应用程序有一个简单的功能,它可以连接到Excel,并在它们之间执行拖放操作。具体来说,我只是从我的应用程序中获取一些文本值,将它们拖到 Excel 中,然后删除它们。

这在 90% 的时间内都有效,但奇怪的是,在某些时候,我的应用程序只是冻结。我附加调试器并暂停执行,它卡在DragDrop.DoDragDrop - 这个函数永远不会返回,我的应用程序将永远挂起。

有没有办法确保DoDragDrop可以返回?还是某种超时?这有时只会在我将数据放入 Excel 时发生,因此据我所知,删除正在完成,函数应该在我的应用程序中返回。

这是我使用的代码:

DragDrop.DoDragDrop(sender as DependencyObject, draggable.GetDragDropString(), DragDropEffects.Copy);

GetDragDropString()只是一个函数,它返回要放入Excel中的数据字符串。 sender只是我拖动的 UI 组件。如网格、编辑框、文本框等。可能是其中任何一个。

感谢您的任何帮助!

编辑:由于在某些情况下DragDrop.DoDragDrop返回存在问题,也许有人可以帮助编写适当的超时?我尝试启动一个新Thread并使其超时,这适用于简单情况以及线程中的工作不需要 UI 资源的情况。但是,当我在超时的新线程中调用DoDragDrop时,它会抛出一个异常,指出线程无法访问该对象,因为其他线程拥有它。所以我需要在同一线程中调用这个函数。所以从本质上讲,当这个函数在一定时间内无法返回时,我需要在 UI 线程上超时。

DragDrop.DoDragDrop 在 Excel 中执行拖放操作时不返回

我认为以下内容应该可以完成这项工作,但我会在进行时分解它

public class DragDropTimer
{
    private delegate void DoDragDropDelegate();
    private System.Timers.Timer dragTimer;
    private readonly int interval = 3000;
    public DragDropTimer()
    {
        dragTimer = new System.Timers.Timer();
        dragTimer.Interval = interval;
        dragTimer.Elapsed += new ElapsedEventHandler(DragDropTimerElapsed);
        dragTimer.Enabled = false;
        dragTimer.AutoReset = false;
    }
    void DragDropTimerElapsed(object sender, ElapsedEventArgs e)
    {
        Initiate();
    }
    public void Initiate()
    {
        // Stops UI from freezing, call action async.
        DoDragDropDelegate doDragDrop = new DoDragDropDelegate(DragDropAction);
        // No async callback or object required
        doDragDrop.BeginInvoke(null, null);
    }
    private void DragDropAction()
    {
        dragTimer.Enabled = false; 
        // Do your work here. or do work before and disable your timer upto you.
    }
}

所以我们有一个基本的类DragDropTimer.我们在构造函数上设置了我们想要的间隔,如果您愿意,您可能希望更改它,我们在计时器上调用DragDropTimerElapsed

Initiate是启动拖动所需的函数,它创建了一个简单的委托,我们要求它执行DragAction步骤,这是您完成所有工作的地方,计时器被禁用。只有当您的拖放成功时,您才可以选择禁用计时器。如果计时器过去了,我们再次调用Initiate重新开始。

另一种选择是通过以下方式在单独的线程中执行丢弃

Task.Factory.StartNew( () => { ... } );