2010-05-06 124 views
103

我有一个ItemsControl包含我想要虚拟化的数据列表,但VirtualizingStackPanel.IsVirtualizing="True"似乎不适用于ItemsControl虚拟化一个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> 

如果我改变ItemsControlListBox,我可以看到Initialized事件只运行的时间屈指可数(巨额利润所以我只需要通过几条记录),但是作为ItemsControl,每个项目都会被初始化。

我曾尝试将ItemsControlPanelTemplate设置为VirtualizingStackPanel,但这似乎没有帮助。

回答

178

这事实上它不仅仅是使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",请参阅here为什么。

另外请注意,我把VirtualizingStackPanel.VirtualizationMode="Recycling"。这将减少调用TextBlock_Initialized的次数,但是很多TextBlocks在屏幕上可见。您可以阅读关于用户界面虚拟化here 的更多信息。

编辑:忘了不言自明的:作为一个替代的解决方案,你可以用ListBox :) 更换ItemsControl此外,检查出这个Optimizing Performance on MSDN page并注意ItemsControl是不是在“控件实现性能特点”表这就是我们需要编辑控件模板的原因。

+1

谢谢你,那就是我正在寻找的那种东西!我正在寻找一种不同于列表框的选择行为,并且当时我认为这对于项目控件来说是最简单的。 – Rachel 2010-05-07 12:20:13

+0

ListView也适用于此。 – 2010-08-10 20:20:42

+0

如果这个itemcontrol进一步嵌套,你应该给它一个高度。否则,不会显示滚动查看器。 – buckley 2014-09-24 21:31:02

-3

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

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

谢谢,但我已经试过这个,它没有工作。 – Rachel 2010-05-07 12:22:38

+6

由于解决方案不完整,我对此投了弃权票。您需要在模板中使用滚动查看器来启用虚拟化。 – 2015-06-02 13:12:48

22

大厦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> 

我不喜欢这个建议,使用一个列表框,因为它们允许在那里你行的选择不一定需要它。