Virtualizing an ItemsControl?

前端 未结 3 2008
终归单人心
终归单人心 2020-11-22 03:45

I have an ItemsControl containing a list of data that I would like to virtualize, however VirtualizingStackPanel.IsVirtualizing=\"True\" does not s

相关标签:
3条回答
  • 2020-11-22 04:00

    Building on DavidN's answer, here is a style you can use on an ItemsControl to virtualise it:

    <!--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>
    

    I do not like the suggestion to use a ListBox as they allow the selection of rows where you do not necessarily want it.

    0 讨论(0)
  • 2020-11-22 04:25

    There's actually much more to it than just making the ItemsPanelTemplate use VirtualizingStackPanel. The default ControlTemplate for ItemsControl does not have a ScrollViewer, which is the key to virtualization. Adding to the the default control template for ItemsControl (using the control template for ListBox as a template) gives us the following:

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

    (BTW, a great tool for looking at default control templates is Show Me The Template)

    Things to notice:

    You have to set ScrollViewer.CanContentScroll="True", see here for why.

    Also notice that I put VirtualizingStackPanel.VirtualizationMode="Recycling". This will reduce the numbers of times TextBlock_Initialized is called to however many TextBlocks are visible on the screen. You can read more on UI virtualization here .

    EDIT: Forgot to state the obvious: as an alternate solution, you can just replace ItemsControl with ListBox :) Also, check out this Optimizing Performance on MSDN page and notice that ItemsControl isn't in the "Controls That Implement Performance Features" table, which is why we need to edit the control template.

    0 讨论(0)
  • 2020-11-22 04:26

    It is just that the default ItemsPanel isn't a VirtualizingStackPanel. You need to change it:

    <ItemsControl>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
    
    0 讨论(0)
提交回复
热议问题