Is it possible to override the ItemsPresenter to use a Virtualizing StackPanel instead of a regular stack panel?

tsells picture tsells · Feb 29, 2012 · Viewed 7.8k times · Source

Background

I have a custom control that inherits from a TreeView and is modified to display in a data grid style. The problem I am seeing is with performance when expanding the tree. This is common from my research with Tree Views. Upon inspection with the WPF Performance tools I noticed that the ItemsPresenter class is using a regular Stack Panel instead of a Virtualizing Stack Panel.

enter image description here

Here is the section of code where the ScrollContentPresenter is used (showing in image).

<ScrollContentPresenter Name="PART_ScrollContentPresenter"
      KeyboardNavigation.DirectionalNavigation="Local"
      Content="{TemplateBinding Content}"
      ContentTemplate="{TemplateBinding ContentTemplate}"
      CanContentScroll="{TemplateBinding CanContentScroll}"
      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>

Here is the template being passed in.

    <ControlTemplate TargetType="CommonControls:TreeListViewItem508">
    <Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Border x:Name="item">
            <Border Name="InnerBorder">
                <Grid Style="{StaticResource GridBackgroundStyle}">
                    <Rectangle Visibility="Collapsed" Fill="#75FFFFFF" Name="UpperHighlight" />
                </Grid>
            </Border>
        </Border>
        <ItemsPresenter Grid.Row="1" Name="ItemsHost" />
    </Grid>
</ControlTemplate>

Question

Is it possible to force the items presenter to use a virtualizing stack panel?

Notes

  • I have already tried wrapping the ItemsPresenter in a ScrollViewer but that gives undesired results (scroll bars for each row).
  • I hard coded the option CanContentScroll = true as a test since this disables virtualization when its set to false.
  • This control is in production and used in multiple places so I don't have the option to replace / rewrite / or perform major modifications to the design at this point. I am just looking to override this one section if possible.

Any suggestions or options are much appreciated.

Resolved:

I modified the template's style by adding this to the style and it switched the stack panels to virtualizing.

 <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>

Answer

Rachel picture Rachel · Feb 29, 2012

You can use a VirtualizingStackPanel, however be aware that there is more to virtualizing a StackPanel than just using a VirtualizingStackPanel

Here is an example using the code found in the link posted above which lists the items that are needed:

<ItemsControl ...
    VirtualizingStackPanel.IsVirtualizing="True" <!-- this is needed -->
    ScrollViewer.CanContentScroll="True" > <!-- this is needed -->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />  <!-- this is needed -->
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.Template>
        <ControlTemplate>
            <Border ...>
                <ScrollViewer> <!-- this is needed -->
                    <ItemsPresenter />
                </ScrollViewer>
            </Border>
        </ControlTemplate>
    </ItemsControl.Template>
</ItemsControl>