in tools/Explorer/TabControl/TabPanel.cs [171:291]
private Size MeasureHorizontal(Size availableSize)
{
double maxChildWidthOrHeight = 0d;
int childCount = InternalChildren.Count;
EnsureChildRects();
double extentWidth = 0d;
double[] widths = new double[childCount]; // stores the widths of the items for use in the arrange pass
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 height
maxChildWidthOrHeight = Math.Max(maxChildWidthOrHeight, Math.Ceiling(tabItem.DesiredSize.Height));
// calculate the child width while respecting the Maximum & Minimum width constraints
widths[i] = Math.Min(MaximumChildWidth, Math.Max(MinimumChildWidth, Math.Ceiling(tabItem.DesiredSize.Width)));
// determines how much horizontal space we require
extentWidth += widths[i];
}
maxChildWidthOrHeight = Math.Max(MinimumChildHeight, Math.Min(MaximumChildHeight, maxChildWidthOrHeight)); // observe the constraints
_extent = new Size(extentWidth, maxChildWidthOrHeight);
bool flag = false;
// 1). all the children fit into the available space using there desired widths
if (extentWidth <= availableSize.Width)
{
_maxVisibleItems = childCount;
FirstVisibleIndex = 0;
double left = 0;
for (int i = 0; i < childCount; i++)
{
_childRects[i] = new Rect(left, 0, widths[i], maxChildWidthOrHeight);
left += widths[i];
if (InternalChildren[i] is FrameworkElement child)
child.Measure(new Size(widths[i], maxChildWidthOrHeight));
}
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 targetWidth = Math.Min(MaximumChildWidth, availableSize.Width / childCount);
// target width applies now if whether we can fit all items in the available space or whether we are scrolling
if (targetWidth >= MinimumChildWidth)
{
_maxVisibleItems = childCount;
FirstVisibleIndex = 0;
extentWidth = 0;
double left = 0;
for (int i = 0; i < childCount; i++)
{
extentWidth += targetWidth;
widths[i] = targetWidth;
_childRects[i] = new Rect(left, 0, widths[i], maxChildWidthOrHeight);
left += widths[i];
if (InternalChildren[i] is FrameworkElement child)
child.Measure(new Size(widths[i], maxChildWidthOrHeight));
}
_extent = new Size(extentWidth, maxChildWidthOrHeight);
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.Width / MinimumChildWidth); // calculate how many visible children we can show at once
if (_maxVisibleItems == 0)
_maxVisibleItems = 1;
double targetWidth = availableSize.Width / _maxVisibleItems; // calculate the new target width
FirstVisibleIndex = _firstVisibleIndex;
extentWidth = 0;
double left = 0;
for (int i = 0; i < childCount; i++)
{
extentWidth += targetWidth;
widths[i] = targetWidth;
_childRects[i] = new Rect(left, 0, widths[i], maxChildWidthOrHeight);
left += widths[i];
if (InternalChildren[i] is FrameworkElement child)
child.Measure(new Size(widths[i], maxChildWidthOrHeight));
}
_extent = new Size(extentWidth, maxChildWidthOrHeight);
CanScrollLeftOrUp = LastVisibleIndex < childCount - 1;
CanScrollRightOrDown = FirstVisibleIndex > 0;
}
return new Size(double.IsInfinity(availableSize.Width) ? _extent.Width : availableSize.Width, maxChildWidthOrHeight);
}