6
votes

I have this application that freezes when calling the dispatcher.invoke for any control.

When i Call the Dispatcher in radiobutton, Grid, Image..etc the App freezes but without giving errors. any help please !!! thank you

I call the thread Method RunClient

private void RunClient()
    {

        TcpClient client;

        // instantiate TcpClient for sending data to server
        try
        {
            // Step 1: create TcpClient and connect to server

            client = new TcpClient();
            client.Connect(ip, 5001);

            // Step 2: get NetworkStream associated with TcpClient
            output = client.GetStream();

            // create objects for writing and reading across stream
            writer = new BinaryWriter(output);
            reader = new BinaryReader(output);

            string theReply = "";

            do
            {
                try
                {
                    // read the string sent to the server
                    theReply = reader.ReadString();

                    int i = 0;

                    foreach (var x in theReply.Split('#'))
                    {
                        ReadString[i] = x;
                        i++;
                    }

                    CheckConnection(ReadString[0]);



                }
                catch (Exception)
                {
                    //do nothing
                }

            } while (ReadString[6].Equals(" ") &&
                   connection.Connected);

            updatelabel = () => GameResult(ReadString[6]);
            Dispatcher.Invoke(new Action(updatelabel));

            if (!connection.Connected)
            {
                MessageBox.Show("The connection was lost. The game will be closed automatically.");
                writer.Close();
                reader.Close();
                output.Close();
                connection.Close();
                this.Close();
            }

        }
        // handle exception if error in establishing connection
        catch (Exception error)
        {
            MessageBox.Show("Check Internet Connectivity. Couldn't connect!");
        }


    }

when the code enters the method ( check connection ) and calls the dispatcher the app freezes.

     void CheckConnection(string ii)
    {
        try
        {
            if (ii.Equals("Connected"))
            {
                MessageBox.Show("A Connection was established");




                int x = Convert.ToInt32(ReadString[1]);

                if (x == 1)
                {

                    updatelabel = () => char1RadioButton2.IsEnabled = false;
                    char1RadioButton2.Dispatcher.Invoke(new Action(updatelabel));
                }

                else
                {
                    updatelabel = () => char5RadioButton2.IsEnabled = false;
                    char5RadioButton2.Dispatcher.Invoke(new Action(updatelabel));
                }


                updatelabel = () => CreatingGameGrid.Visibility = System.Windows.Visibility.Visible;
                CreatingGameGrid.Dispatcher.Invoke(new Action(updatelabel));



                updatelabel = () => JoinGameGrid.Visibility =        System.Windows.Visibility.Visible;
                JoinGameGrid.Dispatcher.Invoke(new Action(updatelabel));

            }
            else
            {
                MessageBox.Show("No Such Game found");
                this.Close();
            }
        }
        catch (Exception x)
        {
            MessageBox.Show(x.ToString());
        }
    }
1

1 Answers

11
votes

The Dispatcher.Invoke attempts to synchronously run the specified action on the Dispatcher Thread.

Assuming the RunClient is run on the Dispatcher Thread, and the while loop continues to run while you are trying to Invoke back onto the Dispatcher Thread, the call will freeze.

The simplest solution is to replace all the Dispatcher.Invoke with Dispatcher.BeginInvoke and give it a priority that will run once your RunClient is finished.

The other solution is to run RunClient on a BackgroundWorker.

Similar questions with answers are

  1. Dispatcher.Invoke loop freeze UI
  2. Dispatcher.Invoke hangs main window.

Response to comment on ReadString freeze

Calling Read on a NetworkStream is a blocking call. Well, in fact, it is the Stream obtained by calling TcpClient.GetStream() that blocks. The documentation on MSDN states 'After you have obtained the NetworkStream, call the Write method to send data to the remote host. Call the Read method to receive data arriving from the remote host. Both of these methods block until the specified operation is performed'.

I used dotPeek to see what ReadString was doing and the first thing it does is read the length of the incoming string off the stream using NetworkStream.ReadByte which will block until it has a value to read.

That means the ReadString will sit there until there is data available to read and the amount of data is the same as or more than is expected. You will need to check if you have anything to read before you do by calling stream.DataAvailable or reader.PeekChar.

Alternatively, you could run your socket code on a separate thread. If you are using .Net 4.5, I would take a good look at the Task Parallel Library. ntziolis says in an answer to this question that 'We have made good experiences with that (long being days rather than minutes or hours).'