Высота окна просмотра ScrollViewer против фактической высоты

Оба являются довольно общими терминами, но мне интересно знать, когда эти высоты будут отличаться от случая, когда мы используем виртуализацию?

Еще один вопрос: читаю на MSDN:

Если CanContentScroll имеет значение true, значения свойств ExtentHeight, ScrollableHeight, ViewportHeight и VerticalOffset являются числом элементов. Если CanContentScroll имеет значение false, значения этих свойств являются независимыми от устройства пикселями.

Однако я столкнулся с проблемой с ViewPort Height: у меня есть 2 списка в приложении:
1. Для которых включена виртуализация и CanContentScroll = True.
2. Которые не имеют виртуализации и CanContentScroll = True.

В ListBox 1 при перетаскивании Высота области просмотра достигает 4/5 (Количество видимых элементов в данный момент). Однако в ListBox 2 я получаю высоту области просмотра, равную фактической высоте списка.

Почему эта разница?

Еще несколько выводов:
1. Высота прокрутки - это количество элементов, не видимых в программе просмотра прокрутки.
2. Высота окна просмотра - это количество элементов, видимых в программе просмотра прокрутки.
Таким образом Viewport Height + ScrollableHeight = Extent Height

Может кто-нибудь объяснить, в чем разница между двумя списками? Мне нужен ViewPort в случае Listbox 1

3 ответа

Решение

Наконец это было основной причиной:

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

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

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

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

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

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

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

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

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

но

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

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

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

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

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

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

Повышение устойчивости логической полосы прокрутки

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

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

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

  • Измените шаблон ScrollViewer, чтобы явно настроить свой пользовательский шаблон ScrollBar на логической полосе прокрутки
    (вместо использования по умолчанию
    шаблон)

  • Измените шаблон ListBox, чтобы использовать явно установить свой пользовательский
    Шаблон ScrollViewer на
    ScrollViewer это создает

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

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

Вежливость - Физическая прокрутка против логической прокрутки

ActualHeight фактическая высота ScrollViewer. Окно просмотра - это то, что видно из содержимого ScrollViewers. Итак, чтобы ответить на ваш вопрос: ViewportHeight отличается от ActualHeight если горизонтальная полоса прокрутки видна Height полосы прокрутки.

Итак, подведем итог:

ActualHeight = ViewportHeight + HorizontalScrollbarHeight

Они могут отличаться от точки (указано) Height оценивается в любое время во время (текущего) процесса рендеринга.

Из MSDN:

Существует разница между свойствами высоты и ширины, а также ActualHeight и ActualWidth. Например, свойство ActualHeight является вычисленным значением, основанным на других параметрах высоты и системе макетов. Значение задается самой системой макетов на основе фактического прохода рендеринга и поэтому может немного отставать от заданного значения свойств, таких как Высота, которые являются основой изменения ввода.

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

Другие вопросы по тегам