A: 

Use

if (InvokeRequired)
{
  //invoke
}
else
{
  //do
}
bleevo
He has that. If (InvokeRequired) { Invoke(); return; } is the same as your code.
Jonathan C Dickinson
Thanks bleevo and Jon, as my first comment indicated, I tried this, out of desparation, and I am not receiving the error in this method now, but another UI updating method, so I still cannot safely say if removing the return did the fix, or it's just still intermittency.
GONeale
Actually it is not. He doesn't have an else statement, just an additional appending if-statement. So given that InvokeRequired is not 100% reliable, he is running into cross-thread violations by accessing his panel from the thread.
David Anderson
Thanks David Anderson, thanks for the downvote Dickinson.
bleevo
@David, he doesn't need an else, he has a return.
Jonathan C Dickinson
@GoNeale, try using panelMain.Invoke(). Read my answer carefully.
Jonathan C Dickinson
@GoNeale: the key point of Jonathan's answer is understanding the difference between this.InvokeRequired and panelMain.InvokeRequired. this and panelMain are different Controls and might be owned by different threads.
cpeterso
+4  A: 

Most people see that error and see one thing, "you are not accessing this control from the main UI thread." In reality you can have 100 UI threads if you want (the behavior for this is not defined, but supported). Chances are panelMain is created on a different thread to (this); I can't see the code - but it looks like you are creating it in your worker/thread.

To confirm the behavior try this:

Action addAction = new Action (
   new delegate { panelMain.Controls.Add(UCLoadingScreen); } )
if(panelMain.InvokeRequired)
{
   panelMain.Invoke(addAction); // Breakpoint here.
}
else
{
   addAction();
}

Be prepared for a different error (a child control on a different thread to it's parent, not sure what error you will get, but I am pretty certain you will). This is not a fix.

A factory will fix this however:

public void CreateControl<T>() where T : new()
{
    if(InvokeRequired)
    {
        return (T)Invoke(new Func<T>(CreateControl<T>()));
    }
    return new T();
}

EDIT: panelMain might not be the thread 'violator', as I said, parenting controls from different threads is results in highly undefined behavior. Make sure all your controls are created in context of your main form's thread.

Jonathan C Dickinson
Hi Jon, I just tested this, and it steps into (panelMain.InvokeRequired) FYI, I was also going to mention to you that panelMain was created in the Win Form designer and would not have been created by any worker thread. But as you've understood, panelMain may not be the violator.
GONeale
Jon, due to messaging limitations on here, I have written my latest attempt in cepterso's comments. Please see and evaluate.
GONeale
+8  A: 

I suspect InvokedRevoked might be lying to you. A WinForm Control defers creation of the Control's underlying Win32 HWND until a method call actually needs it. InvokeRequired will return false if the HWND has not been created yet.

For a detailed explanation, see: "Mysterious Hang or The Great Deception of InvokeRequired"

If your background thread queries InvokeRequired before the UI thread has caused the Control to lazily create its HWND, InvokeRequired will (incorrectly) tell your background thread that it does not need to use Invoke() to pass control back to the UI thread. When the background thread then accesses the Control, BAM! "InvalidOperationException: Cross-thread operation not valid!"

The UI thread can manually force the Control to create its HWND handle to so Control.InvokeRequired will know the UI thread is the Control's owner:

Control control = new Control();
IntPtr handle = control.Handle; // if you ask for HWND, it will be created
cpeterso
Thanks cpeterso, I basically understand. My latest thought is, to place logic in an else statement as I am not receiving my error when I do. Let me explain..
GONeale
I understand code will not execute after the "return" statement. That is not my argument, as what has been written back and forth above. I believe it is working with the else statement due to as you say InvokeRequired lying to me..
GONeale
by adding all the logic in the else, only truly when Invoke is not required will the UI processing activate. From this angle, I believe is why it is working, not so much "return" vs "else" argument. What are your thoughts?
GONeale
@GONeale, if it isn't this it is definitely mine. Either way, both answers are valuable...
Jonathan C Dickinson
@cpeterso, so you are recommending to manually force the control (panelMain) to create it's HWND handle by declare "IntPtr handle.." directly underneath? This will soon become unwieldy as I have many UI elements created on the designer.
GONeale
@cpeterso, Your first statement, regarding deferred creation; could firing the thread from the constructor of my form have anything to do with these abnormalities? (which in turn fired the UI update method)?
GONeale
@cpeterso, PS. Thanks for the link, it's an interesting read.
GONeale
@cpeterso, eep. There could be my problem, the constructor - is it a non-GUI thread? Excerpt: "This will obviously wreck havoc if a code doing the BeginInvoke dance executes on a non-GUI thread."
GONeale
You might consider adding a debug assert or exception in your Controls' constructors that checks whether the current thread is the main UI thread. Your UI thread can save its thread ID in your Main function.
cpeterso
Ah that would be a good trick. Thanks cpeterso. In the end your article helped immensely and calling the thread from the constructor was the exact root of my problems. Thanks dude, dropped you a thanks and a post to that link you gave me on my blog too. =)
GONeale
Happy to help. If I can save other people from debugging this crazy problem, then my work here is done. <:)
cpeterso
Dude! You've saved lots of my time and sanity! +1.
Alex B
A: 

