0

I have been trying many different thing and can't get this code to work. My code to stop backgroundworker then close window.

protected override void OnFormClosing(FormClosingEventArgs e)
    {
        if (bw.IsBusy)
        {
            bw.CancelAsync();
            e.Cancel = true;
            MessageBox.Show("close"); //Does show
            return;
        }
        base.OnFormClosing(e);
    }

During bw worker

if (worker.CancellationPending)
        {
            MessageBox.Show("Cancel"); // Does not show
            //Cancel
            e.Cancel = true;
        }

On completed background worker

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("Completed"); //Does not work

        //Check if restart
        if (bw_restart)
        { 
            bw_restart = false;
            bw.RunWorkerAsync();

        }
        //If it was cancelled
        if (e.Cancelled)
        {
            this.Close();
        }
        //If error show error message
        else if (e.Error != null)
        {
            MessageBox.Show(e.Error.ToString()); // Does not show
        }
        else //No errors or cancelled
        {
            MessageBox.Show(e.ToString()); //Does not shoiw
        }

    }

Cancel button

private void cancel_Click(object sender, EventArgs e)
    {
        bw.CancelAsync(); //Does not work :s
    }

It does not close the window, the X when pressed does not do anything, I got it to close the form but not with stopping the background worker, driving me a bit mad. Link to code i got for this problem that not working: How to stop BackgroundWorker on Form's Closing event?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Rob
  • 302
  • 2
  • 3
  • 15
  • don't use `this.Close()`, try using `this.DialogResult = DialogResult.Cancel` instead. (if this works i'll write as answer) – Sayse Jun 17 '13 at 18:48
  • 1
    In the linked answer of Hans Passant, he does not check for e.cancelled in the RunWorkerCompleted-Function. May that be the issue? – Fabian Bigler Jun 17 '13 at 18:48
  • 1
    Debug the program. See if, when the BGW's completed handler runs if `e.Cancelled` is true. Then see what the value of `mClosePending` is. Are you sure that `this.Close` is being called when the BGW is finished? If yes, put a breakpoint in the form closing event handler and see if it's being hit again (and if so, what it does). – Servy Jun 17 '13 at 18:51
  • sorry they both do not work – Rob Jun 17 '13 at 18:52
  • 1
    also, in the runworkercompleted, is `e.Error` null? – Sayse Jun 17 '13 at 18:52
  • Are you marshalling the "this.Close()" onto the UI thread? Not sure if this would help, but maybe worth a try. If you place a breakpoint on "this.Close()", is the breakpoint hit? – MotoSV Jun 17 '13 at 18:56
  • E.error is not null, and updated code – Rob Jun 17 '13 at 18:57
  • 1
    if e.Error is not null then thats your problem, see what the error is. Basically your backgroundworker ended due to an error – Sayse Jun 17 '13 at 18:58
  • Take a read of the "Caution" section within the MSDN documentation for CancelAsync...http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.cancelasync.aspx. There is a chance that Cancelled flag may not be set even though a cancel request is made. – MotoSV Jun 17 '13 at 19:00
  • @MotoSV He's calling close from the BackgroundWorker's `RunWorkerCompleted` event, which is run in the UI thread. – Servy Jun 17 '13 at 19:01
  • I've added an answer with a way for you to get to the root of your problem. (too long for a comment) – Sayse Jun 17 '13 at 19:07
  • I have updated the code, seems the e.cancel is not working. – Rob Jun 17 '13 at 20:29
  • 1
    Do you have multiple background workers? I see a reference to `worker` and `bw`. – LarsTech Jun 17 '13 at 21:01

3 Answers3

2
   if (e.Cancelled)

That's fundamentally wrong. You can never be 100% sure that it will be set. Canceling a BGW is always a race condition, the BGW might have been busy exiting when you called its CancelAsync() method so never saw the CancellationPending set to true so never assigned e.Cancel = true in the DoWork event handler.

All you know for a fact is that mClosePending is reliable, since it was set to true on the UI thread. So always call Close() it it is set to true, regardless of the e.Cancelled state.

And yes, checking e.Error doesn't hurt either. But still check mClosePending.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Your code snippet is insufficient, I can't see exactly where the cancel test is located. Putting it at the start of the DoWork event handler is a common mistake. But that wasn't the point of my answer, the point was that you shouldn't check e.Cancelled because it is not reliable. – Hans Passant Jun 17 '13 at 20:54
1

As stated in my comment, your BackgroundWorker has ended due to an error, try adding the following at the top of your run worker completed. Once this error has been resolved your question will be more answerable.

if(e.Error != null)
     MessageBox.Show(e.Error.toString());//Put a breakpoint here also
Sayse
  • 42,633
  • 14
  • 77
  • 146
  • @user1977434 - Is the background worker even running? what is bw_restarts value? you should use Breakpoints instead of Messagebox.Show, there are plenty of tutorials on how to do this – Sayse Jun 17 '13 at 20:30
0

CancelAsync doesn't actually abort your thread or anything like that. It sends a message to the worker thread that work should be cancelled via BackgroundWorker.CancellationPending. Your DoWork delegate that is being ran in the background must periodically check this property and handle the cancellation itself.

Look at this:

    private BackgroundWorker background;

    private void Form1_Load(object sender, EventArgs e)
    {
        background = new BackgroundWorker();
        background.WorkerSupportsCancellation = true;
        background.DoWork += BackgroundOnDoWork;
        background.RunWorkerCompleted += BackgroundOnRunWorkerCompleted;

        background.RunWorkerAsync();
    }

    private void BackgroundOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
    {
        MessageBox.Show("stop");
    }

    private void BackgroundOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
    {
        // your doWork loop should check if someone don't call background.CancelAsync();
        while (!background.CancellationPending) 
        {
            // do something
        }
    }

    private void ButtonClick(object sender, EventArgs e)
    {
        background.CancelAsync();
    }
nirmus
  • 4,913
  • 9
  • 31
  • 50
  • Checking the parameter in your while loop isn't going to work. The parameter values aren't changing. It should probably look something like `while (!background.CancellationPending)` – LarsTech Jun 17 '13 at 21:45
  • yea, sure. I changed it. I add also `background.WorkerSupportsCancellation = true;` - without it, it is not possible to call `cancelAsync` – nirmus Jun 17 '13 at 21:50