我有一个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
,但似乎没有帮助。
答案 0 :(得分:201)
实际上,除了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>
(BTW,一个查看默认控件模板的好工具是Show Me The Template)
需要注意的事项:
您必须设置ScrollViewer.CanContentScroll="True"
,请参阅here了解原因。
另请注意我放了VirtualizingStackPanel.VirtualizationMode="Recycling"
。这将减少调用TextBlock_Initialized
的次数,但屏幕上可以看到许多TextBlock。您可以阅读有关UI虚拟化here
的更多信息。
编辑:忘了陈述显而易见的:作为替代解决方案,您只需将ItemsControl
替换为ListBox
:)
另外,请查看此Optimizing Performance on MSDN page并注意ItemsControl
不在“实施性能功能的控件”表中,这就是我们需要编辑控件模板的原因。
答案 1 :(得分:29)
基于DavidN的回答,这是一个可以在ItemsControl上使用的样式来虚拟化它:
<!--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>
我不喜欢使用ListBox的建议,因为它们允许选择您不一定需要的行。
答案 2 :(得分:-3)
默认ItemsPanel
不是VirtualizingStackPanel
。你需要改变它:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>