There's no such thing as an impossible cross threading error!

Mike Weller
lol hence my bracketed comment! but I needed to write something to get your attention :)
GONeale
A: 

I hope this works for you. I assume your gui stuff is on one thread. Just initialize this singleton and rely on it whenever you feel like calling Control.InvokeRequired property.

Cheers,

-Greg

public sealed class UiThread
{
  #region Singleton
  // Singleton pattern implementation taken from Jon Skeet's C# and .NET article www.yoda.arachsys.com/csharp/singleton.html

  UiThread() { }

  public static UiThread Instance { get { return Nested.instance; } }

  class Nested
  {
     // Explicit static constructor to tell C# compiler
     // not to mark type as beforefieldinit
     static Nested() { }

     internal static readonly UiThread instance = new UiThread();
  }
  #endregion

  int _uiThreadId = 0;

  public void SetUiThread(Thread thread)
  {
     if (_uiThreadId != 0)
        throw new ApplicationException("UI Thread has already been established!");

     if (thread.ManagedThreadId == 0)
        throw new ArgumentException("Unexpected thread id value of 0!");

     if (thread.IsBackground)
        throw new ArgumentException("Supplied thread should not be a background thread!");

     if (thread.IsThreadPoolThread)
        throw new ArgumentException("Supplied thread should not be a thread pool thread!");

     _uiThreadId = thread.ManagedThreadId;
  }

  /// <summary>
  /// It's possible for InvokeRequired to return false when running in background thread.
  /// This happens when unmanaged control handle has not yet been created.
  /// We second-guess Microsoft's implementation in this case, checking against foreground thread's Id.
  /// </summary>
  /// <param name="control">Control to check against.</param>
  public bool InvokeRequired(Control control)
  {
     if (control.InvokeRequired)
        return true;

     IntPtr unmanagedHandle = control.Handle;
     bool newResult = control.InvokeRequired;

     if (unmanagedHandle == IntPtr.Zero)
     {
        // Trace.WriteLine() call here forces unmanagedHandle's initialization, 
        //  even with optimizing compiler.
        Trace.WriteLine(string.Format("Control handle could not be established! Control was {0}.", control.ToString()));
     }

     bool retVal = InvokeRequired();

     // Break whenever the result of our check does not match theirs.
     Debug.Assert(retVal == newResult);

     // Return our InvokeRequired result over theirs 
     //   to keep with the tradition of updating controls from foreground only.
     return retVal;
  }

  /// <summary>
  /// Prefer to use overload with Control argument if at all possible.
  /// It's possible for InvokeRequired to return false when running in background thread.
  /// This happens when unmanaged control handle has not yet been created.
  /// We second-guess Microsoft's implementation in this case, checking against foreground thread's Id.
  /// </summary>
  public bool InvokeRequired()
  {
     if (_uiThreadId == 0)
        throw new ApplicationException("UI Thread has not been established!");

     return (Thread.CurrentThread.ManagedThreadId != _uiThreadId);
  }

}

GregC