【问题标题】:Using BackgroundWorker in C#?在 C# 中使用 BackgroundWorker?
【发布时间】:2012-01-17 04:06:31
【问题描述】:

我有两个关于使用 BackgroundWorker 的问题:

1) 假设您有函数 A 和函数 B。函数 A 创建一个运行函数 B 的 BackgroundWorker。因此 BackgroundWorker 现在在单独的线程上运行函数 B。函数 B 是一个无限循环,我打算长时间运行。函数A通过BackgroundWorker使用后,返回。那么现在启动BackgroundWorker(Function A)的函数已经返回,BackgroundWorker线程是否继续在后台运行?或者它是否停止运行函数 B,因为实例化它的函数已经返回?如果它确实停止了,我该如何让它即使在函数 A 返回后函数 B 也能继续运行?

2) 我需要从 BackgroundWorker 创建的单独线程访问窗口窗体项(即文本框)。但是,如果我尝试从非主线程访问窗口窗体项,则会出现跨线程错误。如何从单独的线程安全地访问窗口窗体项?我基本上需要不断地从一个单独的线程更新一个文本框。我知道 BackgroundWorker 有一个名为“RunWorkerCompleted”的成员,该成员在 BackgroundWorker 完成其工作后运行。它允许我从中访问窗口窗体项。但是,我需要在线程执行期间而不是在线程完成之后访问窗口窗体项。我怎样才能通过线程安全地访问这些?如果这不可能,还有哪些其他可能的解决方案?

【问题讨论】:

    标签: c# windows multithreading


    【解决方案1】:

    1) BackgroundWorker 将在函数 A 返回后继续运行。

    2) 创建一个更新文本框的ProgressChanged 事件处理程序,并让BackgroundWorker 在您想要更改文本时调用ReportProgress。当然,您必须让BackgroundWorker 设置一个ProgressChanged 事件可以读取的属性。这是因为在 UI 线程上调用了 ProgressChanged 事件处理程序。

    【讨论】:

    • 谢谢。我使用了 ProgressChanged,但它仍然给我一个跨线程错误。知道为什么吗?
    • @Amir Palsapure 谢谢你的帮助。你的答案对我来说有点太复杂了(不是你的错),而这个似乎更容易一些,所以我决定试一试。我刚开始使用 C#,所以这个答案似乎更容易理解。再次感谢您的帮助。
    • 您在哪个线程上挂钩了事件处理程序。它应该在 UI 线程上。换句话说,在绑定事件处理程序之前,您说的是 WorkAsync()。查看this博客了解跨线程问题。
    • ad 1)> BackgroundWorker 将继续运行,但您需要在某处保留对它的引用。否则迟早会被垃圾回收。
    • 谢谢,它运行良好。它之前不起作用,因为我刚刚意识到 BackgroundWorker 是在另一个线程中创建的,因此导致了跨线程错误。
    【解决方案2】:

    Jim 的回答是正确的。

    在第二部分中,你说

    我需要从 BackgroundWorker 创建的单独线程访问窗口窗体项(即文本框)。

    所以现在如果你只想这样做,那么你需要做的是创建一个如下所示的扩展方法

    public static class ControlExtensions
    {
        public static void Invoke(this Control control, Action action)
        {
            if (control.InvokeRequired) control.Invoke(new MethodInvoker(action), null);
            else action.Invoke();
        }
    }
    

    现在,当您从非 UI 线程访问文本框时,您需要这样做

    txtBox.Invoke(() => { txtBox.Text = "Text Changed from Non-UI thread"; });
    

    希望对你有所帮助。

    【讨论】:

      【解决方案3】:

      第二个问题:

      即使我曾经遇到过同样的问题。所以使用了 _DoWork 方法。
      这就是它对我的工作方式

       private void bgwLongTask_DoWork(object sender, DoWorkEventArgs e)
       {
      
          my long task
          {
            //in between the long task, i want to udpate the datagrid view dataGridView1
      
            if (dataGridView1.InvokeRequired)
               dataGridView1.Invoke(myGridBindDelegate);
            else
               BindDataToGrid();
           }
       }
      

      这里的myGridBindDelegate是调用datagrid视图绑定方法的委托。

          delegate void GridBindDelegate();
          GridBindDelegate myGridBindDelegate;
          myGridBindDelegate = BindDataToGrid;
      
          private void BindDataToGrid()
          {
              dataGridView1.DataSource = dt; //dt is a datatable which is public
              dataGridView1.Refresh();
          }
      

      为我工作。

      【讨论】:

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