虚拟化ItemsControl?


125

我有一个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改为a ListBox,则可以看到该Initialized事件只运行了几次(巨大的利润只是为了让我只需要查看一些记录),但是ItemsControl每一项都被初始化了。

我尝试将设置ItemsControlPanelTemplate为a,VirtualizingStackPanel但这似乎无济于事。

Answers:


219

实际上,有很多更给它不仅仅是制作ItemsPanelTemplate使用VirtualizingStackPanel。默认ControlTemplateItemsControl不具备ScrollViewer,这是关键的虚拟化。将默认控件模板添加到ItemsControl(使用控件模板ListBox作为模板)的默认控件模板中,可以得到以下内容:

<ItemsControl ItemsSource="{Binding AccountViews.Tables[0]}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <TextBlock Initialized="TextBlock_Initialized"
                 Text="{Binding Name}" />
    </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>

(顺便说一句,查看默认控件模板的好工具是“ 向我展示模板”

注意事项:

您必须设置ScrollViewer.CanContentScroll="True",有关原因请参见此处

另请注意,我放了VirtualizingStackPanel.VirtualizationMode="Recycling"。这样可以减少TextBlock_Initialized被调用的次数,但是在屏幕上却可以看到许多TextBlock。您可以在此处阅读有关UI虚拟化的更多信息

编辑:忘了说清楚点:作为替代解决方案,您可以替换ItemsControlListBox:)此外,在MSDN页面上查看此优化性能,并注意ItemsControl“实现性能功能的控件”表中没有此内容,这就是为什么我们需要编辑控件模板。


1
谢谢,这正是我想要的东西!我一直在寻找与列表框不同的选择行为,当时我认为使用项目控件最简单。
雷切尔2010年

如果此itemscontrol进一步嵌套,则还应该给它一个高度。否则,不会显示scrollviewer。
棘手的2014年

9
“还要注意,我把VirtualizingStackPanel.VirtualizationMode = Recycling放了”。它不是应该在您提供的样本中吗?
2015年

虚拟化是否也当包装工ItemsControlScrollViewerinstread添加ScrollControlTemplate
演示

@DavidN在哪里或如何将列标题放在您的解决方案中?
奥兹坎

37

在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的建议,因为它们允许选择不一定需要的行。


-3

只是默认ItemsPanel值不是VirtualizingStackPanel。您需要更改它:

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

8
我不赞成投票,因为解决方案不完整。您需要在模板中使用滚动查看器以启用虚拟化。
萨拉夫·塔卢德(
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.