I have a List
of 774 items. When I set it to Items
property (also List
) of ViewModel bound to ItemsSource
, it takes about 10+ seconds.
I have already tried the answer from Virtualizing an ItemsControl? and it did not work - still 10+ seconds.
This is unmodified code. Note that ItemsControl
is inside a ScrollViewer
.
XAML:
<Grid d:DataContext="{x:Static local:RulesListDesignModel.Instance}" Background="{StaticResource ForegroundLightBrush}">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:RulesListItemControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
C#
ViewModelApplication.CurrentRulesListViewModel.Items = mList;
This is XAML after modifying the code according to the answer from Virtualizing an ItemsControl? (seems to take a bit more than 10 seconds):
<Grid d:DataContext="{x:Static local:RulesListDesignModel.Instance}" Background="{StaticResource ForegroundLightBrush}">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Items}"
VirtualizingStackPanel.IsVirtualizing="True"
ScrollViewer.CanContentScroll="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:RulesListItemControl />
</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>
</Grid>
You should use a ListBox
or ListView
, which have their ScrollViewer
integrated and UI virtualization enabled by default. There is no need to use the more basic ItemsControl
.
You should try the following to use UI virtualization:
<ListBox VirtualizingStackPanel.VirtualizationMode="Recycling" />
Setting VirtualizingStackPanel.VirtualizationMode
to VirtualizationMode.Recycling
improves the scroll performance.
If you want to stay with the ItemsControl
(why would you?) you need to rework the visual tree.
You are currently using two ScrollViewers
. One inside the template and one wrapped around the ItemsControl
. Note that since ScrollViewer.CanContentScroll
defaults to false
, the inner ScrollViewer
is responsible to disable UI virtualization. Setting CanContentScroll
to true
is essential, as it will set the scroll unit to item (instead of pixel). The VirtualizingStackPanel
needs to know the number of visible items.
You should remove the outer ScrollViewer
and your performance should significantly improve:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:RulesListItemControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsVirtualizing="True"
VirtualizationMode="Recycling" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ScrollViewer CanContentScroll="True"
Padding="{TemplateBinding Padding}"
Focusable="False">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
But more important is to focus on your custom RulesListItemControl
. This control is loaded for every item. Complex controls introduces complex initialization. You should try to reduce the visual tree of this control.
Remove every Border
that is not needed, replace Label
with TextBlock
, revisit triggers etc. The goal is to reduce rendering time of each item container.
To do this, you need to override the ControlTemplate
of the controls that you use to compose the RulesListItemControl
.