Я реализовал решение для виртуализации данных, используя некоторые идеи из CodePlex и блог Bea Stollnitz и документ Vincent Da Ven Berhge (та же ссылка). Однако мне нужен был другой подход, поэтому я решил написать собственное решение.
Я использую DataGrid
, чтобы отобразить около миллиона строк с этим решением. Я также использую виртуализацию пользовательского интерфейса. Мое решение возможно, но в некоторых ситуациях я испытываю какое-то странное поведение о том, как DataGrid
запрашивает данные из своего источника.
О решении
В итоге я написал список, который делает всю тяжелую работу. Это общий класс с именем VirtualList<T>.
Он реализует интерфейс ICollectionViewFactory
, поэтому механизм создания представления коллекции может создать экземпляр VirtualListCollectionView<T>
для его переноса. Этот класс наследуется от ListCollectionView
. Я не стал следовать рекомендациям, чтобы написать свою собственную реализацию ICollectionView
. Наследование, похоже, отлично работает.
VirtualList<T>
разбивает все данные на страницы. Он получает общее количество элементов и каждый раз, когда DataGrid
запрашивает строку через индексный индекс, он загружает соответствующую страницу или возвращает ее из кеша. Страницы перерабатываются внутри, а DispatcherTimer
хранит неиспользуемые страницы в режиме простоя.
Шаблоны запросов данных
-
Первое, что я узнал, что
VirtualList<T>
должен реализоватьIList
(не общий). В противном случаеItemsControl
будет рассматривать его какIEnumerable
и запросить/перечислить все строки. Это логично, так какDataGrid
не является безопасным по типу, поэтому он не может использовать интерфейсIList<T>
. -
Строка с индексом 0 часто задается
DataGrid
. Кажется, что он используется для визуального измерения предметов (в зависимости от стека вызовов). Итак, я просто кешу этого. -
Механизм кэширования внутри
DataGrid
использует предсказуемый шаблон для запроса строк, которые он показывает. Сначала он запрашивает видимые строки сверху вниз (два раза для каждой строки), затем он запрашивает пару строк (в зависимости от размера видимой области) перед видимой областью (включая первую видимую строку) в нисходящем так, снизу вверх. После этого он запрашивает одно и то же количество строк после видимых строк (включая последнюю видимую строку) сверху вниз.Если индексы видимых строк равны 4,5,6. Запрос данных будет: 4,4,5,5,6,6,4,3,2,1,6,7,8,9.
Если мой размер страницы правильно установлен, я могу обслуживать все эти запросы с текущей и ранее загруженной страницы.
-
Если
CanSelectMultipleItems
-True
, и пользователь выбирает несколько элементов с помощью кнопки SHIFT или перетаскивания мышью,DataGrid
перечисляет все строки с начала списка до конца выделения. Это перечисление происходит через интерфейсIEnumerable
независимо от того, что реализованоIList
. -
Если выбранная строка не отображается, а текущая видимая область "далеко" от выбранной строки, иногда DataGrid начинает запрашивать все элементы, от выбранной строки до конца видимой области. Включая все строки, между которыми даже не видны. Я не мог разобраться в точном характере этого поведения. Может быть, моя реализация является причиной этого.
Мои вопросы
-
Мне интересно, почему запросы
DataGrid
для не видимых строк, так как эти строки будут запрашиваться снова, когда станут видимыми? -
Почему необходимо запрашивать каждую строку два или три раза?
-
Может ли кто-нибудь сказать мне, как заставить DataGrid использовать
IEnumerable
, за исключением отключения выбора нескольких элементов?