【问题标题】:How can i invoke a method called from backgroundworker dowork event?如何调用从 backgroundworker dowork 事件调用的方法?
【发布时间】:2015-02-01 07:38:22
【问题描述】:

这是方法:

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"));

无效操作异常

在此控件上执行的操作是从错误的线程调用的。使用 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"));

【问题讨论】:

  • 在您的 DoWork 方法中,您试图操作在 UI 线程上创建的 UI 控件。您无法从另一个线程访问该控件。如果你在分手前有 20 秒的延迟,我会说你很幸运

标签: c# .net multithreading winforms


【解决方案1】:

您不能直接从非 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 时,应用程序可能会暂时冻结,但您不会遇到该特定异常。

【讨论】:

  • 授予它工作。但是更新 progressBar 呢?在我的代码中,我在 i++ abd 的方法中做了错误的计算,int 百分比 = (i + 1) * 100 / 100;并且在 ProgressChanged 事件中,它确实更新了 progressBar,但是当操作结束甚至不在 50% 时,它还没有到达 100% 的绿色条
  • toolStripProgressBar2.Maximum 在设计器中设置为 100。要么我没有做任何计算。
【解决方案2】:

DoWork 事件在后台线程中运行。它不能与 UI 元素交互。你应该创造一些结果;本身不是 UI 元素的东西,将其设置为 BGW 的 Result 属性,然后根据 RunWorkerCompleted even 处理程序中的结果更新 UI,该处理程序可以访问 DoWork 中的结果集。

【讨论】:

    猜你喜欢
    • 2021-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多