how does virtualizingstackpanel calculate child size without instantiating the actual item?

StackOverflow https://stackoverflow.com/questions/19393103

  •  30-06-2022
  •  | 
  •  

Question

I am following the tutorials presented here:

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

and in their implementation they have a dependency property on the virtualizingtilepanel that keeps track of the child size. However, the WPF library's virtualizingstackpanel doesn't require me to set a size for the child elements as a property. However, I don't understand how the virtualizing stack panel can calculate which items in the panel are visible without instancing the items.

I would think that they would need a measure pass to know the item containers sizes, but how can they know that without first instantiating the items?

My goal is to create a panel to contain treeviewitems and virtualize them, but following the example from virtualizingtilepanel only lets me virtualize the top level items.

I need to change the way it calculates what items are visible, but I don't see how it can know what items are visible without knowing the size and actually instantiating the items.

edit: wait, maybe it instantiates the objects that go inside the treeviewitem immediately and use those to calculate the size?

Was it helpful?

Solution

VirtualizingStackPanel has two modes. One is called ScrollToContent and in such mode the VirtualizingStackPanel uses indexes of items. As example visible are 10 items and you have an amount of 1000 items therefore the ScrollBar will be displayed small.

The second mode is called ScrollToPixels and in this mode the VirtualizingStackPanel manages a list of which items are virtualized and which are realized. If an item is not realized yet the VirtualizingStackPanel uses its MinHeight value which if none set by user 16 pixels for microsoft. As example visible are 10 items and each item has height of 20 pixels. That would be 200 pixels for viewport height but you have a total amout of 1000 items so the extent will be then 200 + (1000 - 10 ) * 16 = 16040 pixels. The ScrollBar will also appear small and in proper propotion.

In the end VirtualizingStackPanel is a complex thing and it works great mostly. It also allows virtualization vertically and horizontally which is awesome. If you wish to write your own VirtualizingStackPanel I would suggest you to stop reinventing the wheel. You will end up doing the same in code as microsoft guys did so why waisting time when somebody else already developed the VirtualizingStackPanel :)

I reflectored VirtualizingStackPanel with RedGate tool. Take a look at this:

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

If you reflect ScrollViewer you will find this:

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

As you can see the size is guessed when container not avaiable which means its set to 16.0 pixel which is default for microsoft.

Btw pixel scrolling was there in wpf since begin also since .Net 3.5 just see TreeView for example. :) :)

OTHER TIPS

VirtualizingStackPanel items are not directly based on content size, It handles children based on index.
The extent in the stacking direction is determined purely by the number of children. VirtualizingStackPanel has no idea what the size of a child is until it realizes that child.

As the viewport scrolls the next items are realized, this is why you cant use smooth scrolling with Virtualization (except for .Net4.5 where pixel scrolling was added)

There is a great 4 part blog on creating a VirtualizingPanel in WPF, I used this to create a VirtualizingWrapPanel and it gave me a great understanding on how Virtualization works

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top