Я имею ItemsControl
содержа список данных, которые я хотел бы виртуализировать, однако VirtualizingStackPanel.IsVirtualizing="True"
кажется, не работает с ItemsControl
.
Этот действительно имеет место или там другой способ сделать это, что я не знаю?
Для тестирования я использовал следующий блок кода:
<ItemsControl ItemsSource="{Binding Path=AccountViews.Tables[0]}"
VirtualizingStackPanel.IsVirtualizing="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Initialized="TextBlock_Initialized"
Margin="5,50,5,50" Text="{Binding Path=Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Если я изменяюсь ItemsControl
к a ListBox
, Я вижу что Initialized
событие только работает несколько разы (огромные поля именно так, я только должен пройти несколько записей), однако как ItemsControl
каждый объект инициализируется.
Я попытался установить ItemsControlPanelTemplate
к a VirtualizingStackPanel
но это, кажется, не помогает.
На самом деле это гораздо больше, чем просто создание ItemsPanelTemplate
используйте VirtualizingStackPanel
. По умолчанию ControlTemplate
для ItemsControl
не имеет ScrollViewer
, который является ключом к виртуализации. Добавление к шаблону элемента управления по умолчанию для ItemsControl
(с использованием шаблона элемента управления для ListBox
в качестве шаблона) дает нам следующее:
<ItemsControl
VirtualizingStackPanel.IsVirtualizing="True"
ScrollViewer.CanContentScroll="True"
ItemsSource="{Binding Path=AccountViews.Tables[0]}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock
Initialized="TextBlock_Initialized"
Text="{Binding Path=Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate>
<Border
BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<ScrollViewer
Padding="{TemplateBinding Control.Padding}"
Focusable="False">
<ItemsPresenter
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
(Кстати, отличный инструмент для просмотра значений по умолчанию шаблоны управления: Покажи мне шаблон )
На заметку:
Вы должны установить ScrollViewer.CanContentScroll = "True"
, см. здесь почему.
Также обратите внимание, что я поместил VirtualizingStackPanel.VirtualizationMode = "Recycling"
. Это уменьшит количество вызовов TextBlock_Initialized
, сколько бы текстовых блоков ни отображалось на экране. Подробнее о виртуализации пользовательского интерфейса можно прочитать здесь
.
РЕДАКТИРОВАТЬ: Забыл указать очевидное: в качестве альтернативного решения вы можете просто заменить ItemsControl
на ListBox
:)
Также ознакомьтесь с этим Оптимизация производительности на странице MSDN и обратите внимание, что ItemsControl
нет в таблице «Элементы управления, реализующие функции производительности», поэтому нам нужно отредактировать шаблон элемента управления.
Просто по умолчанию ItemsPanel
не является VirtualizingStackPanel
. Вам нужно изменить его:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>