Виртуализация данных ListView и GridView

Примечание. Дополнительные сведения см. в материалах для мероприятия //build/ "Резкое повышение производительности при взаимодействии пользователей с большим объемом данных в GridView и ListView".

Повышение производительности ListView и GridView с помощью виртуализации данных. Сведения о виртуализации пользовательского интерфейса, сокращении элементов и постепенном обновлении элементов см. в разделе "Оптимизация пользовательского интерфейса ListView и GridView".

Метод виртуализации данных необходим для набора данных, который так велик, что он не может или не должен храниться в памяти одновременно. Вы загружаете начальную часть в память (из локального диска, сети или облака) и применяете виртуализацию пользовательского интерфейса к этому частичному набору данных. Позже данные можно загружать постепенно или из произвольных точек в наборе основных данных (случайный доступ) по запросу. Подходит ли виртуализация данных для вас во многих факторах.

  • Размер набора данных
  • Размер каждого элемента
  • Источник набора данных (локальный диск, сеть или облако)
  • Общее потребление памяти приложения

Примечание. Функция включена по умолчанию для ListView и GridView и отображает визуальные элементы временных заполнителей при быстром сдвиге или прокрутке. По мере загрузки данных эти заполнители заменяются шаблоном элемента. Вы можете отключить функцию, задав ListViewBase.ShowsScrollingPlaceholders значение false, но если это сделать, рекомендуется использовать атрибут x:Phase для постепенной отрисовки элементов в шаблоне элемента. Постепенно см. элементы ListView и GridView.

Ниже приведены дополнительные сведения о методах добавочной и случайной виртуализации данных.

Добавочная виртуализация данных

Добавочная виртуализация данных загружает данные последовательно. ListView, использующий добавочную виртуализацию данных, может использоваться для просмотра коллекции миллионов элементов, но изначально загружаются только 50 элементов. По мере того как пользователь сдвигает или прокручивает прокрутку, загрузятся следующие 50. По мере загрузки элементов большой палец полосы прокрутки уменьшается. Для этого типа виртуализации данных создается класс источника данных, реализующий эти интерфейсы.

Такой источник данных — это список в памяти, который может быть постоянно расширен. Элемент управления "Элементы" запрашивает элементы с помощью стандартного индексатора IList и свойств подсчета. Число должно представлять количество элементов локально, а не истинный размер набора данных.

Когда элемент управления "Элементы" приближается к концу существующих данных, он вызовет ISupportIncrementalLoading.HasMoreItems. Если вы возвращаете значение true, он вызовет ISupportIncrementalLoading.LoadMoreItemsAsync, передав рекомендуемое количество элементов для загрузки. В зависимости от места загрузки данных из (локального диска, сети или облака) можно загрузить другое количество элементов, чем рекомендуется. Например, если служба поддерживает пакеты из 50 элементов, но элемент управления "Элементы" запрашивает только 10 элементов, можно загрузить 50. Загрузите данные из серверной части, добавьте его в список и создайте уведомление об изменении с помощью INotifyCollectionChanged или IObservableVector<T> , чтобы элемент управления элементами знал о новых элементах. Также возвращает количество загруженных элементов. Если вы загружаете меньше элементов, чем рекомендуется, или элемент управления "Элементы" был перемещен или прокручен еще дальше в промежуточном режиме, то источник данных будет вызываться снова для дополнительных элементов, и цикл продолжится. Дополнительные сведения см. в примере привязки данных XAML для Windows 8.1 и повторном использовании исходного кода в приложении Windows 10.

Виртуализация данных случайного доступа

Виртуализация данных случайного доступа позволяет загружать данные из произвольной точки в наборе данных. ListView, использующий виртуализацию данных случайного доступа, используемую для просмотра коллекции миллионов элементов, может загружать элементы 100 000 – 100 050. Если пользователь переходит к началу списка, элемент управления загружает элементы 1 – 50. Во всех случаях большой палец полосы прокрутки указывает, что ListView содержит миллион элементов. Позиция отпечатка полосы прокрутки относительно того, где видимые элементы находятся во всем наборе данных коллекции. Этот тип виртуализации данных может значительно сократить требования к памяти и время загрузки для коллекции. Чтобы включить его, необходимо написать класс источника данных, который извлекает данные по запросу и управляет локальным кэшем и реализует эти интерфейсы.

IItemsRangeInfo предоставляет сведения о том, какие элементы активно использует элемент управления. Элемент управления элементами вызывает этот метод всякий раз, когда его представление изменяется, и будет включать эти два набора диапазонов.

  • Набор элементов, входящих в окно просмотра.
  • Набор не виртуализированных элементов, использующих элемент управления, который может не находиться в режиме просмотра.
    • Буфер элементов вокруг окна просмотра, который элемент управления "Элементы" сохраняется так, чтобы сенсорный сдвиг был гладким.
    • Элемент с фокусом.
    • Первый элемент.

Реализуя IItemsRangeInfo , источник данных знает, какие элементы необходимо получить и кэшировать, а также когда следует удалять данные кэша, которые больше не нужны. IItemsRangeInfo использует объекты ItemIndexRange для описания набора элементов на основе их индекса в коллекции. Это так, чтобы он не использовал указатели элементов, которые могут не быть правильными или стабильными. IItemsRangeInfo предназначен для использования только одним экземпляром элемента управления элементами, так как он использует сведения о состоянии для этого элемента управления. Если для нескольких элементов управления требуется доступ к одинаковым данным, для каждого из них потребуется отдельный экземпляр источника данных. Они могут совместно использовать общий кэш, но логика очистки из кэша будет более сложной.

Ниже приведена базовая стратегия для источника данных виртуализации данных случайного доступа.

  • При запросе элемента
    • Если у вас есть доступ к памяти, верните его.
    • Если у вас его нет, возвращается значение NULL или элемент заполнителя.
    • Используйте запрос элемента (или сведения о диапазоне из IItemsRangeInfo), чтобы узнать, какие элементы необходимы, и получить данные для элементов из серверной части асинхронно. После получения данных создайте уведомление об изменении с помощью INotifyCollectionChanged или IObservableVector<T>, чтобы элемент управления элементами знал о новом элементе.
  • (При необходимости) в качестве изменений окна просмотра элементов элемента управления определите необходимые элементы из источника данных через реализацию IItemsRangeInfo.

Помимо этого, стратегия загрузки элементов данных, сколько нужно загрузить, а также какие элементы хранятся в памяти в приложении. Некоторые общие рекомендации, которые следует учитывать:

  • Выполнение асинхронных запросов к данным; Не блокируйте поток пользовательского интерфейса.
  • Найдите сладкое место в размере пакетов, в которые вы извлекаете элементы. Предпочитайте куски болтливым. Не так мало, что вы делаете слишком много небольших запросов; не слишком большой, что они слишком долго извлекаются.
  • Рассмотрим, сколько запросов, которые требуется в одно и то же время. Выполнение одного за раз проще, но это может быть слишком медленно, если время поворота является высоким.
  • Можно ли отменить запросы на данные?
  • Если используется размещенная служба, есть ли затраты на транзакцию?
  • Какие уведомления предоставляются службой при изменении результатов запроса? Знаете ли вы, вставляется ли элемент по индексу 33? Если служба поддерживает запросы на основе смещения "ключ плюс", это может быть лучше, чем просто с помощью индекса.
  • Как вы хотите быть в предварительной выборке элементов? Вы собираетесь попробовать и отслеживать направление и скорость прокрутки, чтобы предсказать, какие элементы необходимы?
  • Насколько агрессивно вы хотите быть в очистке кэша? Это компромисс памяти и опыта.