Виртуализация элементов контроля?
-
03-10-2019 - |
Вопрос
у меня есть 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
к А. ListBox
, Я могу видеть, что Initialized
Мероприятие работает только в нескольких раз (огромные поля просто, поэтому мне нужно только пройти через несколько записей), однако, как ItemsControl
каждый элемент получает инициализированно.
Я пытался установить ItemsControlPanelTemplate
к А. 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
Не находится в таблице «Управления, которые реализуют функции производительности», поэтому нам нужно редактировать шаблон управления.
Другие советы
Строительство на ответе Давидна, вот стиль, который вы можете использовать на элементахControl для виртуализации его:
<!--Virtualised ItemsControl-->
<Style x:Key="ItemsControlVirtualizedStyle" TargetType="ItemsControl">
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<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>
</Setter.Value>
</Setter>
</Style>
Мне не нравится предположение для использования списка, поскольку они позволяют выбирать строки, где вы не обязательно хотите.
Это только то значение по умолчанию ItemsPanel
не а VirtualizingStackPanel
. Отказ Вам нужно изменить это:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>