文本框不刷新并在一段时间后处于中断模式

Textbox doesn't refresh and is in break mode after a little time

我正在制作一个简单的 wpf 应用程序。它有一个按钮和一个文本框,当您单击该按钮时,它应该会一直更新文本框(请参阅代码)。我有 3 个问题:

  1. 它不会更新循环中的文本框。
  2. 当我点击按钮时,它被卡住了,我无法关闭应用程序(只能使用 taskmanager 并停止调试)。
  3. 如果我让文本框卡住而不关闭它。大约一分钟后,我收到此错误:中断模式屏幕出现 ContextSwitchDeadlock。

我曾尝试通过互联网搜索解决问题,但没有成功。我希望你们能够解决它:)。代码在这里:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Play_Click(object sender, RoutedEventArgs e)
    {
        int x = RandomNumber();
    }

    private string TextboxData;
    private int RandomNumber()
    {
        int x = 0;
        int i = 0;
        Random rng = new Random();
        do
        {
            x = rng.Next(1, 1000000);
            i++;
            TextboxData += "\r\nAl zo vaak :O" + i; //the rng loop
            textBox.Text = TextboxData;                
        }
        while (x != 1);
        TextboxData += "\r\nHij heeft zo vaak geprobeerd 1 te halen " + i;
        textBox.Text = TextboxData + Environment.NewLine;
        return x;
    }       
}

问题是您的所有操作都是在主 GUI 线程中进行的。 这意味着您的程序无法重绘界面,因为它正忙于循环执行代码。

为了获得预期的结果,您需要异步执行循环。但是我们必须记住,GUI 应该只从 GUI 线程更新(这是框架要求)。

由于快速计算,文本框更新过于频繁。您可以考虑使用 Thread.Sleep(100).

解决方法如下:

    private async void Play_Click(object sender, RoutedEventArgs e)
    {
        int x = await RandomNumber();
    }

    private async Task<int> RandomNumber()
        {
            int x = 0;
            int i = 0;
            string text = string.Empty;
            Random rng = new Random();

            // This will start work in background. Leaving GUI thread to it's own tasks.
            await Task.Factory.StartNew(() =>
            {
                do
                {
                    x = rng.Next(1, 1000000);
                    i++;
                    text = "\r\nAl zo vaak :O" + i.ToString(); //the rng loop

                    // This will invoke textbox update in GUI thread satisfying update requirement.
                    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input,
                        new Action(() => {  textBox.AppendText(text); }));

                    // We will make it slower in order to see updates at adequate rate.
                    Thread.Sleep(100);
                }
                while (x != 1);    
            }); 

            // thanks to await we will have this code executed after we found our x==1.
            text = "\r\nHij heeft zo vaak geprobeerd 1 te halen " + i;

            textBox.AppendText(text);
            return x;
        } 

不要忘记添加以下用法:

using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;

编辑:我不知道你为什么要从 RandomNumber() 中获得 return 值(它永远是 1。所以它是无意义的)。但是为了正确处理这个问题,我们需要将 async 添加到我们的签名中以便使用 await 以便我们可以获得一个值,在等待块和 return 结果之后执行代码。

这是一个比较复杂的话题,我在这里只提一下,以便有正确的解决方案。如果您感兴趣 - google '.net async await'。但我建议留着以后用:)

此外,我删除了 TextBoxData 字段并将其替换为局部变量,并按照@KevinKal 的建议使用了 textbox.AppendText()