0

I'm creating a chat application in which multiple users can enter their messages and send them to the server over tcp (networkstream).

I have the following code for receiving messages:

private void ReceiveData()
    {
        Task.Run(() =>
        {
            int bufferSize = 1024;
            string message = "";

            byte[] buffer = new byte[bufferSize];
            _NetworkStream = _TcpClient.GetStream();
            AddMessage("Connected!");

            while (true)
            {
                int readBytes = _NetworkStream.Read(buffer, 0, bufferSize);
                message = Encoding.ASCII.GetString(buffer, 0, readBytes);
                Console.WriteLine("I received a message: " + message);

                if (message.Equals("bye"))
                {
                    break;
                }

                AddMessage(message);
            }

            buffer = Encoding.ASCII.GetBytes("bye");
            _NetworkStream.Write(buffer, 0, buffer.Length);

            _NetworkStream.Close();
            _TcpClient.Close();

            AddMessage("Connection closed!");
        });
    }

Now when I call AddMessage (which I call from a different Thread, thus a different context) My application crashes. Which is quite logical given my AddMessage code:

private void AddMessage(string message)
    {
        this.ListBox_Messages.Items.Add(message);
    }

My question is, is the addmessage function responsible for executing this on the ui thread or the function caller, in this case ReceiveData() and what would be the best and most modern way to implement it?

Thank you in advance!

juser
  • 13
  • 4
  • 1
    Do you have plenty of examples inside StackOverflow, like [this](https://stackoverflow.com/questions/661561/how-do-i-update-the-gui-from-another-thread). – Nassiel Feb 17 '19 at 15:36
  • Questions like "What is the best and most modern way to [do something]" are unanswerable here. Any answer provided will be obsolete five minutes from now. – Robert Harvey Feb 17 '19 at 15:36
  • 1
    Possible duplicate of [How do I update the GUI from another thread?](https://stackoverflow.com/questions/661561/how-do-i-update-the-gui-from-another-thread) –  Feb 17 '19 at 15:37
  • @nassiel: Isn't it simply `Control.Invoke()`? – Robert Harvey Feb 17 '19 at 15:38
  • @nassiel According to my teacher this is outdated and we're not allowed to use it – juser Feb 17 '19 at 15:44
  • @juser It really depends on your teacher requirements, but one way would be to call `var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext()` **outside** of Task.Run. Then you can use that scheduler to switch back to the UI thread: `Task.Factory.StartNew(() => AddMessage(message), CancellationToken.None, TaskCreationOptions.None, uiScheduler);` – Kevin Gosse Feb 17 '19 at 16:13
  • Another way would be to use `Progress`: https://learn.microsoft.com/en-us/dotnet/api/system.progress-1?view=netframework-4.7.2 – Kevin Gosse Feb 17 '19 at 16:14
  • I would also look at [Reactive extensions](https://github.com/dotnet/reactive). – Paulo Morgado Feb 17 '19 at 17:58

1 Answers1

2

Did your teacher actually TEACH you any of these "modern methods"?!

Tell him or her there is nothing wrong with going back to basics:

private void AddMessage(string message)
{
    if (this.ListBox_Messages.InvokeRequired)
    {
        this.ListBox_Messages.Invoke((MethodInvoker)delegate {
            this.ListBox_Messages.Items.Add(message);
        });
    }
    else
    {
        this.ListBox_Messages.Items.Add(message);
    }          
}

It's simple, and it just works.

As a computer science teacher myself, I hate seeing these types of questions. Makes me wonder what the teachers are doing.

Teacher: "You must use this magical stuff that I haven't taught you yet!"

Giving your teacher the benefit of the doubt, are there any requirements for this application that you haven't shared with us?

Idle_Mind
  • 38,363
  • 3
  • 29
  • 40