【问题标题】:BackgroundWorker using C#使用 C# 的 BackgroundWorker
【发布时间】:2013-12-13 18:29:11
【问题描述】:

我完全迷路了。我似乎没有得到任何回应。

    BackgroundWorker NewWorker;

    public void StartBackgroundWorker()
    {
        BackgroundWorker NewWorker = new BackgroundWorker();
        NewWorker.DoWork += new DoWorkEventHandler(NewWorker_DoWork);
        NewWorker.ProgressChanged += new ProgressChangedEventHandler(NewWorker_ProgressChanged);
        NewWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(NewWorker_RunWorkerCompleted);
        NewWorker.WorkerReportsProgress = true;

        StartWorker();
    }

    void NewWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        for (int i = 1; (i <= 10); i++)
        {
            if ((worker.CancellationPending == true))
            {
                e.Cancel = true;
                break;
            }
            else
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select StatusCode from Win32_PingStatus where address = 'Metabox-PC'");
                ManagementObjectCollection objCollection = searcher.Get();
                foreach (ManagementObject Results in objCollection)
                {
                    MessageBox.Show(Results.ToString());
                }
                // Perform a time consuming operation and report progress.
                System.Threading.Thread.Sleep(1);
                worker.ReportProgress((i * 10));
            }
        }
    }

    private void NewWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("Finished");
    }

没有任何消息框出现,表明它已完成。 我错过了什么?

【问题讨论】:

  • StartWorker 是做什么的?
  • BackgroundWorker 不是在与 UI 不同的线程上吗? stackoverflow.com/questions/6755519/…
  • @FrancisDucharme 工人本身不在任何线程上。它在几个不同的线程中触发事件。

标签: c# wpf properties


【解决方案1】:

您永远不会在您配置的BackgroundWorker 上调用RunWorkerAsync

认为你是,因为你正在调用StartWorker,(我想)其中包含代码NewWorker.RunWorkerAsync();,但是NewWorker,在StartWorker内部,指的是完全不同的BackgroundWorker,您尚未配置为执行任何操作。

您有一个实例字段NewWorker,以及一个位于StartBackgroundWorker 内的局部变量NewWorker,它隐藏了该实例字段。

如果你真的需要后台工作者作为实例字段,那么不要在StartBackgroundWorker 中隐藏它并始终使用实例字段。如果您不需要它作为实例字段(据记录,这很可能,并且不必要地将变量提升到实例字段会使程序更加混乱),那么您只需启动您在 StartBackgroundWorker 中创建的 BackgroundWorkder .如果StartWorker 确实有足够的代码需要在另一个方法中,那么这可能意味着它应该接受BackgroundWorker 作为参数,这样你就可以传入你在StartBackgroundWorker 中创建的worker。

【讨论】:

    【解决方案2】:

    问题是你永远不会启动你的 NewWorker。那是因为您的“全局” NewWorker 始终为空。

    查看固定代码:

        NewWorker = new BackgroundWorker(); // this line is now fixed.
        NewWorker.DoWork += new DoWorkEventHandler(NewWorker_DoWork);
        NewWorker.ProgressChanged += new ProgressChangedEventHandler(NewWorker_ProgressChanged);
        NewWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(NewWorker_RunWorkerCompleted);
        NewWorker.WorkerReportsProgress = true;
    
        StartWorker();
    

    【讨论】:

    • 为了进一步澄清,您在函数中定义了一个新的本地 NewWorker 变量。据推测,您的意思是使用类中定义的全局变量。
    【解决方案3】:

    为什么需要将后台工作人员设为字段?只需在构造函数和其他所有内容中进行。在其事件中,您可以将对象转换为 BackgroundWorker。

    public void StartBackgroundWorker()
    {
        BackgroundWorker NewWorker = new BackgroundWorker();
        NewWorker.DoWork += new DoWorkEventHandler(NewWorker_DoWork);
        NewWorker.ProgressChanged += new ProgressChangedEventHandler(NewWorker_ProgressChanged);
        NewWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(NewWorker_RunWorkerCompleted);
        NewWorker.WorkerReportsProgress = true;
    
        NewWorker.RunWorkerAsync();
    }
    

    【讨论】:

      【解决方案4】:

      Francis 是对的……任何在 GUI 线程以外的线程中调用 MessageBox 的尝试都会阻塞。您必须调用:

      Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => {
          MessageBox.Show("Hello World!");
      }));
      

      【讨论】:

      • 1) 这根本不能回答问题 2) 是什么让你认为他不想阻止对 Show 的调用?
      • @Servy 1) 实际上我是唯一回答他问题的人。我说过尝试在 GUI 线程之外调用 MessageBox 会阻塞,这就是为什么他的已完成处理程序(确实发生在主线程上)没有被调用的原因,因为它在第一个 MessageBox 上被阻塞。 2)他很可能是,但这不是他的问题。他的问题是为什么他完成的处理程序没有被调用。
      • 未调用已完成的处理程序,因为具有已完成处理程序的 BGW 从未启动。如果它正在启动,那么他将看到消息框,指示进度,即使他说他没有,只是 BGW 将继续工作,同时大量调用 messagebox.show在消息泵中堆积。
      • 这实际上不是 MessageBox 的工作方式,codeproject.com/Articles/121226/MessageBoxes-and-worker-threads 上有一篇关于这一切的优秀 CodeProject 文章。我承认我假设他对 StartWorker() 的调用调用 NewWorker.RunWorkerAsync() 来启动线程,如果您立即尝试在线程函数中执行 MessageBox,那么您会看到它阻塞。这就是实际发生的情况,他的工作线程正在尝试弹出消息框以报告进度并且他遇到了死锁。
      • 是的,它会在等待消息框的同时阻塞BGW,但它可以正常显示,所以没有死锁,只是一个显示的消息框等待用户点击它。如果他有一些未显示的代码导致他的 UI 阻塞,那么是的,消息框没有显示,但没有证据支持该断言,并且有 is 的证据另一个问题,即您假设StartWorker 调用NewWorker.RunWorkerAsync()。它可能有那个代码,但它仍然没有执行这里显示的任何代码。
      【解决方案5】:

      感谢您的所有回答。现在提供的描述对我来说更有意义。

      同样是之前的辩论:消息框确实阻塞了线程。它卡在 10%,然后我的电脑(VM 盒)崩溃了。

      现在我唯一的问题是 e.results 正在返回一个项目数组。但它在对象中。

      我发现很难找回数据。

      public void StartBackgroundWorker()
      {
      
          BackgroundWorker NewWorker = new BackgroundWorker();
          NewWorker.DoWork += new DoWorkEventHandler(NewWorker_DoWork);
          NewWorker.ProgressChanged += new ProgressChangedEventHandler(NewWorker_ProgressChanged);
          NewWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(NewWorker_RunWorkerCompleted);
          NewWorker.WorkerReportsProgress = true;
      
          NewWorker.RunWorkerAsync();
      }
      
      void NewWorker_DoWork(object sender, DoWorkEventArgs e)
      {
          List<string> ReturnResults = new List<string>();
          BackgroundWorker worker = sender as BackgroundWorker;
      
          ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select StatusCode from Win32_PingStatus where address = 'Metabox-PC'");
          ManagementObjectCollection objCollection = searcher.Get();
          foreach (ManagementObject Results in objCollection)
          {
              ReturnResults.Add(Results["StatusCode"].ToString());
          }
          e.Result = ReturnResults;
      
          // Perform a time-consuming operation and report progress.
          System.Threading.Thread.Sleep(1);
      }
      
      private void NewWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
      {
          txtPingable.text = e.Result;
      }
      

      【讨论】:

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