如何加快项目添加到ListView? [英] How to speed adding items to a ListView?

查看:195
本文介绍了如何加快项目添加到ListView?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我添加了几千(如53709)项目一个WinForms ListView的。

i'm adding a few thousand (e.g. 53,709) items to a WinForms ListView.

尝试1 13870毫秒

foreach (Object o in list)
{
   ListViewItem item = new ListViewItem();
   RefreshListViewItem(item, o);
   listView.Items.Add(item);
}

本运行速度非常严重。最明显的第一个定位是调用的BeginUpdate / EndUpdate

This runs very badly. The obvious first fix is to call BeginUpdate/EndUpdate.

尝试二 3,106毫秒

listView.BeginUpdate();
foreach (Object o in list)
{
   ListViewItem item = new ListViewItem();
   RefreshListViewItem(item, o);
   listView.Items.Add(item);
}
listView.EndUpdate();

这是好,但幅度仍然太慢一个数量级。让我们ListViewItems的独立创作,从加入ListViewItems,所以我们发现实际罪魁祸首:

This is better, but still an order of magnitude too slow. Let's separate creation of ListViewItems from adding ListViewItems, so we find the actual culprit:

尝试3 2631毫秒

var items = new List<ListViewItem>();
foreach (Object o in list)
{
   ListViewItem item = new ListViewItem();
   RefreshListViewItem(item, o);
   items.Add(item);
}

stopwatch.Start();

listView.BeginUpdate();
    foreach (ListViewItem item in items)
        listView.Items.Add(item));
listView.EndUpdate();

stopwatch.Stop()

的真正的瓶颈是增加的项目。让我们试着将其转换为的AddRange 而非的foreach

尝试4: 2182毫秒

listView.BeginUpdate();
listView.Items.AddRange(items.ToArray());
listView.EndUpdate();

一个好一点。我们要确保的瓶颈不在 ToArray的()

A bit better. Let's be sure that the bottleneck isn't in the ToArray()

尝试5: 2132毫秒

ListViewItem[] arr = items.ToArray();

stopwatch.Start();

listView.BeginUpdate();
listView.Items.AddRange(arr);
listView.EndUpdate();

stopwatch.Stop();

的限制似乎是将项目添加到列表视图。也许其他超负荷的AddRange ,在这里我们添加一个 ListView.ListViewItemCollection ,而不是一个数组

The limitation seems to be adding items to the listview. Maybe the other overload of AddRange, where we add a ListView.ListViewItemCollection rather than an array

尝试6: 2141毫秒

listView.BeginUpdate();
ListView.ListViewItemCollection lvic = new ListView.ListViewItemCollection(listView);
lvic.AddRange(arr);
listView.EndUpdate();

嗯,这是再好不过的。

Well that's no better.

现在是时候舒展:


  • 第1步 - 确保没有列设置为自动宽度的:

  • Step 1 - make sure no column is set to "auto-width":

查看

第2步 - 确保ListView控件是不是要对项目每一次我添加一个排序:

Step 2 - make sure the ListView isn't trying to sort the items each time i add one:

查看

第3步 - 要求计算器:

Step 3 - Ask stackoverflow:

查看

注意:显然,这是的ListView不是在虚拟模式;因为你不/不能项目增加到虚拟列表视图(将 VirtualListSize )。幸运的是,我的问题是不是在虚拟模式的列表视图。

Note: Obviously this ListView is not in virtual mode; since you don't/cannot "add" items to a virtual list view (you set the VirtualListSize). Fortunately my question is not about a list view in virtual mode.

有什么我失踪,可能占了将项目添加到列表视图是这么慢?

Is there anything i am missing that might account for adding items to the listview being so slow?

奖金颤振

我知道在Windows的ListView类可以做的更好,因为我可以写code,做它 394毫秒

i know the Windows ListView class can do better, because i can write code that does it in 394 ms:

ListView1.Items.BeginUpdate;
for i := 1 to 53709 do
   ListView1.Items.Add();
ListView1.Items.EndUpdate;

这时候相比,相当于C#code 1349毫秒

listView.BeginUpdate();
for (int i = 1; i <= 53709; i++)
   listView.Items.Add(new ListViewItem());
listView.EndUpdate();

是一个数量级更快

is an order of magnitude faster.

我失去了什么属性的WinForms ListView的包装呢?

What property of the WinForms ListView wrapper am i missing?

推荐答案

我看了一下源$ C ​​$ C列表视图,我注意到了一些东西,可能使性能由4因素减缓或者让你看到的:

I took a look at the source code for the list view and I noticed a few things that may make the performance slow down by the factor of 4 or so that you're seeing:

在ListView.cs, ListViewItemsCollection.AddRange 要求 ListViewNativeItemCollection.AddRange ,这是我开始了我的审计

