Reputation: 47
I've made a chat system and I got this error:
Cross-thread operation not valid: 'MessageBox' etc.
What I have done: I've added an invoke. Here is the code:
Invoke(new Action(() => messageBox.Items.Add(usersName.Text + ": " + receivedMessage)));
The problem is, it basically sends a message from the other user which is blank. This is because I'm connected to the chat locally. Here is a picture:
Receiving messages:
private void MessageCallBack(IAsyncResult aResult)
{
try
{
byte[] receivedData = new byte[1500];
receivedData = (byte[])aResult.AsyncState;
ASCIIEncoding aEncoding = new ASCIIEncoding();
string receivedMessage = aEncoding.GetString(receivedData);
Invoke(new Action(() => messageBox.Items.Add(usersName.Text + ": " + receivedMessage)));
buffer = new byte[1500];
socket.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref theirIp, new AsyncCallback(MessageCallBack), buffer);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Sending messages:
private void sendBtn_Click(object sender, EventArgs e)
{
try
{
if (messageTb.Text == "")
{
return;
}
else
{
ASCIIEncoding eEncoding = new ASCIIEncoding();
byte[] msg = new byte[1500];
msg = eEncoding.GetBytes(messageTb.Text);
socket.Send(msg);
messageBox.Items.Add(yourName.Text + ": " + messageTb.Text);
messageTb.Clear();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
this.ActiveControl = messageTb;
}
Upvotes: 2
Views: 583
Reputation: 567
This exception occurs whenever you are trying to access a control in a different thread other than the form's main thread.
I use the bellow simple log mechanism, this is only suitable for a simple application.
private delegate void LogDelegate(ListBox messageBox, string data);
private LogDelegate _logDelegate;
private void Log(ListBox messageBox, string data)
{
if (messageBox.InvokeRequired)
{
LogDelegate logDelegate = Log;
Invoke(logDelegate, messageBox, data);
}
else
{
messageBox.Items.Add(data);
}
}
public Form1()
{
InitializeComponent();
//don't forget, initialize the delegate
_logDelegate = Log;
}
private void btn_Start_Click(object sender, EventArgs e)
{
Log("Anything to log");
}
private void MessageCallBack(IAsyncResult aResult)
{
try
{
//Instead of Invoke use
//Invoke(new Action(() => messageBox.Items.Add(usersName.Text + ": " + receivedMessage)));
Log("Anything to log");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
As I said, the code can be used anywhere and is simple. But for more complex logging mechanism and better performing use Log4Net or NLog.
Upvotes: 2
Reputation: 2077
If the value of the receivedMessage
variable changes before the invoked Action executes, the new value of that variable will be used - if it's functioning in the same way as your messageTb.Text
example, the value is cleared immediately, and the invoked Action will only see the post-Clear blank value. Try copying the usersName.Text + ": " + receivedMessage
string into a single-use variable and referencing that in your Invoke, e.g.
string newMessage = usersName.Text + ": " + receivedMessage;
Invoke(new Action(() => messageBox.Items.Add(newMessage)));
Upvotes: 0