虚拟化一个ItemsControl?

我有一个ItemsControl包含我想虚拟化的数据列表,但是VirtualizingStackPanel.IsVirtualizing="True"似乎不能用于ItemsControl

这是真的,还是有另一种做法,我不知道?

为了testing我一直在使用下面的代码块:

 <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事件只运行几次(巨大的余量只是我只需要通过几条logging),但是作为一个ItemsControl每个项目都被初始化。

我已经尝试将ItemsControlPanelTemplate设置为VirtualizingStackPanel但似乎没有帮助。

实际上,比使ItemsPanelTemplate使用VirtualizingStackPanel还要多。 ItemsControl的默认ControlTemplate没有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> 

(顺便说一句,查看默认控制模板的好工具是Show Me The Template )

注意事项:

你必须设置ScrollViewer.CanContentScroll="True" ,请看这里为什么。

另外请注意,我把VirtualizingStackPanel.VirtualizationMode="Recycling" 。 这将减less调用TextBlock_Initialized的次数,但是在屏幕上可以看到许多TextBlocks。 你可以在这里阅读更多有关UI虚拟化的信息 。

编辑:忘了说明显:作为替代解决scheme,你可以用ListBoxreplaceItemsControl另外,请查看MSDN页面上的优化性能 ,注意ItemsControl不在“Controls that Implement Performance Features”表中,这就是为什么我们需要编辑控件模板。

基于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的build议,因为它们允许select不一定需要的行。

这只是默认的ItemsPanel不是一个VirtualizingStackPanel 。 你需要改变它:

 <ItemsControl> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl>