虚拟化一个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,你可以用ListBox
replaceItemsControl
另外,请查看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>