Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 233
James Joshua Street Avatar asked Oct 15 '13 23:10

James Joshua Street


1 Answers

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. :) :)

like image 121
dev hedgehog Avatar answered Oct 05 '22 11:10

dev hedgehog