Виртуализация панелей используется, когда необходимо улучшить производительность приложения. Он обеспечивает базовую панель для виртуализации дочерних элементов внутри нее. Вместо создания всех элементов пользовательского интерфейса, которые находятся внутри ItemControls, создается только тот элемент, который необходимо отобразить. Поскольку процесс создания этих элементов интенсивен, использование VirtualizingPanel ускоряет отображение элементов управления.
VirtualizingPanel поставляется с новыми функциями в WPF 4.5: два свойства с именами ScrollUnit и CacheLength и виртуализация для сгруппированных данных. В этом посте мы узнаем их подробнее.
Этот пост является частью серии о новых возможностях WPF 4.5 .
Поведение WPF 4.0
Чтобы проиллюстрировать новые свойства и их использование, мы создадим демонстрационный проект. Его можно найти в моей папке Dropbox после регистрации .
Это простое приложение WPF отображает список людей в списке со включенной виртуализацией . В последней части мы сгруппируем людей по возрасту.
Здесь есть кнопка, позволяющая пользователю добавить в список много людей (на самом деле 500). Когда эта операция завершена, мы вычисляем истекшее время рендеринга и отображаем его в виде сообщения в строке состояния. Это позволяет нам быть уверенными, что виртуализация действительно включена. Когда это так, загрузка занимает десяток мс, а когда нет, операция занимает много времени (7000 мс на моем компьютере). Это один из сценариев виртуализации.
foreach (var person in persons) { Persons.Add(person); } var watch = new Stopwatch(); watch.Start(); //Wait for the rendering is finished.. Dispatcher.CurrentDispatcher.Invoke(new Action(() => { }), DispatcherPriority.Loaded, null); watch.Stop(); Message = string.Format("Rendering took {0} ms.", watch.ElapsedMilliseconds);
Виртуализация может быть включена и отключена через вложенное свойство VirtualizingStackPanel.IsVirtualizing в ListBox. По умолчанию это так, но мы все равно заставляем его:
<ListBox ItemsSource="{Binding Persons}" Background="LightBlue" ItemTemplate="{StaticResource PersonDataTemplate}" ItemContainerStyle="{StaticResource ListBoxItemStyle}" VirtualizingStackPanel.IsVirtualizing="True" HorizontalContentAlignment="Stretch" />
Чтобы видеть вещи ясно, я определил стиль для ListBoxItem, который установил их фон в розовый цвет, и я установил фон ListBox в синий:
CacheLength
ViewPort — это видимая область панели виртуализации. При виртуализации только видимые внутри области просмотра действительно создаются в памяти. Создание этих предметов может быть интенсивным и требует заметного времени, чтобы сделать. Если это так, процесс прокрутки не очень хорош для пользователя, потому что реактивность приложения падает до нуля.
Чтобы воспроизвести этот сценарий, я создал UserControl с именем TimeConsumingControl, и я долго что-то делаю в его конструкторе. Затем я помещаю это в DataTemplate:
<DataTemplate x:Key="PersonDataTemplate" DataType="{x:Type local:Person}"> <Grid> <!--This will take time to be instancied--> <local:TimeConsumingControl /> <!--Rest of the data template--> ... </Grid>
В WPF 4.5 вы можете создать кэш элемента, который не отображается. Когда панель виртуализации завершила рендеринг своих элементов, она начинает создавать кэш с низким приоритетом. Таким образом, когда пользователь прокручивает список, он не чувствует медленности рендеринга, поскольку элементы уже будут созданы в кеше. Не то чтобы это было верно только для того, кто в кеше
Вы можете использовать два свойства для настройки кэша в WPF 4.5:
- CacheLength : объем пространства, созданного в кэше до и после ViewPort. Значение по умолчанию составляет 1,1.
- CacheLengthUnit : единица измерения количества места: пиксель, элемент или страница. Страница определяется размером окна просмотра. Значением по умолчанию является страница в документе MSDN, но в моих тестах это, похоже, Item.
Продемонстрировать преимущества их использования сложно с помощью картинки, но вы можете попробовать демонстрационное приложение, чтобы заметить это .
Вот пример их использования в демонстрационном приложении XAML, которое определяет кэш из 2 страниц перед viewPort и 3 после него:
<ListBox ItemsSource="{Binding Persons}" ItemTemplate="{StaticResource PersonDataTemplate}" ItemContainerStyle="{StaticResource ListBoxItemStyle}" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.CacheLength="2,3" VirtualizingStackPanel.CacheLengthUnit="Page"/>
ScrollUnit
Когда виртуализация включена, прокрутка может восприниматься пользователем как нечетная, поскольку отображаются только полные элементы. Если элемент не полностью помещается в область просмотра, определенную ItemsControl, он не отображается.
В WPF 4.5 вы можете установить для свойства ScrollUnit одно из следующих значений:
- Элемент: на панели виртуализации может отображаться пустое окно, поскольку элементы, которые должны быть обрезаны, не отображаются. Это значение по умолчанию (как в WPF 4.0).
- Пиксель: панель виртуализации может отображать частично / обрезанные элементы, так как вы можете исключить их, чтобы они стали поведением по умолчанию.
Поэтому, если мы обновим предыдущий пример, чтобы установить для этого свойства значение Pixel, мы получим следующий XAML:
<ListBox ItemsSource="{Binding Persons}" ItemTemplate="{StaticResource PersonDataTemplate}" ItemContainerStyle="{StaticResource ListBoxItemStyle}" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.ScrollUnit="Pixel" />
IsContainerVirtualizable
Наконец, я узнал, читая документацию MSDN новое присоединенное свойство с именем IsContainerVirtualizable . Похоже, это свойство, которое сообщает VirtualizingPanel, следует ли виртуализировать элемент или нет.
Я пытался использовать это, но мне не удалось. Поэтому я не могу рассказать вам больше об этом, кроме того, что он существует!