in ListView.cs, ListViewItemsCollection.AddRange calls ListViewNativeItemCollection.AddRange, which is where I began my audit

ListViewNativeItemCollection.AddRange (从行:18120)已通过值的整个集合一两次传球,收集所有的检查项目另一个'恢复'后,他们 InsertItems 被称为(他们俩都被检查防范的 owner.IsHandleCreated ,业主作为的ListView ),然后调用的BeginUpdate

ListViewNativeItemCollection.AddRange (from line: 18120) has two passes through the entire collection of values, one to collect all the checked items another to 'restore' them after InsertItems is called (they're both guarded by a check against owner.IsHandleCreated, owner being the ListView) then calls BeginUpdate.

ListView.InsertItems (从行:12952),第一个呼叫,提供了​​完整的名单,然后ArrayList.AddRange被称为(可能是另一路经那里)的另一横然后又后通过。导致

ListView.InsertItems (from line: 12952), first call, has another traverse of the entire list then ArrayList.AddRange is called (probably another pass there) then another pass after that. Leading to

ListView.InsertItems (从行:12952),第二个电话(通过 EndUpdate )另一路经那里被添加到的HashTable Debug.Assert的(!listItemsTable.ContainsKey(ITEMID))将进一步放缓它在调试模式。如果没有创建手柄,它会将项目添加到一个的ArrayList listItemsArray ,但如果(IsHandleCreated),然后调用

ListView.InsertItems (from line: 12952), second call (via EndUpdate) another pass through where they are added to a HashTable, and a Debug.Assert(!listItemsTable.ContainsKey(ItemId)) will slow it further in debug mode. If the handle isn't created, it adds the items to an ArrayList, listItemsArray but if (IsHandleCreated), then it calls

ListView.InsertItemsNative (从行:3848)最后一次通过它实际上是添加到列表视图原生名单。一个 Debug.Assert的(this.Items.Contains(LI)将另外在调试模式下降低性能。

ListView.InsertItemsNative (from line: 3848) final pass through the list where it is actually added to the native listview. a Debug.Assert(this.Items.Contains(li) will additionally slow down performance in debug mode.

因此​​,有额外的通行证了很多通过在.NET控件项目的整个列表以往任何时候都得到真正插入项目到本地列表视图之前。有些通行证是由对手柄检查创建森严,所以如果你能添加项目创建句柄之前,它可能会为您节省一些时间。在 OnHandleCreated 方法以 listItemsArray 键,通话 InsertItemsNative 的情况下直接所有的额外大惊小怪的。

So there are A LOT of extra passes through the entire list of items in the .net control before it ever gets to actually inserting the items into the native listview. Some of the passes are guarded by checks against the Handle being created, so if you can add items before the handle is created, it may save you some time. The OnHandleCreated method takes the listItemsArray and calls InsertItemsNative directly without all the extra fuss.

您可以下载自己源引用看一看,也许我错过了什么。

You can download the source reference yourself and take a look, maybe I missed something.

下面是另一篇博客中讨论除其他事项外的ListView效果。这似乎表明,它更快地创建句柄之前添加项目,但是,当控件呈现,你将为此付出代价。也许应用在评论中提到的渲染优化和添加项目创建句柄之前会得到两全其美的。

Here's another blog post discussing ListView performance, among other things. It seems to indicate that its faster to add items before the handle is created, but that you will pay a price when the control is rendered. Perhaps applying the rendering optimizations mentioned in the comments and adding the items before the handle is created will get the best of both worlds.

编辑:测试此假设在以各种方式,并同时加入项目之前创建句柄suuuper快,这是当它以创建手柄成倍慢。我打了企图欺骗它来创建句柄,然后以某种方式得到它叫InsertItemsNative不经过所有额外的传球去,但很可惜我一直在阻挠。我能想到的可能是唯一可行的事情,就是在C ++项目,项目创建的Win32 ListView控件,东东吧,和创建它的手柄时使用挂钩,以捕获由ListView控件发送的CreateWindow的消息,并传回的win32参考ListView控件,而不是一个新的窗口..但谁知道身边有什么影响会有...一个Win32大师将需要讲出那个疯狂的想法:)

Tested this hypothesis in a variety of ways, and while adding the items before creating the handle is suuuper fast, it is exponentially slower when it goes to create the handle. I played with trying to trick it to create the handle, then somehow get it to call InsertItemsNative without going through all the extra passes, but alas I've been thwarted. The only thing I could think might be possible, is to create your Win32 ListView in a c++ project, stuff it with items, and use hooking to capture the CreateWindow message sent by the ListView when creating its handle and pass back a reference to the win32 ListView instead of a new window.. but who knows what the side affects there would be... a Win32 guru would need to speak up about that crazy idea :)

这篇关于如何加快项目添加到ListView?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