2012-01-25 30 views
70

Tôi đang thêm một vài nghìn (ví dụ: 53,709) mục vào một ListView WinForms.Làm thế nào để tăng tốc độ thêm các mục vào một ListView?

Cố gắng 1: 13,870 ms

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

này chạy rất nặng. Sửa chữa đầu tiên rõ ràng là gọi BeginUpdate/EndUpdate.

Cố gắng 2: 3,106 ms

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

này là tốt hơn, nhưng vẫn theo độ quá chậm. Hãy sáng tạo riêng của ListViewItems từ việc thêm ListViewItems, vì vậy chúng tôi tìm ra thủ phạm thực tế:

Nỗ lực 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() 

Các nút cổ chai thực sẽ bổ sung các hạng mục. Hãy thử chuyển đổi nó để AddRange chứ không phải là một Cố gắng foreach

4:2,182 ms

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

Một chút tốt hơn. Hãy chắc chắn rằng các nút cổ chai không nằm trong ToArray()

Nỗ lực 5:2,132 ms

ListViewItem[] arr = items.ToArray(); 

stopwatch.Start(); 

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

stopwatch.Stop(); 

Giới hạn dường như có thêm mục vào listview. Có lẽ sự quá tải khác của AddRange, nơi chúng ta thêm một ListView.ListViewItemCollection chứ không phải là một mảng

Cố 6:2,141 ms

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

Vâng đó là không tốt.

Bây giờ là lúc để căng:

  • Bước 1 - đảm bảo không có cột được thiết lập để "auto-width":

    enter image description here

    Kiểm tra

  • Bước 2 - đảm bảo ListView không cố gắng để sắp xếp các mục mỗi lần tôi thêm một:

    enter image description here

    Kiểm tra

  • Bước 3 - Hỏi stackoverflow:

    enter image description here

    Kiểm tra

Lưu ý: Rõ ràng ListView đây không phải là trong chế độ ảo; vì bạn không/không thể "thêm" các mục vào chế độ xem danh sách ảo (bạn đặt VirtualListSize). May mắn thay câu hỏi của tôi không phải là về một cái nhìn danh sách trong chế độ ảo.

Có bất kỳ điều gì tôi thiếu mà có thể tính đến việc thêm các mục vào chế độ xem danh sách quá chậm?


Bonus nhí

tôi biết lớp ListView Windows có thể làm tốt hơn, bởi vì tôi có thể viết mã nào đó trong 394 ms:

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

mà khi so sánh với tương đương với C# mã 1,349 ms:

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

là thứ tự cường độ nhanh hơn.

Thuộc tính nào của trình bao bọc ListView WinForms am i bị thiếu?

+2

Lưu ý phụ: Nếu sử dụng Hộp kiểm, bạn nên đặt trạng thái đã chọn trước khi thêm vào ListView. Đang khởi tạo các trạng thái đã chọn http://blogs.msdn.com/b/hippietim/archive/2006/03/20/556007.aspx –

+3

Tôi phải hỏi: tại sao bạn lại thêm nhiều mục? –

+3

Câu hỏi lớn Ian. Bạn đã xem blog này về chủ đề chưa? http://www.virtualdub.org/blog/pivot/entry.php?id=273 –

Trả lời

20

tôi đã xem xét mã nguồn cho xem danh sách và tôi nhận thấy một vài điều mà có thể làm cho việc thực hiện chậm lại bởi các yếu tố của 4 hoặc lâu hơn mà bạn đang nhìn thấy:

trong ListView.cs, ListViewItemsCollection.AddRange gọi ListViewNativeItemCollection.AddRange, đó là nơi tôi bắt đầu kiểm toán của tôi

ListViewNativeItemCollection.AddRange (từ dòng: 18.120) có hai đi qua toàn bộ bộ sưu tập của các giá trị, người ta thu thập tất cả các bài kiểm tra khác để 'phục hồi' họ sau InsertItems là được gọi (cả hai đều được bảo vệ bằng séc với số owner.IsHandleCreated, chủ sở hữu là ListView) rồi gọi số BeginUpdate.

ListView.InsertItems (từ dòng: 12952), cuộc gọi đầu tiên, có một lần duyệt khác của toàn bộ danh sách sau đó ArrayList.AddRange được gọi (có thể là một đường chuyền khác) sau đó một đường chuyền khác sau đó. Dẫn đến

ListView.InsertItems (từ dòng: 12.952), cuộc gọi thứ hai (thông qua EndUpdate) khác đi qua nơi chúng được thêm vào một HashTable, và một Debug.Assert(!listItemsTable.ContainsKey(ItemId)) sẽ làm chậm nó hơn nữa trong chế độ gỡ lỗi. Nếu xử lý không được tạo ra, nó bổ sung thêm các mục cần một ArrayList, listItemsArray nhưng if (IsHandleCreated), sau đó nó gọi

