Как ускорить добавление элементов в ListView?

Я добавляю несколько тысяч (например, 53 709) элементов в WinForms ListView.

Попытка 1 : 13 870 мс

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

Это работает очень плохо. Первое очевидное решение - вызвать BeginUpdate / EndUpdate .

Попытка 2 : 3,106 мс

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 мс

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: 2,182 мс

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

Немного лучше. Убедитесь, что узкое место не в ToArray ()

Попытка 5: 2,132 мс

ListViewItem[] arr = items.ToArray();

stopwatch.Start();

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

stopwatch.Stop();

Кажется, ограничение заключается в добавлении элементов в список.Возможно, другая перегрузка AddRange , где мы добавляем ListView.ListViewItemCollection , а не массив

. Попытка 6: 2141 мс

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

Что ж, не лучше.

Теперь пора растянуть:

  • Шаг 1 - убедитесь, что ни один столбец не установлен на «автоматическая ширина» :

    enter image description here

    Проверьте

  • Шаг 2 - убедитесь, что ListView не пытается сортировать элементы каждый раз, когда я добавляю один:

    enter image description here

    Проверить

  • Шаг 3 - Спросить stackoverflow:

    enter image description here

    Проверить

Примечание: Очевидно, что этот ListView является не в виртуальном режиме; поскольку вы не можете / не можете «добавлять» элементы в представление виртуального списка (вы устанавливаете VirtualListSize ). К счастью, мой вопрос не о представлении списка в виртуальном режиме.

Есть ли что-то, чего мне не хватает, что могло бы объяснить такое медленное добавление элементов в список?


Bonus Chatter

Я знаю, что класс Windows ListView может работать лучше, потому что я могу написать код, который делает это в 394 мс :

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

, что по сравнению с эквивалентным кодом C # 1349 мс :

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

на порядок быстрее.

Какое свойство оболочки WinForms ListView мне не хватает?

81
задан Ian Boyd 25 January 2012 в 18:41
поделиться