Reputation: 125
This is the method:
private TreeNode CreateDirectoryNode(string path, string name)
{
var directoryNode = new TreeNode(name);
var directoryListing = GetDirectoryListing(path);
var directories = directoryListing.Where(d => d.IsDirectory);
var files = directoryListing.Where(d => !d.IsDirectory);
foreach (var dir in directories)
{
i ++;
directoryNode.Nodes.Add(CreateDirectoryNode(dir.FullPath, dir.Name));
int percentage = (i + 1) * 100 / 100;
backgroundWorker1.ReportProgress(percentage);
}
foreach (var file in files)
{
directoryNode.Nodes.Add(new TreeNode(file.Name));
}
return directoryNode;
}
Then in background do work:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var root = txtHost.Text;
treeView1.Nodes.Clear();
treeView1.Nodes.Add(CreateDirectoryNode(root, "root"));
}
And the progresschanged:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.toolStripProgressBar2.Value = Math.Min(this.toolStripProgressBar2.Maximum, e.ProgressPercentage);
}
After 20 seconds of work it throw exception in the DoWork event on the line:
treeView1.Nodes.Add(CreateDirectoryNode(root, "root"));
InvalidOperationException
Action being performed on this control is being called from the wrong thread. Marshal to the correct thread using Control.Invoke or Control.BeginInvoke to perform this action
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=Action being performed on this control is being called from the wrong thread. Marshal to the correct thread using Control.Invoke or Control.BeginInvoke to perform this action.
Source=System.Windows.Forms
StackTrace:
at System.Windows.Forms.TreeNode.Realize(Boolean insertFirst)
at System.Windows.Forms.TreeNodeCollection.AddInternal(TreeNode node, Int32 delta)
at FTP_ProgressBar.Form1.backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in c:\ftp_progressbar\FTP_ProgressBar\Form1.cs:line 419
at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
InnerException:
Line 419 is: treeView1.Nodes.Add(CreateDirectoryNode(root, "root"));
Upvotes: 0
Views: 2592
Reputation: 66439
You can't directly modify UI elements from a non-UI thread. When using a BackgroundWorker
, the best place to modify the UI thread is from the ProgressChanged
or RunWorkerCompleted
events.
First, pass the values from the UI via the RunWorkerAsync()
method:
backgroundWorker1.RunWorkerAsync(txtHost.Text);
Only do non-UI work in the DoWork
event, then pass the results to the RunWorkerCompleted
event:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var root = Convert.ToString(e.Argument); // txtHost.Text;
var dirNode = CreateDirectoryNode(root, "root");
e.Result = dirNode;
}
Subscribe to the RunWorkerCompleted
event to update the UI:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var dirNode = (TreeNode)e.Result;
treeView1.Nodes.Clear();
treeView1.Nodes.Add(dirNode);
}
The app may freeze momentarily while the TreeView is being updated in the RunWorkerCompleted
event, but you won't get that particular exception.
Upvotes: 4
Reputation: 203821
The DoWork
event runs in a background thread. It cannot interact with UI elements. You should be creating some result; something that is not itself a UI element, setting it to the BGW's Result
property, and then updating the UI based on that result in the RunWorkerCompleted
even handler, which can access the result set in DoWork
.
Upvotes: 0