ListView.InsertItemsNative (từ dòng: 3848) vượt qua chính thức thông qua danh sách, nơi nó được thực sự bổ sung vào listview bản địa. a Debug.Assert(this.Items.Contains(li) cũng sẽ làm chậm hiệu suất trong chế độ gỡ lỗi.

Vì vậy, có rất nhiều lượt vượt qua toàn bộ danh sách các mục trong điều khiển .net trước khi nó thực sự chèn các mục vào chế độ xem danh sách gốc. Một số đường chuyền được bảo vệ bằng các kiểm tra chống lại Xử lý được tạo ra, vì vậy nếu bạn có thể thêm các mục trước khi xử lý được tạo, nó có thể giúp bạn tiết kiệm thời gian. Phương pháp OnHandleCreated lấy số listItemsArray và gọi trực tiếp InsertItemsNative mà không cần thêm bất kỳ phiền toái nào.

Bạn có thể đọc mã ListView trong chính mình và hãy xem, có thể tôi đã bỏ sót điều gì đó.

In the March 2006 issue of MSDN Magazine có một bài viết có tên là Winning Forms: Practical Tips for Boosting The Performance of Windows Forms Apps.

Bài viết này chứa các mẹo để cải thiện hiệu suất của ListView, trong số những thứ khác. Nó dường như chỉ ra rằng nhanh hơn của nó để thêm các mục trước khi xử lý được tạo ra, nhưng bạn sẽ phải trả một mức giá khi điều khiển được trả lại. Có lẽ việc áp dụng tối ưu hóa kết xuất được đề cập trong các nhận xét và thêm các mục trước khi xử lý được tạo ra sẽ có được tốt nhất của cả hai thế giới.

Chỉnh sửa: Đã thử nghiệm giả thuyết này theo nhiều cách khác nhau và trong khi thêm các mục trước khi tạo tay cầm nhanh chóng, nó sẽ chậm hơn theo cấp số nhân khi tạo bộ điều khiển. Tôi chơi với cố gắng để lừa nó để tạo ra các xử lý, sau đó bằng cách nào đó có được nó để gọi InsertItemsNative mà không đi qua tất cả các vượt qua thêm, nhưng than ôi tôi đã bị cản trở. Điều duy nhất tôi có thể nghĩ rằng có thể là có thể, là tạo ra List32 Win32 của bạn trong một dự án C++, công cụ nó với các mục, và sử dụng hooking để nắm bắt thông báo CreateWindow được gửi bởi ListView khi tạo xử lý của nó và trả về một tham chiếu đến win32 ListView thay vì một cửa sổ mới .. nhưng ai mà biết được những gì bên cạnh ảnh hưởng sẽ có ... một guru Win32 sẽ cần phải lên tiếng về điều đó ý tưởng điên rồ :)

-2

Tạo tất cả ListViewItems bạnFIRST, sau đó thêm chúng vào ListView cùng một lúc.

Ví dụ:

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); 
+8

Ông ta đã làm điều đó trong các trang 3, 4, 5 và 6. –

6

tôi đã sử dụng mã này:

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

tôi đã thiết lập cũng GenerateMember false cho mỗi cột.

Liên kết tới bộ chọn chế độ xem danh sách tùy chỉnh: http://www.codeproject.com/Articles/5332/ListView-Column-Sorter

+4

Có, có một * máy sắp xếp * đang hoạt động trong khi thêm các mục là *** rất chậm. Nhưng trong trường hợp này tôi không có máy phân loại. Nhưng đây là một bước đầu tiên hữu ích cho những người có thể không nhận ra rằng listview .NET gọi sắp xếp * mỗi lần * một mục được thêm vào - thay vì ở cuối. –

0

Tôi có cùng một vấn đề. Sau đó, tôi tìm thấy nó là sorter làm cho nó rất chậm. Tận dụng tối sorter như là null

this.listViewAbnormalList.ListViewItemSorter = null; 

sau đó khi nhấp chuột sorter, trên ListView_ColumnClick phương pháp, làm cho nó

lv.ListViewItemSorter = new ListViewColumnSorter() 

Cuối cùng, sau khi nó được sắp xếp, làm cho sorter rỗng một lần nữa

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

[Slav2 đề xuất rằng] (http://stackoverflow.com/a/11379077/12597). Mà tôi cũng đề nghị trong câu hỏi ban đầu của tôi. –

+0

Vâng, nó giống với câu trả lời ở trên. :) – Batur

Các vấn đề liên quan