My application has a simple feature where it hooks up to Excel and will do drag drop operations between them. Specifically, I am just taking some text values from my application, dragging them into Excel, and dropping them.
This works 90% of the time, but strangely at certain times, my application just freezes. I attach the debugger and pause the execution and it gets stuck at DragDrop.DoDragDrop
- this function never returns and my application will forever hang.
Is there a way to ensure the DoDragDrop
can return? Or some sort of timeout? This happens only sometimes when I drop the data into Excel, so for what I know, the drop is being completed and the function should return within my application.
Here's the code I use:
DragDrop.DoDragDrop(sender as DependencyObject, draggable.GetDragDropString(), DragDropEffects.Copy);
GetDragDropString()
is just a function that returns the string of data to drop in Excel.
sender
is just the UI component that I'm dragging. Like a grid, or edit box, text box, etc. Could be any of those.
Thanks for any help!
EDIT: Since there's an issue with DragDrop.DoDragDrop
returning in certain cases, perhaps someone can help with writing a proper timeout? I've tried starting a new Thread
and having it timeout, which works in simple cases and when the work within the thread doesn't require UI resources. However, when I call DoDragDrop
in a new thread with a timeout, it will throw an exception saying the thread cannot access the object because a different thread owns it. So I need to call this function within the same thread. So essentially I need a timeout on the UI thread when this function fails to return in a certain amount of time.
I think the following should do the job but I will break it down as I go along
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.
}
}
So we have a basic class DragDropTimer
. We set the interval we want on constructor, you may want to change that if you wish and we call the DragDropTimerElapsed
on timer elapsed.
Initiate
is the function you need to start the drag, its creates a simple delegate and we ask it to execute the DragAction
steps, this is where you do all your work and the timer gets disabled. You may choose to disable the timer only if you DragDrop succeeds. If the timer elapses we call Initiate
again to start all over again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With