Cross Thread Communications

  • Thread starter AliR \(VC++ MVP\)
  • Start date
A

AliR \(VC++ MVP\)

Hi everyone,

I have a Socket derived class that parses the received data into a message,
populates a object with that information and then tries to send an event to
inform the owner of the socket that there is message to be processed. But
this is not working as the socket receiver method seems to be in a different
thread then the form that owns the socket.

The receive callback gets the data from the socket and process the
information, once it constructs a full message from it then it calls a
delegate if the delegate is set.

The method that handles this event needs to change some controls on the form
and when I do that I get the exception:
Cross-thread operation not valid: Control 'syncButton' accessed from a
thread other than the thread it was created on.

I would appreciate any suggestions on solving this.

class LSSocket : Socket
{
public event ProcessMessageHandler ProcessMessageEvent;

public void OnReceiveData(IAsyncResult)
{
....
if (ProcessMessageEvent != null)
{
ProcessMessageEvent(this, new ProcessMessageArgs(Msg));
}
}
}

class ProcessMessageArgs : System.EventArgs
{
public ProcessMessageArgs(LSMessage msg)
{
this.msg = msg;
}
public LSMessage msg;
}
delegate void ProcessMessageHandler(object sender, ProcessMessageArgs
e);

I would have had to use PostThreadMessage in native windows development, but
I can't figure out what I need to use in this situation.

AliR.
 
I

Ignacio Machin ( .NET/ C# MVP )

Hi everyone,

I have a Socket derived class that parses the received data into a message,
populates a object with that information and then tries to send an event to
inform the owner of the socket that there is message to be processed. But
this is not working as the socket receiver method seems to be in a different
thread then the form that owns the socket.

The receive callback gets the data from the socket and process the
information, once it constructs a full message from it then it calls a
delegate if the delegate is set.

The method that handles this event needs to change some controls on the form
and when I do that I get the exception:
Cross-thread operation not valid: Control 'syncButton' accessed from a
thread other than the thread it was created on.

I would appreciate any suggestions on solving this.

class LSSocket : Socket
{
public event ProcessMessageHandler ProcessMessageEvent;

public void OnReceiveData(IAsyncResult)
{
....
if (ProcessMessageEvent != null)
{
ProcessMessageEvent(this, new ProcessMessageArgs(Msg));
}
}
}

class ProcessMessageArgs : System.EventArgs
{
public ProcessMessageArgs(LSMessage msg)
{
this.msg = msg;
}
public LSMessage msg;
}
delegate void ProcessMessageHandler(object sender, ProcessMessageArgs
e);

I would have had to use PostThreadMessage in native windows development, but
I can't figure out what I need to use in this situation.

AliR.

Use Control.Invoke to execute the event in the UI thread.
 
A

AliR \(VC++ MVP\)

message
Use Control.Invoke to execute the event in the UI thread.

I looked at Control.Invoke, but wasn't really sure where it would apply. A
little more explanation would be great.

Are you saying that I have to use that in event hander method in my form
class to do the UI manipulation? Or am I supposed to use it in place of the
event hander call? Or am I supposed to call the event handler delegate
using the Invoke method?

Here is the event handler method:
public void ProcessMessage(object sender, ProcessMessageArgs e)
{
switch (e.msg.m_Command)
{
case MSG_SERVERIP: ServerIP = e.msg.m_Address;
ServerPort = 29308;
syncButton.Enabled = true;
break;
default: Debug.Print("Oh Oh");
break;
}
}

AliR
 
A

AliR \(VC++ MVP\)

AliR (VC++ MVP) said:
message


I looked at Control.Invoke, but wasn't really sure where it would apply.
A little more explanation would be great.

Are you saying that I have to use that in event hander method in my form
class to do the UI manipulation? Or am I supposed to use it in place of
the event hander call? Or am I supposed to call the event handler
delegate using the Invoke method?

Here is the event handler method:
public void ProcessMessage(object sender, ProcessMessageArgs e)
{
switch (e.msg.m_Command)
{
case MSG_SERVERIP: ServerIP = e.msg.m_Address;
ServerPort = 29308;
syncButton.Enabled = true;
break;
default: Debug.Print("Oh Oh");
break;
}
}

AliR

I think I got it. (Correctly or not I don't know.)
Beside the event member, I added a parent form object to the class of type
Control.

delegate void ProcessMessageHandler(LSMessage Msg);
class LSSocket : Socket
{
public event ProcessMessageHandler ProcessMessageEvent;
public Form ParentForm = null;

public void OnReceiveData(IAsyncResult)
{
//pares data into a LSMessage class (Msg)
....
if (ProcessMessageEvent != null && ParentForm != null)
{
// ProcessMessageEvent(this, new
ProcessMessageArgs(Msg));
ParentForm.Invoke(ProcessMessageEvent,Msg);
}
}
.....
}

Hopefully this is the right way of doing it.

AliR.
 
A

AliR \(VC++ MVP\)

Peter Duniho said:
[...]
public void ProcessMessage(object sender, ProcessMessageArgs e)
{
switch (e.msg.m_Command)
{
case MSG_SERVERIP: ServerIP = e.msg.m_Address;
ServerPort = 29308;
syncButton.Enabled = true;
break;
default: Debug.Print("Oh Oh");
break;
}
}

Try:

public void ProcessMessage(object sender, ProcessMessageArgs e)
{
switch (e.msg.m_Command)
{
case MSG_SERVERIP: ServerIP = e.msg.m_Address;
ServerPort = 29308;
syncButton.Invoke((MethodInvoker)delegate {
syncButton.Enabled = true } );
break;
default: Debug.Print("Oh Oh");
break;
}
}

Not only does that avoid having to track a specific parent control in your
event-raising class, IMHO it's better for the GUI-specific stuff to stay
in the GUI-specific class.

Pete

Very cool, thank you. I had no idea how to use Invoke! As you can tell
I'm a newbee.

AliR.
 
I

Ignacio Machin ( .NET/ C# MVP )

message




I looked at Control.Invoke, but wasn't really sure where it would apply. A
little more explanation would be great.

Are you saying that I have to use that in event hander method in my form
class to do the UI manipulation?

Yes, in windows forms the controls should only be accessed from the
UI thread. You can make an event to be executed in the UI thread (or
more exactly in the control's creation thread, that in the current
implementation is the UI) by using Control.Invoke.

Invoke what does is put a message in the message pump that will be
executed as any other message in a win. app.
 

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