У нас просто было аналогичное требование, чтобы иметь возможность отображать произвольные неиндексированные таблицы строк 1M + в нашем приложении с «очень хорошей» производительностью, используя набор DataGridView
. Сначала я подумал, что это невозможно, но с достаточным количеством царапин на голове мы нашли что-то, что работает очень хорошо после нескольких дней, проливая на Reflector и .NET Profiler. Это было трудно сделать, но результаты того стоили.
Мы решили эту проблему, создав класс, реализующий ITypedList
и IBindingList
(например, можно назвать LargeTableView
) для управления асинхронным поиском и кэшированием информации из базы данных. Мы также создали один класс наследования PropertyDescriptor (например, LargeTableColumnDescriptor
) для извлечения данных из каждого столбца.
Когда для свойства DataGridView.DataSource
задан класс, реализующий IBindingList
, он переходит в псевдовиртуальный режим , который отличается от обычного VirtualMode, где, например, когда закрашивается каждая строка (например, когда пользователь прокручивает), DataGridView обращается к индексатору [] для IBindingList
и соответствующим GetValue
методам для каждого столбца PropertyDescriptor
для извлечения значений по мере необходимости. Событие CellValueNeeded
не вызывается. В нашем случае мы обращаемся к базе данных при обращении к индексатору, а затем кешируем значение, чтобы последующие перерисовки не попадали в базу данных.
Я провел аналогичные тесты с использованием памяти. DataGridView
выделяет массив, который является размером списка (то есть 1М строк), однако каждый элемент в массиве изначально ссылается на один DataGridViewRow, поэтому использование памяти приемлемо. Я не уверен, является ли поведение таким же, когда VirtualMode имеет значение true. Нам удалось устранить задержку прокрутки , немедленно вернув String.Empty
в методе GetValue
, если строка не кэширована, а затем выполнив запрос к базе данных асинхронно. Когда асинхронный запрос завершен, вы можете вызвать событие IBindingList.ListChanged
, чтобы сообщить DataGridView, что ему следует перекрасить ячейки, за исключением этого времени чтения из кэша, который легко доступен. Таким образом, пользовательский интерфейс никогда не блокируется в ожидании вызовов базы данных.
Одна вещь, которую мы заметили, заключается в том, что производительность значительно выше, если вы установите DataSource или количество виртуальных строк до , добавив DataGridView в форму - это сократит время инициализации вдвое. Кроме того, убедитесь, что для автоматического изменения размера строки и столбца установлено значение None
, иначе у вас возникнут дополнительные проблемы с производительностью.
Примечание: способ «загрузки» такой большой таблицы в наше приложение .NET заключался в создании временной таблицы на сервере SQL, которая перечисляла первичные ключи в нужном порядке сортировки вместе с IDENTITY ( номер строки), а затем сохранить соединение для последующих запросов строки. Это, естественно, требует времени для инициализации (примерно 3-5 с на достаточно быстром SQL-сервере), но без знания доступных индексов у нас нет лучшей альтернативы. Затем в нашей реализации ITypedList мы запрашиваем строки на страницах по 100 строк, где 50-я строка - это строка, которая рисуется, так что мы ограничиваем количество запросов, выполняемых при каждом обращении к индексатору, и получаем вид наличие всех данных, доступных в нашем приложении.
Дальнейшее чтение:
http://msdn.microsoft.com/en-us/library/ms404298.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.ibindinglist.aspx