0

I am trying to learn networking by making my own little network library. Currently I have a list of new clients that a code like this can use. The NewClientConnected() method returns true if there's anything in the list and removes the first element.

ConnectedClient newClient; // ConnectedClient is my class storing it's socket and stream and all that.
if(NewClientConnected(out newClient)
{
...handling new client, notification, etc...
}

Same goes for checking for new packets (prefixed slice of stream). I sought to take it to the next level and attempt to raise events when things like this happen and started with new connections. Problem is, the event is raised from another thread, causing an exception as the event is handled in the form1.cs.

How can I make sure the event is handled by the main thread from a static non-control class? Should I just keep doing what I do? (snippet above) I hear the idea of a consumer-produces relationship, it would still require a timer (uses its own thread) or another thread if I recall correctly.

I have tried to google it and look on here, but everyone seems to have a different problems. It is in a library project while another projects (my server and client test) is referring to it.

Thanks in advance.

Gisle Aune
  • 13
  • 4

2 Answers2

1

If the operations you want to perform interact with the user interface then you have to invoke them on the UI thread.

So instead of handling the event directly, try this:

// Somewhere in the form1 code:
Server.newConnectionEvent += ConnectionEVentHandler(myMethod)

public void myMethod()
{
  //Event method called from another thread
  //can only do things here that do affect the UI!
  this.Dispatcher.Invoke(CalledOnUIThread);
}

public void CalledOnUIThread()
{
  //Handle event on UI thread here
  //Can do things here that affect the UI
}

This code has to run from the form1 class, since it uses 'this'. So all you change (presumably, you didn't show your event handler code) is put the actual code that you want to run in a seperate method and then invoke that seperate method from the event handler.

See http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx for the API documentation on the dispatcher class.

See What is the definition of a UI thread? Is there only one UI thread in a .NET application? for a simple explanation of the UI thread.

Community
  • 1
  • 1
Onots
  • 2,118
  • 21
  • 28
  • How can I use that dispatcher in a static class? Or should I make some kind of event-thrower class that is instantiated upon Initializing server/successfull connection on client side? – Gisle Aune Jul 14 '11 at 08:38
  • You use it in form1.cs, and your form class isn't static. I will try to clarify the asnwer. – Onots Jul 14 '11 at 08:48
  • The event is thrown from a library's static class. I find it kind of bad to have the library project rely on the project reffering it having this code. I'll rather use the sollution above than trying to call a method from outside the dll's assembly. If I so manage to link it to a form by reference, how should I handle multi-form programs or Unity3D that I am also testing it on (no forms)? – Gisle Aune Jul 14 '11 at 08:54
  • I'm really curious about how you raise the event in the library and how you subscribe to it in the form. The library shouldn't need any reference to the form at all. – Onots Jul 14 '11 at 09:07
  • It is referred by the project, not the form. The reciever thread for a socket throws an event when finished reading a prefixed slice of the stream completely. Would Async make that easier? – Gisle Aune Jul 14 '11 at 09:20
  • Subscription is done by like Server.newConnectionEvent += ConnectionEVentHandler(myMethod). – Gisle Aune Jul 14 '11 at 10:02
0

Take a look at Control.Invoke and Control.BeginInvoke methods.

Control.Invoke - "Executes the specified delegate on the thread that owns the control's underlying window handle."

http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.begininvoke.aspx

This should fix your "another thread exception"

Ondra
  • 1,619
  • 13
  • 27
  • If every change done in the handled event require Control.invoke, then the old system (timer with if-conditions chopping off lists) works imho better – Gisle Aune Jul 14 '11 at 08:40
  • This approach is almost the same as the one with the Dispatcher. The difference is Control.Invoke is for WinForms, Dispatcher.Invoke is for WPF – Ondra Jul 14 '11 at 09:01
  • Can I have a disptacher in my static class (in the library project) that throes events to be handled on the main thread? – Gisle Aune Jul 14 '11 at 09:08