Click here to Skip to main content
15,900,511 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hi everyone, I am at the moment programming a chat client and server, but am having a hard time making my client work probably when the client receives a chat message from the server. Atm, I've found out that the client does get the right answer from the server and the form where the incoming chat message should appear is loading and opening, but freezes when I use myform.show();

I've tried this delegate and "invoker", but it still freezes codes:
C#
delegate void SetFormCallback(Form form);
private void Form_Changer(Form form)
{
    if (form.InvokeRequired)
    {
        SetFormCallback d = new SetFormCallback(Form_Changer);
        form.Invoke(d, new object[] { form });
    }
    else
    {
        form.Show();
    }
}


The code for receiving mesages is this which is running in a separate thread:
C#
private void RecieveFromServer()
        {
//strings used for deffrense requests
            string message = "";
            string userReciever = "";
            string request = "";
            int errorResponse = 1;
            string ConResponse = "";
            while (connected == true)
            {
                srReceiver = new StreamReader(tcpServer.GetStream());
                request = srReceiver.ReadLine();
                if (request == "message")
                {
                    userReciever = srReceiver.ReadLine();
                    userName = srReceiver.ReadLine();
                    message = srReceiver.ReadLine();
//checks a global dictonary if the user that send the message already is a 
//receiver in another window(keys getting deleted from chat form on form close)
                    if (!chatWindowDict.ContainsKey(userReciever))
                    {
//main problem starts here
//chat form here is a global varible
                        chatForm = new ChatForm(chatWindowDict);
                        chatWindowDict.Add(userReciever, chatForm);
                        chatForm.userReciever = userreciever;
                        chatForm.userName = this.userName;
                        chatForm.tcpServer = this.tcpServer;
                        chatForm.formSender = this;
                        this.Form_Changer(chatForm);
                        this.add_chat_text("\n" + userReciever + " Says: \n" + message);
                    }
                    else
                    {
//this works fine because the window already is open.
                        chatForm = chatWindowDict[userReciever];
                        this.add_chat_text("\n" + userReciever + " Says: \n" + message);
                    }
                }


As said every time the client recieves messages from the server, the new chat form freezes and also does some funny stuff to the main form, but I don't know what and my debugger does not say anything, also the chat form does not have any onload events which could cause something to freeze it.

Any ideas??? Thanks.

- Jackie
Posted
Updated 19-Jun-11 15:43pm
v11

No, this is not how to work with threads in UI. I don't even want to think what exactly happens if you're doing such things, I'll just explain how to re-design it.

You should keep all the UI in a single thread as it is.

All the calls to UI methods, properties and constructors should be done only from the UI threads, period.

You're doing networking in a separate, not UI thread. This is absolutely correct. You have to. Everything using blocking call or execution taking any considerable time should be done in a separate thread. The only problem is working with UI in those thread. You cannot call anything on UI, but you should communicate with UI. For this purpose, you need to use method Invoke or BeginInvoke of System.Windows.Threading.Dispatcher or System.Windows.Forms.Control.

Please see my past answers for detailed explanation of how it works:
Control.Invoke() vs. Control.BeginInvoke()[^],
Problem with Treeview Scanner And MD5[^].

You do just the opposite: you used Invoke in the UI thread, where it makes no sense (just a call works) and do not use it in your non-UI thread, which cannot work.

As to using threads for networking, see also my skeleton design in my past answer; it should be very close to what you want to do: Multple clients from same port Number[^].

See also the collection on my past answers on using threads:
How to get a keydown event to operate on a different thread in vb.net[^],
Control events not firing after enable disable + multithreading[^].

Good luck,
—SA
 
Share this answer
 
When your program starts out, at some place where you are sure you are in the UI thread, you can save the value of Dispatcher.CurrentDispatcher in an easily accessible location, e.g. a member variable named _dispatcher.

_dispatcher = Dispatcher.CurrentDispatcher;


Next, change the block of code that you have identified as caused a problem to a method:

private void AddMessageToNewForm(string userReceiver, string message)
{
  chatForm = new ChatForm(chatWindowDict);
  chatWindowDict.Add(userReciever, chatForm);
  chatForm.userReciever = userReciever;
  chatForm.userName = this.userName;
  chatForm.tcpServer = this.tcpServer;
  chatForm.formSender = this;
  this.Form_Changer(chatForm);
  this.add_chat_text("\n" + userReciever + " Says: \n" + message);
}


and then in place of all that code, use Dispatcher.Invoke to force the code to be run in the UI thread.

if (!chatWindowDict.ContainsKey(userReciever))
{
  _dispatcher.Invoke(DispatcherPriority.Normal,
     new Action<string, string>(AddMessageToNewForm), userReceiver, message);
}


I agree with the previous responder that the use of Invoke inside Form_Changer is not the right way to proceed.
 
Share this answer
 
Comments
Jackie00100 20-Jun-11 8:29am    
Ty for answer but i cant find the dispatcher tool/reference in threading any where...
jeanlibera 20-Jun-11 10:00am    
It's System.Windows.Threading.Dispatcher. Here's a link: http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.currentdispatcher.aspx
Jackie00100 20-Jun-11 12:42pm    
well i must be blind or it isn't there cos i only have "forms" under system.windows but i guess i can download the dll from somewhere and still use it yes?
jeanlibera 20-Jun-11 13:25pm    
It's in WindowsBase.dll

.NET Framework - Supported in: 4, 3.5, 3.0
.NET Framework Client Profile - Supported in: 4, 3.5 SP1


System.Windows.Forms.Control.Invoke, which is what you are using in your Forms_Changed method currently, is an older method which should do the same thing, although I have never personally used it.
Jackie00100 20-Jun-11 16:04pm    
ty SO much friend i owe you one its works very well now so tyvm :) even that it does work now may i please ask you one last thing; what is this part: "new Action<string, string="">" of the code do that the only thing i haven't figured out what does if you can tell me i'll be glad, but again thanks alot! :D
You cannot create forms on anything other than the UI (startup) thread. You also canot create any UI controls or manifpulate any controls from anything other than the UI thread.

To do this from a background thread, you have to Invoke functions on the UI thread to do the work for the background thread.

Read this[^].
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900