【问题标题】:Backgroundworker's RunWorkerCompleted event is firing even before completing the workBackgroundworker RunWorkerCompleted 事件甚至在完成工作之前就被触发
【发布时间】:2013-07-29 13:35:19
【问题描述】:

我正在使用 BackgroundWorker 线程来执行一个长任务(基本上是读取一个大的 xml 文件)。工作人员第一次按要求正常工作,但如果我上传第二个 xml 文件,使用相同的后台工作人员有时工作正常,但大多数情况下,后台工作人员的 RunWorkerCompleted 甚至在 DoWork 事件之前被触发。部分代码如下所示

    private void openFile_Click(object sender, RoutedEventArgs e)
    {
          // Code removed for brevity
  worker = new BackgroundWorker();
            worker.RunWorkerAsync();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.WorkerReportsProgress = true;
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
       }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        DataImport();
        //worker.Dispose();
        //worker.Disposed += new EventHandler(worker_Disposed);
        //worker.DoWork -= worker_DoWork;
        //worker.RunWorkerCompleted -= worker_RunWorkerCompleted;
        //worker = null;
        //GC.Collect(GC.GetGeneration(worker), GCCollectionMode.Forced);
    }

worker 是一个全局定义的变量。我不明白这里有什么问题。请帮忙

【问题讨论】:

  • 完成的一些提示:不要打电话给GC.Collect(),要检查e.Error
  • 如果没有看到 DoWork() 的概要,则无法回答。
  • 如果你的 DoWork 函数产生一个线程来执行它的工作,而你没有执行 .Join(),DoWork 将立即返回。但正如@Henk 所说,需要看看 DoWork 做了什么。

标签: c# .net wpf backgroundworker


【解决方案1】:

您应该在调用RunWorkerAsync() 之前添加DoWork-event 处理程序(以及所有其他事件处理程序)

否则,RunWorkerAsync 可能实际上什么都不做。

【讨论】:

  • 是的,但并没有真正解释“甚至在 DoWork 事件之前就被解雇”的症状。
  • 可能还想提一下,因为他正在重用工作人员,所以他应该确保不要多次添加事件处理程序。
  • @JimMischel 此外,他正在重用事件处理程序,因此触发的 RunWorkerCompleted 事件可能不属于“当前”后台工作人员。
  • OP 每次都在创建一个新的 Bgw。注释掉的代码确实试图根除旧代码。两者都足以排除处理程序的重用。
  • @Vikram RunWorkerCompleted += ... 不是由您调用,而是由 BackgroundWorker 调用。只有当它确定是合适的时间时,你才分配它去做的工作。更重要的是,您需要在同一概念上在 RunWorkerAsync() 之前分配 DoWork+= - BGW 在确定是时候处理给定事件时需要分配函数。 RunWorkerAsync 将启动,当它确定资源足够可用时,它将开始分配的“DoWork”。当“DoWork”完成时,BGW 会知道并查看是否分配了“Completed”。
【解决方案2】:

应该是这样的:

worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;

worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += 
    new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += 
    new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

worker.RunWorkerAsync();

RunWorkerAsync 应该在订阅DoWorkRunWokerCompleted 事件后调用。

【讨论】:

    【解决方案3】:

    你应该首先检查后台工作人员是否忙,使用这个......

            backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
    
            if (backgroundWorker1.IsBusy)
            {
                backgroundWorker1.CancelAsync();
            }
            else
            {
                backgroundWorker1.RunWorkerAsync();
    
            }
    

    【讨论】:

      【解决方案4】:

      正如https://stackoverflow.com/a/16809596/8029935 中所说,当 DoWork 方法因异常而死时,您可以盲目地假设工作人员已经完成工作并产生了结果。它被 BackgroundWorker 捕获并作为 e.Error 属性传递给 RunWorkerCompleted 事件处理程序。

      因此,我建议您必须使用 try/catch 语句检查该属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-17
        • 1970-01-01
        • 2011-11-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多