这是方法:
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;
}
然后在后台工作:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var root = txtHost.Text;
treeView1.Nodes.Clear();
treeView1.Nodes.Add(CreateDirectoryNode(root, "root"));
}
进步改变了:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.toolStripProgressBar2.Value = Math.Min(this.toolStripProgressBar2.Maximum, e.ProgressPercentage);
}
工作20秒后,它会在DoWork事件中抛出异常:
treeView1.Nodes.Add(CreateDirectoryNode(root, "root"));
出现InvalidOperationException
正在从错误的线程调用正在对此控件执行的操作。使用Control.Invoke或Control.BeginInvoke对正确的线程进行Marshal来执行此操作
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:
第419行是:treeView1.Nodes.Add(CreateDirectoryNode(root," root"));
答案 0 :(得分:4)
您无法直接从非UI线程修改UI元素。使用BackgroundWorker
时,修改UI线程的最佳位置来自ProgressChanged
或RunWorkerCompleted
事件。
首先,通过RunWorkerAsync()
方法从UI传递值:
backgroundWorker1.RunWorkerAsync(txtHost.Text);
仅在DoWork
事件中执行非UI工作,然后将结果传递给RunWorkerCompleted
事件:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var root = Convert.ToString(e.Argument); // txtHost.Text;
var dirNode = CreateDirectoryNode(root, "root");
e.Result = dirNode;
}
订阅RunWorkerCompleted
事件以更新用户界面:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var dirNode = (TreeNode)e.Result;
treeView1.Nodes.Clear();
treeView1.Nodes.Add(dirNode);
}
在RunWorkerCompleted
事件中更新TreeView时,应用可能会暂时冻结,但您不会得到该特定异常。
答案 1 :(得分:0)
DoWork
事件在后台线程中运行。它无法与UI元素交互。你应该创造一些结果;一些本身不是UI元素的东西,将其设置为BGW的Result
属性,然后根据RunWorkerCompleted
偶数处理程序中的结果更新UI,该处理程序可以访问{{1}中的结果集}}