Search code examples
c#backgroundworker

Cancelling BackgroundWorker While Running


I have an application in which I launch a window that displays byte data coming in from a 3rd party tool. I have included .CancelAsync() and .CancellationPending into my code (see below) but I have another issue that I am running into.

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    Thread popupwindow = new Thread(() => test());
    popupwindow.Start(); // start test script

    if(backgroundWorker.CancellationPending == true)
    {
       e.Cancel = true;
    }
}

private voide window_FormClosing(object sender, FormClosingEventArgs e)
{
   try
   {
      this.backgroundWorker.CancelAsync();
   }
   catch (Exception ex)
   {
      MessageBox.Show(ex.Message.ToString());
   }
}

Upon cancelling the test I get an `InvalidOperationException occurred" error from my rich text box in my pop-up window. It states that "Invoke or BeginInvoke" cannot be called on a control until the window handle has been created". I am not entirely sure what that means and would appreciate your help.

LogWindow code for Rich Text Box:

public void LogWindowText(LogMsgType msgtype, string msgIn)
    {
        rtbSerialNumberValue.Invoke(new EventHandler(delegate
        {
            rtbWindow.SelectedText = string.Empty;
            rtbWindow.SelectionFont = new Font(rtbWindow.SelectionFont, FontStyle.Bold);
            rtbWindow.SelectionColor = LogMsgTypeColor[(int)msgtype];
            rtbWindow.AppendText(msgIn);
            rtbWindow.ScrollToCaret();
        }));
    }

Solution

  • After reading your code; it appears the background worker completes nearly instantly; likely killing any threads that were spawned from it. More to the point; a background worker that is already stopped will throw "InvalidOperationException" when "CancelAsync" is called.

    I'd advise placing any GUI related work into caller instead of the background worker thread. This is an important consideration because you will get cross-thread exceptions and other strange behavior such as rather serious GUI refresh issues.

    The background worker "DoWork" method should be considered threaded already. You can see this by adding simple debug statements to your code.

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
            Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
    
            backgroundWorker1.RunWorkerAsync();
        }
    

    Finally; I'd add that CancellationPending works best when polled in a loop-construct like so,

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            foreach (var workItem in work)
            {
                workItem.Perform();
    
                if (backgroundWorker1.CancellationPending)
                {
                    break;
                }
            }
        }
    

    Hope this helps.