虚拟化ItemsControl?

Rac*_*hel 121 wpf virtualization itemscontrol virtualizingstackpanel

我有一个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>
Run Code Online (Sandbox Code Playgroud)

如果我将其更改ItemsControl为a ListBox,我可以看到该Initialized事件只运行了几次(巨大的边距只是因此我只需要通过一些记录),但是ItemsControl每个项目都会被初始化.

我试过设置ItemsControlPanelTemplate为a VirtualizingStackPanel但似乎没有帮助.

Dav*_*idN 210

实际上它不仅仅是ItemsPanelTemplate使用它VirtualizingStackPanel.默认ControlTemplateItemsControl不具备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>
Run Code Online (Sandbox Code Playgroud)

(BTW,一个查看默认控件模板的好工具是Show Me The Template)

需要注意的事项:

你必须设置ScrollViewer.CanContentScroll="True",看到这里的原因.

还要注意我放了VirtualizingStackPanel.VirtualizationMode="Recycling".这将减少TextBlock_Initialized调用的次数,但是在屏幕上可以看到许多TextBlock.你可以阅读更多的UI虚拟这里 .

编辑:忘了不言自明的:作为一个替代的解决方案,只需更换ItemsControlListBox:)另外,看看这个MSDN页面上优化性能,请注意,ItemsControl是不是在"控件实现性能特点"表,这是为什么我们需要编辑控件模板.

  • "还注意到我把VirtualizingStackPanel.VirtualizationMode = Recycling".它不应该在你提供的样本中吗? (9认同)
  • ```ScrollViewer.CanContentScroll="True"``` 有一个缺点,这是虚拟化工作所必需的,因为该项目而不是基于像素的处理会在列表末尾产生不需要的空格。不过,从 .NET 4.5 开始,可以通过在“ItemsControl”中添加“VirtualizingPanel.ScrollUnit="Pixel” VirtualizingPanel.IsContainerVirtualizing="True"``` 来修复此问题 (2认同)

Zod*_*man 33

基于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>
Run Code Online (Sandbox Code Playgroud)

我不喜欢使用ListBox的建议,因为它们允许选择您不一定需要的行.