해제 - c# listview 행 선택




ListView에 항목을 빠르게 추가하는 방법은 무엇입니까? (3)

나는 같은 문제를 가지고있다. 그렇다면 나는 그것을 sorter 너무 느리다는 것을 알았다. 분류기를 null로 설정

this.listViewAbnormalList.ListViewItemSorter = null;

ListView_ColumnClick 메서드에서 정렬기를 클릭하면

 lv.ListViewItemSorter = new ListViewColumnSorter()

마침내 정렬 된 후에 sorter 다시 null로 만듭니다.

 ((System.Windows.Forms.ListView)sender).Sort();
 lv.ListViewItemSorter = null;

https://code.i-harness.com

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()

실제 병목 현상은 항목을 추가하는 것입니다. foreach 아닌 AddRange 로 변환 해 봅시다.

시도 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();

제한은 목록보기에 항목을 추가하는 것 같습니다. 어레이가 아닌 ListView.ListViewItemCollection 을 추가하는 AddRange 의 다른 오버로드 일 수 있습니다.

시도 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();

크기가 더 빠릅니다.

WinForms ListView 래퍼의 어떤 속성이 누락 되었습니까?


나는이 코드를 사용했다 :

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();

또한 각 열에 대해 GenerateMember 를 false로 설정했습니다.

사용자 지정 목록보기 분류기에 대한 링크 : http://www.codeproject.com/Articles/5332/ListView-Column-Sorter


목록보기의 소스 코드를 살펴 보았습니다. 성능을 4 배나 느려지 게 만드는 몇 가지 사항을 확인했습니다.

ListView.cs에서 ListViewItemsCollection.AddRange 는 내가 감사를 시작한 ListViewItemsCollection.AddRange 호출합니다.

ListViewNativeItemCollection.AddRange (from line : 18120)는 전체 값 모음을 두 번 통과합니다. 하나는 InsertItems 가 호출 된 후 다른 모든 항목을 '복원'합니다 ( owner.IsHandleCreated 에 대한 검사에 의해 보호됩니다. 소유자가 ListView ) BeginUpdate 를 호출합니다.

ListView.InsertItems (줄에서 : 12952), 첫 번째 호출, 전체 목록의 다른 트래버스 있고 ArrayList.AddRange 호출됩니다 (아마도 다른 패스) 다음에 또 다른 패스. 선도

ListView.InsertItems (행 : 12952), 두 번째 호출 ( EndUpdate 를 통해), HashTable 추가 된 곳을 통과하는 또 다른 패스, Debug.Assert(!listItemsTable.ContainsKey(ItemId)) 는 디버그 모드에서 더 느려집니다. 핸들이 작성되지 않은 경우, 항목을 ArrayList , listItemsArray 하지만 if (IsHandleCreated) 를 호출하면

ListView.InsertItemsNative (줄 : 3848) 최종적으로 네이티브 목록 뷰에 실제로 추가되는 목록을 통과합니다. Debug.Assert(this.Items.Contains(li) 추가로 디버그 모드에서 성능이 저하됩니다.

따라서 네이티브 목록보기에 항목을 실제로 삽입하기 전에 .net 컨트롤의 전체 항목 목록을 통해 추가 패스가 많이 있습니다. 패스 중 일부는 생성되는 핸들에 대한 검사로 보호되므로 핸들을 만들기 전에 항목을 추가 할 수 있으면 시간을 절약 할 수 있습니다. OnHandleCreated 메서드는 listItemsArray 하고 별도의 OnHandleCreated 없이 InsertItemsNative 직접 호출합니다.

참조 소스 에서 ListView 코드를 직접 읽을 수 있습니다. 어쩌면 뭔가 놓쳤을 수도 있습니다.

MSDN 매거진 2006 년 3 월호 에는 Winning Forms: Practical Tips for Boosting The Performance of Windows Forms Apps 있습니다.

이 기사에는 ListViews의 성능 향상을위한 팁이 포함되어 있습니다. 그것은 핸들이 생성되기 전에 아이템을 추가하는 것이 빠르지 만 컨트롤이 렌더링 될 때 가격을 지불한다는 것을 나타냅니다. 아마도 주석에 언급 된 렌더링 최적화를 적용하고 핸들을 만들기 전에 항목을 추가하면 두 가지 장점이 모두 우수합니다.

편집 :이 가설을 여러 가지 방법으로 테스트했으며 핸들을 만들기 전에 항목을 추가하는 것이 빠르지 만 핸들을 만들 때 기하 급수적으로 느립니다. 나는 핸들을 만들기 위해 속일려고 노력했다. 그런 다음 어떻게 든 InsertItemsNative를 호출하여 모든 추가 패스를 거치지 않고 플레이했지만 어쨌든 나는 방해 받았다. 내가 생각할 수있는 유일한 방법은 C ++ 프로젝트에서 Win32 ListView를 만들고, 항목을 채우고, 핸들을 만들 때 ListView가 보낸 CreateWindow 메시지를 캡처하고 후크를 사용하여 win32에 대한 참조를 다시 전달하는 것입니다 새 창 대신 ListView ..하지만 측면에 어떤 영향을 미칠지 누가 알겠는가? Win32 전문가는 그 미친 생각에 대해 말할 필요가있다. :)





listview