0
\$\begingroup\$

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.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Er, is this WinForms/WPF? I didn't think they were compatible with XNA.. \$\endgroup\$ Jun 18, 2011 at 19:50
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Jun 19, 2011 at 2:29
  • \$\begingroup\$ 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. \$\endgroup\$
    – user1430
    Jun 20, 2011 at 15:58

2 Answers 2

1
\$\begingroup\$

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.BeginInvoke(new InvokeDelegate(UpdateStartButtonCallback));
}

private void UpdateStartButtonCallback()
{
    startGameButton.Text = "blah blah";
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ "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") \$\endgroup\$ Jul 22, 2011 at 17:18
0
\$\begingroup\$

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 :)

\$\endgroup\$
7
  • \$\begingroup\$ He is already using Invoke(), which is the same as BeginInvoke() but synchronous. \$\endgroup\$ Jun 19, 2011 at 16:38
  • \$\begingroup\$ he should use BeginInvoke, which lets the background thread go about its business while the work item gets dispatched to the UI thread. \$\endgroup\$ Jun 20, 2011 at 17:15
  • \$\begingroup\$ @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. \$\endgroup\$ Jun 20, 2011 at 19:09
  • \$\begingroup\$ 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 :-) \$\endgroup\$ Jun 20, 2011 at 19:55
  • \$\begingroup\$ @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. \$\endgroup\$
    – Tinco
    Jun 21, 2011 at 21:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .