时间:2019-05-10 标签:c#updatelistbox without 'lag'
Posted
技术标签:
【中文标题】时间:2019-05-10 标签:c#updatelistbox without \'lag\'【英文标题】:c# update listbox without 'lag'时间:2019-05-10 标签:c#updatelistbox without 'lag' 【发布时间】:2012-02-05 19:59:43 【问题描述】:我一直在网上寻找一种方法来做到这一点,但没有成功,所以问题来了。
如何在单独的线程中将项目添加到列表框,这样它就不会冻结用户界面? 每次向列表框添加大约 5-15k 项,每次都会冻结 ui 5-12 秒。
表单有 4 个列表框,首先创建这些列表框的信息,然后将其添加到二维数组中(这样做可以更轻松地跟踪属于 1 行的所有信息)。之后我遍历该二维数组,将 1 行中的 4 列添加到其各自的列表框中。
例如。
for (int n = 0; n < 7500; n++)
listBox1.Items.Add(itemList[n, 0].ToString());
listBox2.Items.Add(itemList[n, 1].ToString());
listBox3.Items.Add(itemList[n, 2].ToString());
listBox4.Items.Add(itemList[n, 3].ToString());
如前所述,如何使用 UI 以外的线程来更新这些列表框,以防止不必要的 ui 冻结
【问题讨论】:
您确定普通列表框是向用户显示 1500 个项目的最佳 UI 吗?他们没有办法一次看到所有这些人的列表。 我想显示这么多项目的原因是出于调试目的,以检查信息是否真的全部正确以及我所期望的。这个程序稍后将被集成到另一个根本不显示项目的程序中。我只是好奇如何做到这一点,如果可能的话(事实证明是这样的)。不过我会看看 Listviews 【参考方案1】:您可以采用不同的方法并改用虚拟 ListView。当 ListView 是“虚拟的”时,您负责维护项目列表并告诉 ListView 在绘制事件上显示什么。这样,您可以以任何您想要的线程安全方式更新您的列表,并且 ListView 只会询问您“在屏幕上绘制什么”而不是完整的项目列表。当获取所有项目的列表非常昂贵时,这实际上是首选方法。
请参阅有关 VirtualMode 的文档:
http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.virtualmode.aspx
更新:既然你提到你需要它来进行调试,我还建议你使用调试输出 (Debug.WriteLine()
),它可能更适合这项工作。它经过优化,是线程安全的,除了自身不会阻塞任何东西,最好的部分是它不会影响发布版本的性能。
如果您需要更高性能的输出,您可以将调试输出重定向到您喜欢的任何地方。
【讨论】:
谢谢!我将对此进行调查,唯一的原因是我想知道是否有更好的方法可以在没有 ui 滞后的情况下快速显示它.. 只是为了让我知道。不要向用户展示,因为他们永远不会看到它。【参考方案2】:使用BeginUpdate()
和EndUpdate()
http://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.beginupdate.aspx
【讨论】:
【参考方案3】:这本来就是不可能的。 您只能从 UI 线程操作 UI。 (UI 不是线程安全的)
您可以通过调用BeginUpdate()
和EndUpdate()
使其更快,您可以通过在虚拟模式下使用ListView 使其更快(但更难)。
但是,您不应在 lsitbox 中显示 15,000 个项目。 这样的列表框在实际使用中是没有用的。
【讨论】:
ListBox 不支持虚拟模式。看我的回答。【参考方案4】:listBox1.BeginUpdate();
listBox2.BeginUpdate();
listBox3.BeginUpdate();
listBox4.BeginUpdate();
for (int n = 0; n < 7500; n++)
listBox1.Items.Add(itemList[n, 0].ToString());
listBox2.Items.Add(itemList[n, 1].ToString());
listBox3.Items.Add(itemList[n, 2].ToString());
listBox4.Items.Add(itemList[n, 3].ToString());
listBox1.EndUpdate();
listBox2.EndUpdate();
listBox3.EndUpdate();
listBox4.EndUpdate();
这将延迟绘制,直到所有项目都添加完毕,所以它应该更快。
【讨论】:
【参考方案5】:您应该尝试使用BeginUpdate
/EndUpdate
方法:
listbox1.BeginUpdate();
// Adds 5K items
listbox1.EndUpdate();
【讨论】:
【参考方案6】:您可以通过将 for 循环包裹在其中来防止 ListBox
在每次添加后重新绘制,从而显着加快此过程:
listBox1.BeginUpdate();
listBox2.BeginUpdate();
listBox3.BeginUpdate();
listBox4.BeginUpdate();
for (int n = 0; n < 7500; n++)
listBox1.Items.Add(itemList[n, 0].ToString());
listBox2.Items.Add(itemList[n, 1].ToString());
listBox3.Items.Add(itemList[n, 2].ToString());
listBox4.Items.Add(itemList[n, 3].ToString());
listBox1.EndUpdate();
listBox2.EndUpdate();
listBox3.EndUpdate();
listBox4.EndUpdate();
【讨论】:
+1,答案对我来说似乎已经足够好了。也有兴趣了解投反对票的原因。 我没有投反对票,但我怀疑这是因为你之前的其他帖子。同时发布。【参考方案7】:我只是想把大家的答案放在一起。你真的应该在你的 GUI 线程中更新项目,否则你可能会得到意想不到的结果。为了保证代码在 GUI 线程中运行,并且您的列表不会在每次 Add() 时重新绘制自身,您需要 BeingUpdate() 和 EndUpdate() 对,正如其他人所发布的那样,但要在 GUI 线程中运行它,请使用BeingInvoke(),它只是将任务放在“GUI 线程队列”上,以供使用。 BeingInvoke() 将立即返回,但您的请求将被放入队列中。
BeingInvoke() API 文档。 http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx
BeginInvoke() 上的good discussion 以及使用它的原因。
BeginInvoke((MethodInvoker)delegate
listBox1.BeginUpdate();
listBox2.BeginUpdate();
listBox3.BeginUpdate();
listBox4.BeginUpdate();
for (int n = 0; n < 7500; n++)
listBox1.Items.Add(itemList[n, 0].ToString());
listBox2.Items.Add(itemList[n, 1].ToString());
listBox3.Items.Add(itemList[n, 2].ToString());
listBox4.Items.Add(itemList[n, 3].ToString());
listBox1.EndUpdate();
listBox2.EndUpdate();
listBox3.EndUpdate();
listBox4.EndUpdate();
);
【讨论】:
以上是关于时间:2019-05-10 标签:c#updatelistbox without 'lag'的主要内容,如果未能解决你的问题,请参考以下文章
时间:2019-05-10 标签:c#release optimizationunusedstring
时间:2019-05-10 标签:c#socketconnectionwithmultithreadingtelnet
时间:2019-05-10 标签:c#paypalrestapitransactionsearch
时间:2019-05-10 标签:c#socketThread