NetworkStream.BeginRead and Forms threading

  • Thread starter Stephen Brooker
  • Start date
S

Stephen Brooker

Hi all,

I've got a basic TCP app that is giving me trouble. I have a separate
class that takes care of the TCP connection, and uses the NetworkStreams
BeginRead and EndRead with a callback function to deal with the server
response. All works well and the data is received OK. Once all the data
is received, the connection is closed and I fire an event indicating all
is finished. The event is handled in the main form of the application
and I can work with the returned data OK.

The problem arises when I try to add some of the data to a TreeView. It
complains that only the creating thread can modify the TreeViews data
and I should use BeginInvoke etc (all this so far I understand). So I
assume control is still with the thread created by BeginRead? Am I
correct? If so, is there any way of forcing control to return to the
main forms threads once the event is fired for the data being received?
I've been able to set values on several other controls, the TreeView is
the only one giving me problems (why is it so picky when none of the
other controls are).

TIA

Steve.
 
J

Jon Skeet [C# MVP]

Stephen Brooker said:
I've got a basic TCP app that is giving me trouble. I have a separate
class that takes care of the TCP connection, and uses the NetworkStreams
BeginRead and EndRead with a callback function to deal with the server
response. All works well and the data is received OK. Once all the data
is received, the connection is closed and I fire an event indicating all
is finished. The event is handled in the main form of the application
and I can work with the returned data OK.

The problem arises when I try to add some of the data to a TreeView. It
complains that only the creating thread can modify the TreeViews data
and I should use BeginInvoke etc (all this so far I understand). So I
assume control is still with the thread created by BeginRead? Am I
correct?

The thread the event handler gets called on will be whatever thread
raises the event - probably a threadpool thread, yes. (BeginRead
doesn't necessarily "create" a thread though, and there's no guarantee
that all the data will be read by one thread - usually you call
BeginRead multiple times until all the data has been read, and the
callbacks for those calls could each happen on a different thread.)
If so, is there any way of forcing control to return to the
main forms threads once the event is fired for the data being received?

By using BeginInvoke (or Invoke) exactly as it says you should.
I've been able to set values on several other controls, the TreeView is
the only one giving me problems (why is it so picky when none of the
other controls are).

You've been lucky, that's all. The golden rule of Windows Forms
threading is that you don't do *anything* with a control apart from
BeginInvoke, EndInvoke, Invoke, InvokeRequired, or CreateGraphics,
unless you're running on the thread which created the control.

See http://www.pobox.com/~skeet/csharp/threads/winforms.shtml
 
S

Stephen Brooker

You've been lucky, that's all. The golden rule of Windows Forms
threading is that you don't do *anything* with a control apart from
BeginInvoke, EndInvoke, Invoke, InvokeRequired, or CreateGraphics,
unless you're running on the thread which created the control.

See http://www.pobox.com/~skeet/csharp/threads/winforms.shtml

OK, thanks Jon.

So does that effectively mean that every function in the main form that
modifies the GUI, and gets called after the TCP connection is
established needs modification using Invoke etc?
 
J

Jon Skeet [C# MVP]

Stephen Brooker said:
OK, thanks Jon.

So does that effectively mean that every function in the main form that
modifies the GUI, and gets called after the TCP connection is
established needs modification using Invoke etc?

If it's still in a thread other than the UI thread, yes.
 
S

Stephen Brooker

Jon said:
If it's still in a thread other than the UI thread, yes.

So is there no way to force control to return to the main thread and
stop running on the threadpool thread? I can use Invoke etc, but that
still returns control to the existing thread doesn't it (certainly seems
to with my code)?

Apologies for repeating my question but I'm trying to make sure I
understand this properly. This is the first time I've mucked about with
TCP (and indirectly threads) in C# and it seems to introduce an awful
lot of stuffing about simply to keep GUI responsiveness. 90% of my code
will execute after the TCP connection is established, so there is a lot
of extra code that will need to be changed/added. There's got to be an
easier way.

Thanks for your help by the way.
 
J

Jon Skeet [C# MVP]

Stephen Brooker said:
So is there no way to force control to return to the main thread and
stop running on the threadpool thread? I can use Invoke etc, but that
still returns control to the existing thread doesn't it (certainly seems
to with my code)?

Just call BeginInvoke to another method and then return from the
current method. That will execute the other method back on the main UI
thread and then let the threadpool thread return to the pool.

You can't "shift" a stack from one thread to another though.
Apologies for repeating my question but I'm trying to make sure I
understand this properly. This is the first time I've mucked about with
TCP (and indirectly threads) in C# and it seems to introduce an awful
lot of stuffing about simply to keep GUI responsiveness. 90% of my code
will execute after the TCP connection is established, so there is a lot
of extra code that will need to be changed/added. There's got to be an
easier way.

Not really. It's a bit of a pain, but that's how you have to do it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top