防止文本框因快速更新而滞后

qJa*_*ake 7 c# winforms

给出以下示例代码:

new Thread(() =>
{
    for(int i = 0; i < 10000; i++)
    {
        Invoke((MethodInvoker)() => 
        {
            myTextBox.Text += DateTime.Now.ToString() + "\r\n";
            myTextBox.SelectedIndex = myTextBox.Text.Length;
            myTextBox.ScrollToCarat();
        });
    }
}).Start();

当您运行此代码时,在循环和线程终止后,文本框仍在更新(可能是因为缓冲的Invokes).我的应用程序使用类似的逻辑来填充文本框,我遇到了同样的问题.

我的问题是:如何尽可能快地填写此文本框,每次仍然滚动到底部,然后减少/消除这种滞后?

SPF*_*ake 8

您可以在这里选择几个选项.首先,您可以在窗体上设置双缓冲,最终将在底层位图上绘制所有更新,然后显示新绘制的图像(而不是在图形对象上单独绘制控件).我用这种方法看到了大约50%的速度提升.把它扔进构造函数:

this.SetStyle(
  ControlStyles.AllPaintingInWmPaint |
  ControlStyles.UserPaint |
  ControlStyles.DoubleBuffer,true);
Run Code Online (Sandbox Code Playgroud)

另外要记住的是,字符串连接对于大量数据来说是缓慢的.你最好使用StringBuilder来构建数据,然后使用StringBuilder.ToString显示它(尽管更好地错开更新,可能每100次迭代一次).在我的机器上,只需更改它以附加到StringBuilder,它从2.5分钟开始运行10k迭代到大约1.5分钟.更好,但仍然很慢.

new System.Threading.Thread(() =>
{
    for(int i = 0; i < 10000; i++)
    {
        sb.AppendLine(DateTime.Now.ToString());
        Invoke((Action)(() => 
        {
            txtArea.Text = sb.ToString();
            txtArea.SelectionStart = txtArea.Text.Length;
            txtArea.ScrollToCaret();
        }));
    }
}).Start();
Run Code Online (Sandbox Code Playgroud)

最后,刚刚测试出惊人的结果(在I​​nvoke调用之前将一个条件投入到上面的代码中),它在2秒内完成.由于我们使用StringBuilder实际构建字符串,我们仍然保留所有数据,但现在我们只需要进行100次更新,而不是10k次.

那么现在,你有什么选择?鉴于这是一个WinForm应用程序,您可以利用众多Timer对象中的一个来实际执行该特定控件的UI更新,或者您可以只保留对底层数据"读取"或"更新"的计数器(在您的情况下,一个流)并且只更新X个更改的UI.利用StringBuilder选项和交错更新可能是要走的路.