虚拟化堆栈面板如何在不实例化实际项目的情况下计算子大小

本文关键字:项目 情况下 计算 实例化 堆栈 虚拟化 | 更新日期: 2023-09-27 18:35:26

我正在按照这里介绍的教程进行操作:

http://blogs.msdn.com/b/dancre/archive/tags/virtualizingtilepanel/

它们的实现中,它们在 VirtualizingTilePanel 上具有一个依赖属性,用于跟踪子大小。但是,WPF 库的虚拟化堆栈面板不需要我将子元素的大小设置为属性。但是,我不明白虚拟化堆栈面板如何在不实例化项目的情况下计算面板中的哪些项目可见。

我认为他们需要度量传递才能知道项目容器的大小,但是如果不首先实例化项目,他们怎么能知道呢?

我的目标是创建一个面板来包含树视图项并对其进行虚拟化,但遵循虚拟化磁贴面板的示例只能让我虚拟化顶级项。

我需要更改它计算哪些项目可见

的方式,但我看不出它如何在不知道大小并实际实例化项目的情况下知道哪些项目可见。

编辑:等等,也许它会立即实例化进入 TreeViewItem 中的对象并使用这些对象来计算大小?

虚拟化堆栈面板如何在不实例化实际项目的情况下计算子大小

VirtualizingStackPanel 有两种模式。一种称为ScrollToContent,在这种模式下,VirtualizingStackPanel使用项目的索引。例如,可见的是 10 个项目,而您有 1000 个项目的数量,因此滚动条将显示得很小。

第二种模式称为ScrollToPixel,在此模式下,VirtualizingStackPanel管理哪些项目被虚拟化以及哪些项目被实现的列表。如果一个项目尚未实现,VirtualizingStackPanel 使用其 MinHeight 值,如果没有由用户为 Microsoft 设置 16 像素。例如,可见有 10 个项目,每个项目的高度为 20 像素。视口高度为 200 像素,但您总共有 1000 个项目,因此范围将为 200 + (1000 - 10 ) * 16 = 16040 像素。滚动条也会显得很小且处于适当的位置。

最后,VirtualizingStackPanel是一件复杂的事情,它大部分工作得很好。它还允许垂直和水平虚拟化,这很棒。如果你想编写自己的VirtualizingStackPanel,我建议你停止重新发明轮子。你最终会在代码中做同样的事情,就像微软的人所做的那样,所以当其他人已经开发了VirtualizingStackPanel:)时,为什么要浪费时间

我用RedGate工具反射了VirtualizingStackPanel。看看这个:

    private Size ContainerSizeForItem(ItemsControl itemsControl, object item, int index, out UIElement container)
    {
        Size containerSize;
        container = index >= 0 ? ((ItemContainerGenerator)Generator).ContainerFromIndex(index) as UIElement : null;
        if (container != null)
        {
            containerSize = container.DesiredSize;
        }
        else
        {
            // It's virtualized; grab the height off the item if available.
            object value = itemsControl.ReadItemValue(item, _desiredSizeStorageIndex);
            if (value != null)
            {
                containerSize = (Size)value;
            }
            else
            {
                //
                // No stored container height; simply guess.
                //
                containerSize = new Size();

                if (Orientation == Orientation.Horizontal)
                {
                    containerSize.Width = ContainerStackingSizeEstimate(itemsControl, /*isHorizontal = */ true);
                    containerSize.Height = DesiredSize.Height;
                }
                else
                {
                    containerSize.Height = ContainerStackingSizeEstimate(itemsControl, /*isHorizontal = */ false);
                    containerSize.Width = DesiredSize.Width;
                }
            }
        }
        return containerSize;
    }
    private double ContainerStackingSizeEstimate(IProvideStackingSize estimate, bool isHorizontal)
    {
        double stackingSize = 0d;
        if (estimate != null)
        {
            stackingSize = estimate.EstimatedContainerSize(isHorizontal);
        }
        if (stackingSize <= 0d || DoubleUtil.IsNaN(stackingSize))
        {
            stackingSize = ScrollViewer._scrollLineDelta;
        }
        return stackingSize;
    }

如果你反映ScrollViewer,你会发现这个:

internal const double _scrollLineDelta = 16.0;   // Default physical amount to scroll with one Up/Down

如您所见,当容器不可用时,会猜测大小,这意味着它设置为 16.0 像素,这是 Microsoft 的默认设置。

顺便说一句,像素滚动在 wpf 中从一开始就存在,因为 .Net 3.5 只是看到 TreeView 例如。 :) :)

VirtualizingStackPanel 项不直接基于内容大小,它基于索引处理子项。
堆叠方向的范围完全由子级的数量决定。 VirtualizingStackPanel 不知道孩子的大小是多少,直到它意识到那个孩子。

当视口滚动时,接下来的项目就会实现,这就是为什么您不能在虚拟化中使用平滑滚动的原因(除了 .添加了像素滚动的Net4.5)

有一个关于在 WPF 中创建VirtualizingPanel的很棒的 4 部分博客,我用它来创建一个VirtualizingWrapPanel,它让我对Virtualization的工作原理有了很好的了解

http://blogs.msdn.com/b/dancre/archive/2006/02/06/implementing-a-virtualized-panel-in-wpf-avalon.aspx

相关文章: