给出以下示例代码:
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).我的应用程序使用类似的逻辑来填充文本框,我遇到了同样的问题.
我的问题是:如何尽可能快地填写此文本框,每次仍然滚动到底部,然后减少/消除这种滞后?
您可以在这里选择几个选项.首先,您可以在窗体上设置双缓冲,最终将在底层位图上绘制所有更新,然后显示新绘制的图像(而不是在图形对象上单独绘制控件).我用这种方法看到了大约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)
最后,刚刚测试出惊人的结果(在Invoke调用之前将一个条件投入到上面的代码中),它在2秒内完成.由于我们使用StringBuilder实际构建字符串,我们仍然保留所有数据,但现在我们只需要进行100次更新,而不是10k次.
那么现在,你有什么选择?鉴于这是一个WinForm应用程序,您可以利用众多Timer对象中的一个来实际执行该特定控件的UI更新,或者您可以只保留对底层数据"读取"或"更新"的计数器(在您的情况下,一个流)并且只更新X个更改的UI.利用StringBuilder选项和交错更新可能是要走的路.
| 归档时间: |
|
| 查看次数: |
6885 次 |
| 最近记录: |