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