Подтвердить что ты не робот

WPF DataGrid: свойство CanContentScroll, вызывающее нечетное поведение

У меня есть решение, в котором я генерирую DataGrid (или несколько экземпляров) на основе пользовательских критериев. Каждая сетка продолжает получать данные, когда она приходит через ObservableCollection

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

чем я нашел.. CanContentScroll свойство! Он полностью фиксирует странное поведение прокрутки, приносящее мне временное блаженство и счастье.

однако он вызывает 2 неудачных побочных эффекта.

  • всякий раз, когда я снова создаю экземпляры сетки и привязываю их к моей наблюдаемой коллекции, она замораживает все мое окно в течение 5 секунд. когда моя сетка растет до большого размера, эта задержка может продолжаться 30 секунд.

  • когда я вызываю TradeGrid.ScrollIntoView(TradeGrid.Items(TradeGrid.Items.Count - 1)), чтобы прокручивать его вниз, он прыгает вниз и назад.

Есть ли другой способ добиться плавной прокрутки?

4b9b3361

Ответ 1

Вы сталкиваетесь с различиями между физической прокруткой и логической прокруткой.

Как вы обнаружили, у каждого есть свои компромиссы.

Физическая прокрутка

Физическая прокрутка (CanContentScroll = false) просто идет по пикселям, поэтому:

  • Окно просмотра всегда представляет собой ту же часть вашего размера прокрутки, что дает вам гладкий опыт прокрутки и

но

  • Все содержимое DataGrid должно иметь все шаблоны, которые были полностью применены и измерены и упорядочены для определения размера полосы прокрутки, что приводит к длительным задержкам во время загрузки и высокому использованию ОЗУ и
  • На самом деле это не прокрутка элементов, поэтому он не очень хорошо разбирается в ScrollIntoView.

Логическая прокрутка

Логическая прокрутка (CanContentScroll = true) вычисляет его видовое пространство прокрутки и степень по элементам вместо пикселей, поэтому:

  • В окне просмотра может отображаться различное количество элементов в разное время, то есть количество элементов в окне просмотра по сравнению с количеством элементов в пределах варьируется, что приводит к изменению длины полосы прокрутки и

  • Прокрутка перемещается от одного элемента к другому и никогда не находится между ними, что приводит к "отрывистой" прокрутке

но

  • Пока вы используете VirtualizationStackPanel под капотом, нужно только применять шаблоны, а также измерять и упорядочивать элементы, которые на самом деле видны в данный момент, и

  • ScrollIntoView намного проще, так как ему просто нужно получить нужный индекс элемента

Выбор между ними

Это только два вида прокрутки, предоставляемые WPF. Вы должны выбирать между ними на основе вышеупомянутых компромиссов. Обычно логическая прокрутка лучше всего подходит для средних и больших наборов данных, а физическая прокрутка лучше всего подходит для небольших.

Трюк для ускорения загрузки во время физической прокрутки состоит в том, чтобы сделать физическую прокрутку лучше, чтобы обернуть ваши предметы в пользовательский Decorator, который имеет фиксированный размер и устанавливает его дочернюю видимость в скрытую, когда она не видна. Это предотвращает появление ApplyTemplate, Measure и Arrange на элементах управления потомками этого элемента, пока вы не будете готовы к этому.

Трюк, чтобы сделать физическую прокрутку ScrollIntoView более надежным, - это вызвать его дважды: сразу же и один раз в обратном вызове диспетчера DispatcherPriority.ApplicationIdle.

Улучшение стабильности прокрутки логической прокрутки

Если все ваши элементы имеют одинаковую высоту, количество элементов, видимых в окне просмотра в любое время, будет оставаться неизменным, в результате чего размер большого пальца прокрутки останется прежним (поскольку отношение с общим числом, если элементы не меняются).

Также возможно изменить поведение самого ScrollBar, поэтому большой палец всегда рассчитывается как фиксированный размер. Чтобы сделать это без какого-либо взломанного кода:

  • Подкласс Track, чтобы заменить вычисление положения и размера Thumb в MeasureOverride с помощью собственных
  • Измените шаблон ScrollBar, используемый для прокрутки ScrollBar с логической прокруткой, чтобы использовать ваш подклассовый трек вместо обычного.
  • Измените шаблон ScrollViewer, чтобы явно настроить свой собственный шаблон ScrollBar на прокручиваемом ScrollBar (вместо шаблона по умолчанию)
  • Измените шаблон ListBox, чтобы использовать явно установленный пользовательский шаблон ScrollViewer на создаваемом им ScrollViewer.

Это означает, что вы копируете много шаблонов кода с встроенными шаблонами WPF, поэтому это не очень изящное решение. Но альтернативой этому является использование хакерского кода для ожидания до тех пор, пока все шаблоны не будут расширены, а затем найдите ScrollBar и просто замените шаблон ScrollBar тем, который использует ваш собственный трек. Этот код сохраняет два больших шаблона (ListBox, ScrollViewer) за счет очень сложного кода.

Использование другой панели будет гораздо большим объемом работы: VirtualizingStackPanel - это единственная панель, которая виртуализирует, и только она и StackPanel для логической прокрутки. Поскольку вы используете возможности виртуализации VirtualizingStackPanel, вам придется перепрограммировать все эти функции, а также все функции info IScrollInfo, а также ваши обычные функции Panel. Я мог бы сделать что-то подобное, но я бы выделил несколько, возможно, много дней, чтобы все было правильно. Я рекомендую вам не попробовать.

Ответ 2

У меня также есть проблема с моей DataGrid, и, наконец, я сделал:

ScrollViewer.CanContentScroll="True"   
EnableRowVirtualization="True"
VirtualizingPanel.VirtualizationMode="Standard"

Теперь все отлично работает в моем DataGrid.