我正在尝试获得一个平滑的滚动列表框,其行为方式与Delphi的TMemo.Add()方法相同。
使用下面的测试代码,它可以滚动一段时间,然后在600左右暂停并且无法刷新直到完成。
我已经看到过必须在不同的线程上运行下面的代码才能更新才能成功。这是我经常使用的那种东西,我希望有一个更简单的解决方案。
for (int i = 0; i < 10000; i++)
{
listBox1.Items.Add(i);
listBox1.SetSelected(listBox1.Items.Count - 1, true);
listBox1.SelectedIndex = -1;
this.Refresh(); // overkill but just to make sure...
}
答案 0 :(得分:2)
我不建议这样做,因为连续重绘的性能成本会真正扼杀速度,这就是你所看到的600左右 - 它只是处理得太多了。
您可以在循环期间调用Application.Refresh
以继续处理窗口消息,从而使其保持响应,但再次以性能为代价。
我最近看到的一个策略,不是简单但有效的是伪造列表框。因此,在添加过程中,您隐藏列表框并将其替换为用于在类似于列表框的内容上绘制的面板或类似物。完成后你会回来。通过这种方式,您可以获得非常流畅的视觉效果。更多的工作,但也许值得。
答案 1 :(得分:0)
我没有在这样的循环中使用application.refresh(虽然它可以很好地工作),你可能想尝试application.processMessages。我用过它,它对我有用。 -don
答案 2 :(得分:0)
您可能想要以不同的方式考虑这一点。我假设您希望每次添加项目时重新绘制列表框,以向用户显示您正在取得进展。如果是这种情况,那么我在类似情况下使用的方法是:
答案 3 :(得分:0)
在我的计算机上运行正常,直到我尝试与表单进行交互,此时它将停止更新。但是,这不是重点。真正的问题是,为什么要填充一个包含10000个项目的列表框并为每个显示的项目更新?
一个合理的选择可能是批量处理项目(可能在一个单独的线程中),然后发布一些项目,以便时不时地显示:
private void SomeMethod()
{
ThreadPool.QueueUserWorkItem((state) =>
{
List<int> ints = new List<int>();
for (int i = 0; i < 10000; i++)
{
ints.Add(i);
if (i % 25 == 0) // update the listbox on every 25th item
{
this.Invoke(
new Action<IEnumerable<int>>(AddItemsToList), ints);
ints.Clear();
}
if (ints.Count != 0) // make sure to add any "trailing" items
{
this.Invoke(
new Action<IEnumerable<int>>(AddItemsToList), ints);
}
}
});
}
private void AddItemsToList(IEnumerable<int> items)
{
listBox1.BeginUpdate();
foreach (var item in items)
{
listBox1.Items.Add(item);
}
listBox1.EndUpdate();
listBox1.SetSelected(listBox1.Items.Count - 1, true);
listBox1.SelectedIndex = -1;
listBox1.Update();
}
现在,当列表加载时,你也有一个相当敏感的用户界面。