I am completely lost in what is really causing the problem. So rather trying to explain the problem, I might as well as get straight to the code with the problem. Here is the layout of my program:
private void connection_OnMessage(object sender, agsXMPP.protocol.client.Message msg)
{
if (!string.IsNullOrEmpty(msg.Body) && ((msg.XDelay != null && msg.XDelay.Stamp.Date == DateTime.Today) || msg.XDelay == null))
{
agsXMPP.Jid JID = new Jid(msg.From.Bare);
int rowIndex = chatLog.Rows.Add();
chatLog.Rows[rowIndex].Cells["chatNameColumn"].Value = JID.User;
chatLog.Rows[rowIndex].Cells["chatMessageColumn"].Value = msg.Body;
//Begin line of the problem
if (IncomingMessage != null)
IncomingMessage(this, JID.User, msg.Body);
//End of the problem
}
}
The above code snippet is of class A. After starting up the program, this class makes the connection to the server. Right after being connected, this code snippet is rapidly fired about 20 times, once per line of message. (There are already about 20 lines of message in the chat log.) Since only one message makes it through the if condition, the lines commented with the problem is only run once. Those lines fire the code snippet below of class B.
(Around the time class A is firing, I have another class like A that fires the similar event to be handled by class B the same way, which will be handled by class C.)
private void newSource_IncomingMessage(IChatSource sender, string user, string message)
{
UpdatedMessageEventHandler temp = UpdatedMessage;
if (temp != null)
temp(sender, user, message);
}
The above code snippet of class B fires the code snippet below of class C.
private void chatManager_UpdatedMessage(IChatSource source, string user, string message)
{
if (!source.Muted)
{
updateMessage(source, user, message);
}
}
delegate void UpdateMessageCallback(IChatSource source, string user, string message);
private void updateMessage(IChatSource source, string user, string message)
{
if (allDataGridView.InvokeRequired)
{
UpdateMessageCallback d = new UpdateMessageCallback(updateMessage);
Invoke(d, new object[] { source, user, message });
}
else
{
int row = allDataGridView.Rows.Add();
allDataGridView.Rows[row].DefaultCellStyle.ForeColor = source.TextColor;
allDataGridView.Rows[row].Cells["NameColumn"].Value = user;
allDataGridView.Rows[row].Cells["MessageColumn"].Value = message;
if (!MenuItem.Checked)
{
MenuItem.Checked = true;
Show();
}
}
}
Here is what I tried to do to fix the problem, but the code is removed already:
Here is what happened:
In conclusion, I don't know what is causing the UI thread to be blocked. Any pointer or what I might do wrong?
The problem is that you're calling methods crossthreading. This can lead to deadlocks.
You could solve this, adding the messages on a concurrent queue and on a timer (gui thread) checking the queue and adding the messages to controls.
This is not a complete solution, but a method to prevent crossthread method invoking
Like: (PSEUDO) (wrote online on the site)
// dataholder
public class ChatMsg
{
public string User {get;set;}
public string Message {get;set;}
}
// message store
private List<ChatMsg> _messages = new List<ChatMsg>();
// timer
private Timer _timer;
// callback for you chatapi?? (like you wrote)
private void newSource_IncomingMessage(IChatSource sender, string user, string message)
{
UpdatedMessageEventHandler temp = UpdatedMessage;
// lock the store
lock(_messages)
_messages.Add(new ChatMsg { User = user, Message = message });
}
// constructor
public Form1()
{
// create the check timer.
_timer = new Timer();
_timer.Interval = 100;
_timer.Tick += Timer_Tick;
_timer.Start();
}
// timer method
private void Timer_Tick(object sender, EventArgs e)
{
// copy of the queue
ChatMsg[] msgs;
// lock the store and 'move' the messages
lock(_messages)
{
msgs = _messages.ToArray();
_messages.Clear();
}
if(msgs.Length == 0)
return;
// add them to the controls
foreach(var msg in msgs)
{
// add the message to the gui controls... (copied from your question)
int row = allDataGridView.Rows.Add();
allDataGridView.Rows[row].DefaultCellStyle.ForeColor = source.TextColor;
allDataGridView.Rows[row].Cells["NameColumn"].Value = user;
allDataGridView.Rows[row].Cells["MessageColumn"].Value = message;
}
}
Something like that..
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments