Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception when closing Form (thread + invoke)

I have just started to learn about threads and methodinvoking in c#, but I have come across a problem which I couldn't find the solution of.

I made a basic C# form program which keeps updating and displaying a number, by starting a thread and invoke delegate.

Starting new thread on Form1_load:

private void Form1_Load(object sender, EventArgs e)
  {
        t = new System.Threading.Thread(DoThisAllTheTime);
        t.Start();
  }

Public void DoThisAllTheTime (which keeps updating the number) :

public void DoThisAllTheTime()
  {
     while(true)
      {
        if (!this.IsDisposed)
         {
           number += 1;
           MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
           this.Invoke(yolo);
         }
      }
  }

Now when I click the X button of the form, I get the following exception:

'An unhandled exception of type 'System.ObjectDisposedException' occurred in System.Windows.Forms.dll

Can't update a deleted object'

While I actually did check if the form was disposed or not.

EDIT: I added catch (ObjectDisposedException ex) to the code which fixed the problem. Working code:

  public void DoThisAllTheTime()
  {
     while(true)
      {
         number += 1;

         try {  
              MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
              this.Invoke(yolo);
             }
         catch (ObjectDisposedException ex)
             {
              t.Abort();
             }
      }
 }
like image 335
John Avatar asked Nov 02 '22 12:11

John


1 Answers

Your call to this.IsDisposed is always out of date. You need to intercept your form closing event and stop the thread explicitly. Then you won't have to do that IsDisposed test at all.

There are many ways you can do this. Personally, I would use the System.Threading.Tasks namespace, but if you want to keep your use of System.Threading, you should define a member variable _updateThread, and launch it in your load event:

_updateThread = new System.Threading.Thread(DoThisAllTheTime);
_updateThread.Start();

Then in your closing event:

private void Form1_Closing(object sender, CancelEventArgs e)
{
    _stopCounting = true;
    _updateThread.Join();
}

Finally, replace the IsDisposed test with a check on the value of your new _stopCounting member variable:

public void DoThisAllTheTime()
{
    MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
    while(!_stopCounting)
    {
        number += 1;
        this.Invoke(yolo);
    }
}
like image 180
Rob Lyndon Avatar answered Nov 13 '22 18:11

Rob Lyndon