[英]How can i invoke a method called from backgroundworker dowork event?
这是方法:
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编组到正确的线程以执行此操作
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”));
您不能直接从非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
事件以更新UI:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var dirNode = (TreeNode)e.Result;
treeView1.Nodes.Clear();
treeView1.Nodes.Add(dirNode);
}
在RunWorkerCompleted
事件中更新TreeView时,该应用程序可能会暂时冻结,但是您不会收到该特定异常。
DoWork
事件在后台线程中运行。 它不能与UI元素进行交互。 您应该创建一些结果; 本身不是UI元素的东西,将其设置为BGW的Result
属性,然后在RunWorkerCompleted
偶数处理程序中基于该结果更新UI,可以访问DoWork
的结果集。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.