关闭表单后,BackgroundWorker报告ProgressChanged

时间:2013-08-04 15:35:50

标签: c# winforms backgroundworker

在我的winforms项目中,我得到了一些运行BackgroundWorker的Form。基本上它是一个模拟,所以它可以在某个时候解决,但也可以由用户停止,所以当它完成任何一种方式时,它需要重绘结果。我遇到了一个问题,即当我关闭主窗口时它的引用为null,但BW仍然可以触发ReportProgress,最终会出现异常。

我的BackgroundWorker(简化代码):

void backgroundWorkerRunSimulation_DoWork(object sender, DoWorkEventArgs e)
{
    bool ShouldContinue = true;
    do
    {
        SomeHeavyComputing();
        if(CheckIfSimulationDone() | backgroundWorkerRunSimulation.CancellationPending)
            ShouldContinue=false;

        //Redrawing results on the interface
        if (AlwaysRefresh | !ShouldContinue)
            UpdateGUI();    //<--Method invoked on form's thread

        //Reporting progress
        backgroundWorkerRunSimulation.ReportProgress(0, SomeReportingObject);
    }
    while(ShouldContinue);
}

和ReportProgress:

    private void backgroundWorkerRunSimulation_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        UpdateStatusBar((GUIReportInfo)e.UserState);//<-also invoked on form's thread

    }

其中

void UpdateStatusBar(GUIReportInfo ReportInfo)
{
    if (this.InvokeRequired)
    {
        ReportInfoDelegate updateStatusBar = new ReportInfoDelegate(UpdateStatusBar);
        this.Invoke(updateStatusBar, new object[] { ReportInfo });
    }
    else
        //Some assignments on form - crashes here, null reference exc
}

显然不应该启动UpdateStatusBar,我很惊讶UpdateGUI(这是类比的)不会崩溃。但有没有办法检查表格是否仍然存在? 添加:

this.Invoke(new MethodInvoker(delegate { this.Close(); }));

到FormClosing事件似乎解决了这个问题,虽然我不明白为什么会这样。是不是在表单的线程上激活了Close()方法?

我很乐意帮助你。

2 个答案:

答案 0 :(得分:1)

我猜测添加的调用只是偶然改变了事件的顺序,所以它不会崩溃。优雅的解决方案是实现FormClosing并在那里中止BW,并等待它直到完成。此外,在BW代码中,您应该检查“CancellationPending”。更多信息:

http://msdn.microsoft.com/en-us/library/hybbz6ke.aspx

编辑: 这里最高投票的答案证明了解决方案: How to stop BackgroundWorker on Form's Closing event?

答案 1 :(得分:0)

我已经设法通过等待带有计时器的工人来解决我的问题。

void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
    if (backgroundWorkerSimulationRunMany.IsBusy)
    {
        backgroundWorkerSimulationRunMany.CancelAsync();
        e.Cancel = true;
        timerDelayQuit.Start();
    }

}
private void timerQuitDelay_Tick(object sender, EventArgs e)
{
    timerDelayQuit.Stop();
    this.Close();
}