Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cross-thread operation not valid, even if using InvokeRequired [duplicate]

I have a form with my custom controls on it.

I have a method in my Form:

private void SetEnabledOnControls(bool val)
{
  if (InvokeRequired)
  {
      Invoke((Action<bool>)SetEnabledOnControls, val);
  }
  else
  {
       //do the work - iterate over child controls, 
       //and they iterate over their children, etc...
  }
}

And inside the methods that are on the else branch I get the mentioned exception:
Cross-thread operation not valid: Control 'txtNumber' accessed from a thread other than the thread it was created on.

My scenario is actually a bit more complicated - I just extrapolated this as an example. What's actually going on is that I'm using WorkflowFoundation - I have StateMachineActivity (CTP1) running in WorkflowApplication (which runs in it's own thread), I subscribed to it's event, and from there I'm calling SetEnabledOnControls. Also, I'm using bookmarks to resume my workflow (and also, there's MEF on the side, not involved in the scenario).

All of that is irrelevant to my obvious misunderstanding of the InvokeRequired - how is it possible that if the InvokeRequired is false, I have cross threaded exception? I don't create any of the controls 'manually' - it's all there in the Initialize() placed by designer.

Can anyone shed some light on this?

Thanks!

EDIT Using GWLlosa suggestion, I've tracked the ThreadId using System.Threading.Thread.CurrentThread.ManagedThreadId. Now comes the weird part... the thread id in Initialize() is 10. Between passing the first 2 states, it comes in with Id 13 - InvokeRequired was true, and it invoked correctly. BUT, after the second state, when it enters SetEnabledOnControls it's again 13, but this time InvokeRequired is false! How come!? Later on, of course, it fails to change child controls (not surprising). Could it be that the Form somehow changed the thread it's living in??

EDIT 2 Now I'm calling with:

 if (IsHandleCreated)
 {
     Invoke((Action<bool>)SetEnabledOnControls, val);
 }

and it has IsHandleCreated to true, but still fails with what devSpeed pointed at.

EDIT 3 FACEPALM :) One of the buttons that were resuming state was at first CancelButton for the Form. When it was removed from the property as such, the codebihind still had the DialogResult=Cancel for it - so my form was indeed closing, and of course it was missing the handle so the InvokeRequired didn't return correct info, and hence the errors.

Thanks everyone! I learned a new thing today :)

like image 612
veljkoz Avatar asked Dec 16 '10 17:12

veljkoz


1 Answers

It might make your debugging easier if you log the thread ID when the controls are created (in the Initialize() function) and the thread ID just before you try to touch it. Generally, I've seen this happen when you've somehow created the controls on a thread other than the one you expect in the first place.

like image 162
GWLlosa Avatar answered Oct 06 '22 00:10

GWLlosa