Creating a new From in an eventhandler of a form, the event is invoked by another thread.
-
Please help, Here is my scenario: Mainform has a private ChatSocket object that uses a socket, and this ChatSocket object has its own thread to Receive() bytes in a while(true) loop. Whenever the socket receives data, its calls an event I made in ChatSocket called MessageReceived. The MessageReceivedEventArgs contain the string of who the message was from and the message itself. The Mainform is listening for this event and calls the OnMessageReceived( object sender, MessageReceivedEventArgs e ); This method checks a hashtable ( which is a private member in the Mainform ) to see if a ChatForm is already on the screen for the user the message came from. If it is not already on the screen ( in the hashtable ) it makes a new ChatForm. This ChatForm is made and i call Show() on it. It shows, but it is pure white and it says it is not responding. I tried async events as well, calling BeginInvoke() but that does not work either. The thread of the MainForm is named MainThread, and the thread for the socket recving is called RecvThread, however when I am in the event handler within the MainForm, the thread running has an empty string for a name. I read that only the thread that creates the form should use it. If i create the ChatForm with a OnClick event with one fo the buttons on the MainForm it works fine. I also noticed that when you click on the button the new chatform is not fully displayed untill the OnClick method has completly returned. In my case the thread that invokes the event (ChatSocket) goes back to Receive() and therfore never returns. That is why I thought the async events would work but it still does not.
-
Please help, Here is my scenario: Mainform has a private ChatSocket object that uses a socket, and this ChatSocket object has its own thread to Receive() bytes in a while(true) loop. Whenever the socket receives data, its calls an event I made in ChatSocket called MessageReceived. The MessageReceivedEventArgs contain the string of who the message was from and the message itself. The Mainform is listening for this event and calls the OnMessageReceived( object sender, MessageReceivedEventArgs e ); This method checks a hashtable ( which is a private member in the Mainform ) to see if a ChatForm is already on the screen for the user the message came from. If it is not already on the screen ( in the hashtable ) it makes a new ChatForm. This ChatForm is made and i call Show() on it. It shows, but it is pure white and it says it is not responding. I tried async events as well, calling BeginInvoke() but that does not work either. The thread of the MainForm is named MainThread, and the thread for the socket recving is called RecvThread, however when I am in the event handler within the MainForm, the thread running has an empty string for a name. I read that only the thread that creates the form should use it. If i create the ChatForm with a OnClick event with one fo the buttons on the MainForm it works fine. I also noticed that when you click on the button the new chatform is not fully displayed untill the OnClick method has completly returned. In my case the thread that invokes the event (ChatSocket) goes back to Receive() and therfore never returns. That is why I thought the async events would work but it still does not.
I have fixed the problem, but im not sure if there is a better way of doing it. I ended up making a class that displays the ChatBox form I created as ShowDialog(), this seems to noew display the form, as Show() did not work. However, ShowDialog() blocks the thread untill that form is closed. So I have to craete the ChatBox form then pass it to an object that starts a new thread just for it. I dont really like this way because if i have 20 clients im chatting with thats 20 extra threads. If anyone knows a better way please repsond. Sorry if my first post is a lot to take in, i didnt know how to explain my problem without giving all the background and details. original problem, trying to be more clear: a thread invokes an event, and a form (on the main thread) that is listening for the event creates a new form in the event hanlder, but the new form pops up and is "Not Responding". I see that the new form is actually created in the thread that invokes the event, not the thread that has the form (that has the event handler), I dont really like that, i thought events you fire off and then the form thread would work on the event handler, i think this is why i had a problem (creating a form in a different thread and calling show() if i called showDialog() it works but the other thread blocks). I even tried async events, but even though its not the thread that invoked the event now creating the new form( working on the event handler), but its an anonymous new thread working on the event handler. I dont know how to make it more clear, this does sound confusing reading it back to myself sorry again. The class to fix the problem, but creates a thread for each new form now: private class EEChatBoxThread { internal EEChatBoxThread( FormEEChatBox chatBox ) { _chatBox = chatBox; Thread thread = new Thread( new ThreadStart( ShowChatBox ) ); thread.Name = chatBox.Client; thread.IsBackground = true; thread.Priority = ThreadPriority.BelowNormal; thread.Start(); } private void ShowChatBox() { _chatBox.ShowDialog(); } private FormEEChatBox _chatBox; } Part of MainForm: public void OnMessageReceived( Object sender, MessageReceivedEventArgs e ) { FormEEChatBox chatBox = GetChatBox( e.From ); chatBox.MessageRecv( e.From, e.Message, e.Secure )
-
I have fixed the problem, but im not sure if there is a better way of doing it. I ended up making a class that displays the ChatBox form I created as ShowDialog(), this seems to noew display the form, as Show() did not work. However, ShowDialog() blocks the thread untill that form is closed. So I have to craete the ChatBox form then pass it to an object that starts a new thread just for it. I dont really like this way because if i have 20 clients im chatting with thats 20 extra threads. If anyone knows a better way please repsond. Sorry if my first post is a lot to take in, i didnt know how to explain my problem without giving all the background and details. original problem, trying to be more clear: a thread invokes an event, and a form (on the main thread) that is listening for the event creates a new form in the event hanlder, but the new form pops up and is "Not Responding". I see that the new form is actually created in the thread that invokes the event, not the thread that has the form (that has the event handler), I dont really like that, i thought events you fire off and then the form thread would work on the event handler, i think this is why i had a problem (creating a form in a different thread and calling show() if i called showDialog() it works but the other thread blocks). I even tried async events, but even though its not the thread that invoked the event now creating the new form( working on the event handler), but its an anonymous new thread working on the event handler. I dont know how to make it more clear, this does sound confusing reading it back to myself sorry again. The class to fix the problem, but creates a thread for each new form now: private class EEChatBoxThread { internal EEChatBoxThread( FormEEChatBox chatBox ) { _chatBox = chatBox; Thread thread = new Thread( new ThreadStart( ShowChatBox ) ); thread.Name = chatBox.Client; thread.IsBackground = true; thread.Priority = ThreadPriority.BelowNormal; thread.Start(); } private void ShowChatBox() { _chatBox.ShowDialog(); } private FormEEChatBox _chatBox; } Part of MainForm: public void OnMessageReceived( Object sender, MessageReceivedEventArgs e ) { FormEEChatBox chatBox = GetChatBox( e.From ); chatBox.MessageRecv( e.From, e.Message, e.Secure )
I think a better way might to be to use the InvokeRequired() and Invoke() methods in the OnMessageReceived method to marshal the event to the GUI thread. You should then be able to create and display the new form with no problems. See the article http://www.codeproject.com/cs/miscctrl/TSWizard.asp[^] for some examples of this. Chris Jobson
-
I think a better way might to be to use the InvokeRequired() and Invoke() methods in the OnMessageReceived method to marshal the event to the GUI thread. You should then be able to create and display the new form with no problems. See the article http://www.codeproject.com/cs/miscctrl/TSWizard.asp[^] for some examples of this. Chris Jobson
Thanks you sooo much Chris Jobson, I looked at this sample you recomended the day you sent it, and see it was only the object "Step4" in that solution that i would be concerned with. This worked perfectly and i just summed up a quick way to handle what i was trying to do and how this helped me for others to see. Again, thanks alot. code below of what i basically was trying to do: private void button1_Click(object sender, System.EventArgs e) { System.Threading.Thread formThread = new System.Threading.Thread( new System.Threading.ThreadStart( ShowNewFormThread ) ); formThread.IsBackground = true; formThread.Priority = System.Threading.ThreadPriority.BelowNormal; formThread.Start(); } private delegate void ShowNewFormThreadDelegate(); private void ShowNewFormThread() { if( InvokeRequired ) { ShowNewFormThreadDelegate del = new ShowNewFormThreadDelegate( ShowNewFormThread ); Invoke( del, new Object [] { } ); return ; } ++i; Form form = new Form(); form.Text = i.ToString(); form.Width = 50; form.Height = 50; form.Owner = this; _forms.Add( form.Text, form ); form.Show(); } private void OnFormClosed( object sender, EventArgs e ) { _forms.Remove( ( ( Form )sender ).Text ); } int i = 0; private Hashtable _forms = new Hashtable();