I have an application that allows data to be dragged and dropped into it, before performing a potentially very long operation upon it. This works fine, however, the Explorer window freezes whilst my application is processing. Is there any way to "release" it so to speak as soon as I have taken a copy of the file list?
My current code is:
private void MainForm_DragDrop(object sender, DragEventArgs e)
{
ClearTempFiles(); //Clear all files before populating
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); //Get the filepaths for the dragdrop data
List<string> toParse = new List<string>();
foreach (string file in files)
{
FileAttributes attr = File.GetAttributes(file);
if (attr.HasFlag(FileAttributes.Directory)) //If a folder has been included, add all files from within
{
toParse.AddRange(DirSearch(file));
}
else
{
toParse.Add(file); //Add files
}
}
CurrentJobData = new JobData(toParse); //Create new JobData from these files <---- Takes up to a few minutes with hundreds of files.
CurrentJobData.ToTree(treeView1); //Push this data to the TreeView
} //Handles the dragdrop of data, populating the solution
You need to let the event run to completion. Due to the nature of the DragDrop operation both applications involved need to be sure the operation has completed. They can only tell if the DragDrop message is handled by either message pump. As long as that didn't happen, Explorer can only assume the user is still dragging and dropping. So as already suggested in the comments, use a BackgroundWorker:
private void Form1_DragDrop(object sender, DragEventArgs e)
{
// gets all data from Explorer
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); //Get the filepaths for the dragdrop data
// don't block the UI thread, that prevents the
// processing of both Windows messages in Explorer and your app
// to complete, effectively blocking both of them
backgroundWorker1.RunWorkerAsync(files);
// if you want your form to be unavailable
// while processing takes place
// set Enabled to false on your form
this.Enabled = false;
}
You're DoWork
eventhandler will now do the heavy lifting. Notice how I set the Result
property of the DoWorkEventArgs
to send your JobData to the completed event.
// this all runs on a background, non-UI threed
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
ClearTempFiles(); //Clear all files before populating
string[] files = (string[])e.Argument; // this is passed in from RunWorkerAsync
List<string> toParse = new List<string>();
foreach (string file in files)
{
FileAttributes attr = File.GetAttributes(file);
if (attr.HasFlag(FileAttributes.Directory)) //If a folder has been included, add all files from within
{
toParse.AddRange(DirSearch(file));
}
else
{
toParse.Add(file); //Add files
}
}
e.Result = new JobData(toParse); //Create new JobData from these files <---- Takes up to a few minutes with hundreds of files.
}
In the RunWorkerCompleted
eventhandler you're back on the UI thread, where you can fill and update your TreeView
. Notice how at the end the Form is enabled again, making sure the user can interact with the application.
// this runs on the UI thread
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
CurrentJobData = (JobData) e.Result;
CurrentJobData.ToTree(treeView1); //Push this data to the TreeView
// set Enabled to true on your controls
this.Enabled = true;
}
If you want to report progress, make sure to use the ProgressChanged eventhandler so you're on the UI thread and call the ReportProgress
method on the backgroundworker to invoke that handler.
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