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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20801726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:19:26  来源:igfitidea点击:

App freezes after Dispatcher.Invoke

c#wpfmultithreadingsockets

提问by Kevin k5

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

我有这个应用程序在调用任何控件的 dispatcher.invoke 时会冻结。

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

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

回答by Mark Travis

The Dispatcher.Invoke attempts to synchronouslyrun the specified action on the Dispatcher Thread.

Dispatcher.Invoke尝试同步运行的调度程序线程指定的操作。

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.

假设 RunClient 在 Dispatcher 线程上运行,并且 while 循环在您尝试调用回 Dispatcher 线程时继续运行,则调用将冻结。

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.

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

The other solution is to run RunClient on a BackgroundWorker.

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

Similar questions with answers are

有答案的类似问题是

  1. Dispatcher.Invoke loop freeze UI
  2. Dispatcher.Invoke hangs main window.
  1. Dispatcher.Invoke 循环冻结 UI
  2. Dispatcher.Invoke 挂起主窗口

Response to comment on ReadString freeze

对 ReadString 冻结评论的回应

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'.

在 NetworkStream 上调用 Read 是一个阻塞调用。嗯,其实阻塞的就是调用TcpClient.GetStream()得到的Stream 。MSDN 上的文档指出'获得NetworkStream 后,调用Write 方法将数据发送到远程主机。调用 Read 方法接收来自远程主机的数据。这两种方法都会阻塞,直到执行指定的操作'.

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

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

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.DataAvailableor reader.PeekChar.

这意味着 ReadString 将一直驻留在那里,直到有数据可供读取并且数据量与预期相同或更多。您将需要检查,如果您有任何你通过调用之前做阅读stream.DataAvailablereader.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. ntziolissays in an answer to this questionthat 'We have made good experiences with that (long being days rather than minutes or hours).'

或者,您可以在单独的线程上运行您的套接字代码。如果您使用的是 .Net 4.5,我会好好看看Task Parallel Libraryntziolis在回答这个问题时说:“我们在这方面取得了很好的经验(很长一段时间,而不是几分钟或几小时)。” '