TreeView使用重写的控件模板丢失虚拟化

时间:2017-01-04 13:59:17

标签: wpf xaml treeview virtualization controltemplate

当我在XAML中有以下TreeView时(ItemsSource通过代码隐藏设置为一长串列表列表):

<TreeView x:Name="Tree"
          VirtualizingPanel.IsVirtualizing="True"
          ScrollViewer.CanContentScroll="True">
    <!-- ItemTemplate and ItemContainerStyle ommitted for brevity -->
</TreeView>

虚拟化工作得很好。但是,当我尝试覆盖TreeView的模板以及内部ScrollViewer的模板时,虚拟化消失了。我的模板看起来与默认模板相同,但我拿出的彩色矩形除外,这是重新定义模板的全部动机。

    <TreeView.Template>
        <ControlTemplate TargetType="{x:Type TreeView}">
            <ScrollViewer Focusable="False" 
                          CanContentScroll="True">
                <ScrollViewer.Template>
                    <ControlTemplate TargetType="{x:Type ScrollViewer}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition Height="auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition Width="auto" />
                            </Grid.ColumnDefinitions>

                            <ScrollContentPresenter Grid.Column="0" Grid.Row="0" />

                            <ScrollBar x:Name="PART_VerticalScrollBar" 
                                       Orientation="Vertical"
                                       Grid.Row="0" Grid.Column="1"
                                       Value="{TemplateBinding VerticalOffset}"
                                       Maximum="{TemplateBinding ScrollableHeight}"
                                       ViewportSize="{TemplateBinding ViewportHeight}"
                                       Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />

                            <ScrollBar x:Name="PART_HorizontalScrollBar"
                                       Orientation="Horizontal"
                                       Grid.Row="1" Grid.Column="0"
                                       Value="{TemplateBinding HorizontalOffset}"
                                       Maximum="{TemplateBinding ScrollableWidth}"
                                       ViewportSize="{TemplateBinding ViewportWidth}"
                                       Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
                        </Grid>
                    </ControlTemplate>
                </ScrollViewer.Template>
                <ScrollViewer.Content>
                    <ItemsPresenter x:Name="ItemsPresenter" />
                </ScrollViewer.Content>
            </ScrollViewer>
        </ControlTemplate>

我暂时通过在TreeView的资源中创建一个透明的SolidColorBrush {x:Static SystemColors.ControlBrushKey}来解决这个问题,但我更想知道我做错了什么。

2 个答案:

答案 0 :(得分:0)

许多因素可能会破坏用户界面虚拟化,有时甚至在您不期望它时:

  1. 将列表控件放在ScrollViewer中:ScrollViewer提供了一个窗口 它的孩子内容。问题是儿童内容被赋予无限的“虚拟” 空间。在这个虚拟空间中,ListBox以其全部大小呈现自己的全部大小 展出的物品。作为一个副作用,每个项目都有自己的内存占用 ListBoxItem对象。每次将ListBox放入容器时都会出现此问题 并不试图限制其规模;例如,如果出现同样的问题 将它弹出到StackPanel而不是Grid。
  2. 更改列表的控件模板并且无法使用ItemsPresenter: ItemsPresenter使用ItemsPanelTemplate,它指定了 VirtualizingStackPanel。如果你打破这种关系或改变了 ItemsPanelTemplate自己,所以它不使用VirtualizingStackPanel,你会输 虚拟化功能。
  3. 不使用数据绑定:应该是显而易见的,但如果您以编程方式填写列表 - 例如,通过动态创建ListBoxItem对象,您需要 - 否 虚拟化将会发生。当然,您可以考虑使用自己的优化 策略,例如仅创建您需要的对象并仅在其中创建它们 他们需要的时间。

答案 1 :(得分:0)

我发现了问题。在ScrollViewer模板中,ScrollContentPresenter需要将CanContentScroll设置为其模板化父级的值。

<ScrollContentPresenter Grid.Column="0" Grid.Row="0"
                        CanContentScroll="{TemplateBinding CanContentScroll}" />