ListView에 항목을 빠르게 추가하는 방법은 무엇입니까?
WinForms ListView에 수천 (예 : 53,709) 항목을 추가하고 있습니다.
시도 1 :13,870 ms
foreach (Object o in list)
{
ListViewItem item = new ListViewItem();
RefreshListViewItem(item, o);
listView.Items.Add(item);
}
이것은 매우 나쁘게 실행됩니다. 분명한 첫 번째 해결 방법은 BeginUpdate/EndUpdate
.
시도 2 :3,106 ms
listView.BeginUpdate();
foreach (Object o in list)
{
ListViewItem item = new ListViewItem();
RefreshListViewItem(item, o);
listView.Items.Add(item);
}
listView.EndUpdate();
이것은 더 좋지만 여전히 너무 느립니다. ListViewItems 생성과 ListViewItems 추가를 분리하여 실제 범인을 찾습니다.
시도 3 :2,631 ms
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
대신 a 로 변환 해 봅시다 .foreach
시도 4 : 2,182 ms
listView.BeginUpdate();
listView.Items.AddRange(items.ToArray());
listView.EndUpdate();
조금 더 나은. 병목 현상이 없는지 확인합시다.ToArray()
시도 5 : 2,132 ms
ListViewItem[] arr = items.ToArray();
stopwatch.Start();
listView.BeginUpdate();
listView.Items.AddRange(arr);
listView.EndUpdate();
stopwatch.Stop();
제한은 목록보기에 항목을 추가하는 것 같습니다. 의 다른 오버로드 AddRange
일 수 있습니다. 여기서 ListView.ListViewItemCollection
배열 이 아닌를 추가합니다.
시도 6 : 2,141 ms
listView.BeginUpdate();
ListView.ListViewItemCollection lvic = new ListView.ListViewItemCollection(listView);
lvic.AddRange(arr);
listView.EndUpdate();
글쎄요.
이제 스트레칭 할 시간입니다.
1 단계 -열이 "자동 너비"로 설정되어 있지 않은지 확인합니다 .
검사
2 단계 -ListView가 항목을 추가 할 때마다 항목을 정렬하지 않는지 확인합니다.
검사
3 단계 -stackoverflow에 문의 :
검사
참고 : 분명히이 ListView는 가상 모드가 아닙니다. 가상 목록보기에 항목을 "추가"할 수 없거나 할 수 없기 때문입니다 (를 설정 VirtualListSize
). 다행히도 내 질문은 가상 모드의 목록보기에 관한 것이 아닙니다.
목록보기에 항목을 추가하는 것이 너무 느려서 누락 된 것이 있습니까?
보너스 채터
Windows ListView 클래스가 더 잘할 수 있다는 것을 알고 있습니다.에서 코드를 작성할 수 있기 때문입니다 394 ms
.
ListView1.Items.BeginUpdate;
for i := 1 to 53709 do
ListView1.Items.Add();
ListView1.Items.EndUpdate;
동등한 C # 코드와 비교할 때 1,349 ms
:
listView.BeginUpdate();
for (int i = 1; i <= 53709; i++)
listView.Items.Add(new ListViewItem());
listView.EndUpdate();
is an order of magnitude faster.
What property of the WinForms ListView wrapper am i missing?
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:
in ListView.cs, ListViewItemsCollection.AddRange
calls ListViewNativeItemCollection.AddRange
, which is where I began my audit
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
(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
(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
(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.
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 read the ListView
code in the reference source yourself and take a look, maybe I missed something.
In the March 2006 issue of MSDN Magazine there was an article called Winning Forms: Practical Tips for Boosting The Performance of Windows Forms Apps
.
This article contained tips for improving the performance of ListViews, 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.
Edit: 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 :)
I used this code:
ResultsListView.BeginUpdate();
ResultsListView.ListViewItemSorter = null;
ResultsListView.Items.Clear();
//here we add items to listview
//adding item sorter back
ResultsListView.ListViewItemSorter = lvwColumnSorter;
ResultsListView.Sort();
ResultsListView.EndUpdate();
I have set also GenerateMember
to false for each column.
Link to custom list view sorter: http://www.codeproject.com/Articles/5332/ListView-Column-Sorter
I have the same problem. Then I found it's sorter
make it so slow. Make the sorter as null
this.listViewAbnormalList.ListViewItemSorter = null;
then when click sorter, on ListView_ColumnClick
method , make it
lv.ListViewItemSorter = new ListViewColumnSorter()
At last, after it's been sorted, make the sorter
null again
((System.Windows.Forms.ListView)sender).Sort();
lv.ListViewItemSorter = null;
This is simple code I was able to construct to add Items to a listbox that consist of columns. The first column is item while the second column is price. The code below prints Item Cinnamon in first column and 0.50 in the second column.
// How to add ItemName and Item Price
listItems.Items.Add("Cinnamon").SubItems.Add("0.50");
No instantiation needed.
Create all your ListViewItems FIRST, then add them to the ListView all at once.
For example:
var theListView = new ListView();
var items = new ListViewItem[ 53709 ];
for ( int i = 0 ; i < items.Length; ++i )
{
items[ i ] = new ListViewItem( i.ToString() );
}
theListView.Items.AddRange( items );
참고 URL : https://stackoverflow.com/questions/9008310/how-to-speed-adding-items-to-a-listview
'your programing' 카테고리의 다른 글
더 많은 정신 광기-파서 유형 (규칙 대 int_parser <>) 및 메타 프로그래밍 기술 (0) | 2020.10.08 |
---|---|
이 앱에는 구성된 Android 키 해시가 없습니다. (0) | 2020.10.08 |
기본값, 값 및 제로 초기화 혼란 (0) | 2020.10.08 |
TensorFlow에서 CSV 데이터를 * 실제로 * 읽는 방법은 무엇입니까? (0) | 2020.10.08 |
Blob URL을 일반 URL로 변환 (0) | 2020.10.07 |