0

In my winforms project I got some Form, that runs BackgroundWorker. Basically it's a simulation, so it can be solved at some point but it can also be stopped by the user, so when it finishes either way it needs to redraw the results. I got a problem with the fact, that when I close main window its reference becames null, but BW can still fire ReportProgress, which ends up with an exception.

My BackgroundWorker (simplified code):

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);
}

And ReportProgress:

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

    }

Where

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
}

Obviously UpdateStatusBar shouldn't be fired up, and I'm suprised that UpdateGUI (which is analogic) doesn't crash. But is there any way to check whether the form is still there? Adding:

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

to FormClosing event seems to solve the problem, though I don't understand why would that work. Isn't Close() method fired up on the form's thread anyway?

I'd be glad for any help.

nobody
  • 19,814
  • 17
  • 56
  • 77
Tarec
  • 3,268
  • 4
  • 30
  • 47
  • possible duplicate of [How to stop BackgroundWorker on Form's Closing event?](http://stackoverflow.com/questions/1731384/how-to-stop-backgroundworker-on-forms-closing-event) – Hans Passant Aug 04 '13 at 17:04

2 Answers2

1

I'm guessing that the added invoke just accidentally changes the order of events, so it won't crash. The elegant solution would be to implement FormClosing and abort the BW there, and wait for it till it finishes. Also, in the BW code you should check for "CancellationPending". More information here:

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

EDIT: The top-voted answer from here demonstrates the solution: How to stop BackgroundWorker on Form's Closing event?

Community
  • 1
  • 1
BartoszKP
  • 34,786
  • 15
  • 102
  • 130
  • It does check for CancellationPending, making ShouldContinue false when needed. Yes, I need to "wait" in FormClosing for BGWorker to stop, but you can't just sleep the thread. I need to do it asynchronously and I've no idea on how to do that. – Tarec Aug 04 '13 at 16:10
  • Sorry, I didn't notice the ShouldContinue flag modification. However, if you want to discontinue because the Form has been closed there will be problem with "UpdateGUI". Seems like "cancel" and "finish" events should be treated individually. I've also updated the answer regarding the problem of "waiting". – BartoszKP Aug 04 '13 at 16:18
  • Thank you for your help. I just came up with something similar solution, but you were right - main windows shouldn't close before bw isn't stopped. – Tarec Aug 04 '13 at 16:33
0

I've managed to solve my problem by just waiting for worker with a timer.

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();
}
Tarec
  • 3,268
  • 4
  • 30
  • 47
  • 1
    An addition would be to hide the window with Visible = false. Then at least the form *looks* like it's closed as well. – Patrick Aug 04 '13 at 16:55
  • That's a nice idea, though if something would go wrong, you wouldn't know the app is still there. – Tarec Aug 04 '13 at 16:57