Thread problem updating Windows Forms control in XNA C#

I'm development a network card game, and for now i've two players connected but there is a problem with one of them, this one can't do anything on the game. Looks that screen was blocked. I'm think that is because a code i used before.

That code is:

if (InvokeRequired)
{
this.Invoke(new MethodInvoker(delegate
{

...

}));
return;
}


The code above is surrounding code to changing Button values, make connection with server and create game window. Without this code a warning is shown.

InvalidOperationException was unhandled

Cross-thread operation not valid: Control 'startGameButton' accessed from a thread other than the thread it was created on.

• Er, is this WinForms/WPF? I didn't think they were compatible with XNA.. – BlueRaja - Danny Pflughoeft Jun 18 '11 at 19:50
• Well, you could use them with XNA. But this question obviously has little to do with XNA. Luis could you explain what technology you are using? It sound like WPF or Silverlight. – Andrew Russell Jun 19 '11 at 2:29
• Can you explain your problem better? Is the problem that the screen (UI) becomes blocked an unresponsive, or is the problem that you get this exception? It's unclear to me because it sounds like you're saying that without the Invoke() code you show, an InvalidOperationException "warning" is shown. – Josh Jun 20 '11 at 15:58

Win Forms only allows the UI thread to access and create UI Controls. There is an inbuilt way to run delegates on the UI thread for particular control: Control.BeginInvoke(): http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx.

So you would need something like:

 if (BeginInvokeRequired)
{
startGameButton.BeginInvoke(new InvokeDelegate(delegate()
{
startGameButton.Text = "blah blah";
}));
}
else
{
...
}


(If your code is in the startGameButton as it seems to be just replace startGameButton with this).

Incidentally there are few bad things with your original code. Notice I have removed your early return in the if block and I wrap the rest of the method in the else - this is because I am using BeginInvoke() not Invoke() which will return immediately - your delegate will be placed on a queue and be run when UI thread can run it - using Invoke you would have to wait until the UI thread has run it which is unneccesary (it should be run straight away anyway as the UI should not have long running operations to perform).

You needn't use anonymous delegates by the way:

public void UpdateStartButton()
{
}

{
startGameButton.Text = "blah blah";
}

• "You needn't use anonymous delegates by the way" - In fact, delegate syntax is not required either (since .Net 3.0 I believe). BeginInvoke(UpdateStartButtonCallback) works exactly the same. If you're using .Net 3.5 or greater, since the code is only one line, a simple lambda expression would work too: BeginInvoke(() => startGameButton.Text = "blah blah") – BlueRaja - Danny Pflughoeft Jul 22 '11 at 17:18

Looks like you're using WinForms for your windows. You're not allowed to run WinForms control delegates on a thread that does not own said control.

The old way of working around this is described here: http://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.80).aspx

Though instead I would take the new school route and use BeginInvoke: http://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.80).aspx

Which just lets you forget about any of that boilerplate code :)

• He is already using Invoke(), which is the same as BeginInvoke() but synchronous. – BlueRaja - Danny Pflughoeft Jun 19 '11 at 16:38
• he should use BeginInvoke, which lets the background thread go about its business while the work item gets dispatched to the UI thread. – Joel Martinez Jun 20 '11 at 17:15
• @Joel: Unless he needs to wait for the result of the computation, or wants to let it finish for some other reason. In any case, if Invoke() does not work, BeginInvoke() will not work either, so this answer is incorrect. – BlueRaja - Danny Pflughoeft Jun 20 '11 at 19:09
• He says "Looks that screen was blocked" when using the synchronous Invoke ... it stands to reason that he should decouple the two threads by using BeginInvoke. Of course, without more info it's hard to say :-) – Joel Martinez Jun 20 '11 at 19:55
• @blueraja did I misread the msdn page? It says that unlike Invoke() which must be called on the appropriate thread, BeginInvoke() will just always work. I haven't tried it myself but that is what I take from the msdn page. – Tinco Jun 21 '11 at 21:19