0

在我的 winforms 项目中,我得到了一些运行 BackgroundWorker 的表单。基本上它是一个模拟,所以它可以在某个时候解决,但它也可以由用户停止,所以当它完成任何一种方式时,它都需要重新绘制结果。我遇到了一个问题,即当我关闭主窗口时,它的引用变为空,但 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);
}

和报告进度:

    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() 方法是否不会在表单的线程上触发?

我很乐意提供任何帮助。

4

2 回答 2

1

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

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

编辑:此处投票最多的答案演示了解决方案: 如何在 Form's Closing 事件中停止 BackgroundWorker?

于 2013-08-04T15:45:45.970 回答
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();
}
于 2013-08-04T16:30:51.493 回答