Я взглянул на исходный код для представления списка и заметил несколько вещей, которые могут замедлить производительность в 4 раза или около того, что вы видите:
в ListView.cs, ListViewItemsCollection.AddRange
звонки ListViewNativeItemCollection.AddRange
, где я и начал аудит
ListViewNativeItemCollection.AddRange
(из строки: 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
и вызывает InsertItemsNative
напрямую, без лишней суеты.
Вы можете прочитать код ListView
в справочном источнике и посмотреть, может быть, я что-то пропустил.
В мартовском выпуске журнала MSDN за март 2006 года была статья под названием Winning Forms: Practical Tips for Boosting The Performance of Windows Forms Apps
.
Эта статья, среди прочего, содержала советы по повышению производительности ListViews. Кажется, это указывает на то, что быстрее добавлять элементы перед созданием дескриптора, но вы заплатите цену при визуализации элемента управления. Возможно, применение оптимизаций рендеринга, упомянутых в комментариях, и добавление элементов до создания дескриптора позволит получить лучшее из обоих миров.
Редактировать: Эта гипотеза проверялась различными способами, и хотя добавление элементов перед созданием дескриптора происходит очень быстро, оно экспоненциально медленнее, когда идет создание дескриптора. Я пытался обмануть его, чтобы создать дескриптор, затем каким-то образом заставить его вызывать InsertItemsNative, не проходя все дополнительные проходы, но, увы, я был сорван. Единственное, что я мог бы подумать, что это возможно, - это создать свой Win32 ListView в проекте c ++, заполнить его элементами и использовать перехват для захвата сообщения CreateWindow, отправленного ListView при создании его дескриптора, и передачи ссылки на win32 ListView вместо нового окна ... но кто знает, на что может повлиять сторона ... Гуру Win32 нужно будет рассказать об этой безумной идее:)