private Size MeasureVertical()

in tools/Explorer/TabControl/TabPanel.cs [300:420]


        private Size MeasureVertical(Size availableSize)
        {
            int childCount = InternalChildren.Count;
            double maxChildWidthOrHeight = 0d;

            EnsureChildRects();

            double extentHeight = 0d;
            double[] heights = new double[childCount];

            // we will first measure all the children with unlimited space to get their desired sizes
            // this will also get us the height required for all TabItems
            for (int i = 0; i < childCount; i++)
            {
                if (!(InternalChildren[i] is TabItem tabItem)) 
                    return new Size();

                SetDimensions(tabItem);

                tabItem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

                ClearDimensions(tabItem);

                // calculate the maximum child width
                maxChildWidthOrHeight = Math.Max(maxChildWidthOrHeight, Math.Ceiling(tabItem.DesiredSize.Width));

                // calculate the child width while respecting the Maximum & Minimum width constraints
                heights[i] = Math.Min(MaximumChildHeight, Math.Max(MinimumChildHeight, Math.Ceiling(tabItem.DesiredSize.Height)));

                // determines how much horizontal space we require
                extentHeight += heights[i];
            }
            maxChildWidthOrHeight = Math.Max(MinimumChildWidth, Math.Min(MaximumChildWidth, maxChildWidthOrHeight));  // observe the constraints
            _extent = new Size(maxChildWidthOrHeight, extentHeight);

            bool flag = false;
            // 1). all the children fit into the available space using there desired widths
            if (extentHeight <= availableSize.Height)
            {
                _maxVisibleItems = childCount;
                FirstVisibleIndex = 0;

                double top = 0;
                for (int i = 0; i < childCount; i++)
                {
                    _childRects[i] = new Rect(0, top, maxChildWidthOrHeight, heights[i]);
                    top += heights[i];

                    if (InternalChildren[i] is FrameworkElement child) 
                        child.Measure(new Size(maxChildWidthOrHeight, heights[i]));
                }

                CanScrollLeftOrUp = false;
                CanScrollRightOrDown = false;

                flag = true;
            }

            // 2). all the children fit in the available space if we reduce their widths to a uniform value 
            // while staying within the MinimumChildWidth and MaximumChildWidth constraints
            if (!flag)
            {
                // make sure the width is not greater than the MaximumChildWidth constraints
                double targetHeight = Math.Min(MaximumChildHeight, availableSize.Height / childCount);

                // target width applies now if whether we can fit all items in the available space or whether we are scrolling
                if (targetHeight >= MinimumChildHeight)
                {
                    _maxVisibleItems = childCount;
                    FirstVisibleIndex = 0;

                    extentHeight = 0;
                    double top = 0;

                    for (int i = 0; i < childCount; i++)
                    {
                        extentHeight += targetHeight;
                        heights[i] = targetHeight;
                        _childRects[i] = new Rect(0, top, maxChildWidthOrHeight, heights[i]);
                        top += heights[i];

                        if (InternalChildren[i] is FrameworkElement child) 
                            child.Measure(new Size(maxChildWidthOrHeight, heights[i]));
                    }
                    _extent = new Size(maxChildWidthOrHeight, extentHeight);

                    flag = true;

                    CanScrollLeftOrUp = false;
                    CanScrollRightOrDown = false;
                }
            }

            // 3) we can not fit all the children in the viewport, so now we will enable scrolling/virtualizing items
            if (!flag)
            {
                _maxVisibleItems = (int)Math.Floor(_viewPort.Height / MinimumChildHeight);          // calculate how many visible children we can show at once
                double targetHeight = availableSize.Height / _maxVisibleItems;                      // calculate the new target width
                FirstVisibleIndex = _firstVisibleIndex;

                extentHeight = 0;
                double top = 0;
                for (int i = 0; i < childCount; i++)
                {
                    extentHeight += targetHeight;
                    heights[i] = targetHeight;
                    _childRects[i] = new Rect(0, top, maxChildWidthOrHeight, heights[i]);
                    top += heights[i];

                    if (InternalChildren[i] is FrameworkElement child) 
                        child.Measure(new Size(maxChildWidthOrHeight, heights[i]));
                }
                _extent = new Size(maxChildWidthOrHeight, extentHeight);

                CanScrollLeftOrUp = LastVisibleIndex < childCount - 1;
                CanScrollRightOrDown = FirstVisibleIndex > 0;
            }

            return new Size(maxChildWidthOrHeight, double.IsInfinity(availableSize.Height) ? _extent.Height : availableSize.Height);

        }