应用程序在Dispatcher.Invoke之后冻结

时间:2013-12-27 13:38:23

标签: c# wpf multithreading sockets

我有这个应用程序在调用dispatcher.invoke进行任何控制时冻结。

当我在radiobutton,Grid,Image ..etc中调用Dispatcher时,应用程序冻结但没有出错。任何帮助请!!!谢谢

我调用线程方法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!");
        }


    }

当代码进入方法(检查连接)并调用调度程序时,应用程序会冻结。

     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 个答案:

答案 0 :(得分:9)

Dispatcher.Invoke attempts to synchronously在Dispatcher Thread上运行指定的操作。

假设RunClient在Dispatcher Thread上运行,而while循环在你尝试重新调用Dispatcher Thread时继续运行,则调用将冻结。

最简单的解决方案是将所有Dispatcher.Invoke替换为Dispatcher.BeginInvoke,并为其设置一个优先级,该优先级将在RunClient完成后运行。

另一种解决方案是在BackgroundWorker上运行RunClient。

回答的类似问题是

  1. Dispatcher.Invoke loop freeze UI
  2. Dispatcher.Invoke hangs main window
  3. 对ReadString冻结评论的回复

    调用NetworkStream上的Read是一个阻塞调用。嗯,事实上,它是通过调用阻塞TcpClient.GetStream()获得的Stream。 MSDN上的文档说明'获取NetworkStream后,调用Write方法将数据发送到远程主机。调用Read方法以接收从远程主机到达的数据。这两种方法都会阻塞,直到执行指定的操作'。

    我使用dotPeek来查看ReadString正在做什么,它首先要做的是使用NetworkStream.ReadByte从流中读取传入字符串的长度,它将阻塞直到它有一个要读取的值。

    这意味着ReadString将一直存在,直到有数据可供读取且数据量与预期相同或更多。在致电stream.DataAvailablereader.PeekChar之前,您需要先检查一下是否有任何需要阅读的内容。

    或者,您可以在单独的线程上运行套接字代码。如果您使用的是.Net 4.5,我会好好看一下Task Parallel Libraryntziolis在对此question的回答中说'我们已经为此做了很好的经历(长期是几天而不是几分钟或几小时)。'