protected override Size MeasureOverride(Size availableSize) {
if (_itemsControl == null) {
return new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width,
double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height);
}
if (double.IsInfinity(_itemWidth)) {
_itemWidth = ItemWidth;
_itemHeight = ItemHeight;
if (double.IsInfinity(_itemWidth) || double.IsInfinity(_itemHeight)) {
try {
var itemSize = DetectItemSize(new Size(_itemWidth, _itemHeight));
_itemWidth = itemSize.Width;
_itemHeight = itemSize.Height;
} catch (Exception e) {
Logging.Write($"Exception: {e}");
}
}
}
_isInMeasure = true;
_childLayouts.Clear();
var extentInfo = GetExtentInfo(availableSize);
EnsureScrollOffsetIsWithinConstrains(extentInfo);
var layoutInfo = GetLayoutInfo(availableSize, _itemWidth, _itemHeight, extentInfo);
RecycleItems(layoutInfo);
// Determine where the first item is in relation to previously realized items
var generatorStartPosition = _itemsGenerator.GeneratorPositionFromIndex(layoutInfo.FirstRealizedItemIndex);
var visualIndex = 0;
var currentX = layoutInfo.FirstRealizedItemLeft;
var currentY = layoutInfo.FirstRealizedItemTop;
var orientation = Orientation;
double offsetX, offsetY;
switch (HorizontalContentAlignment) {
case HorizontalAlignment.Left:
case HorizontalAlignment.Stretch:
offsetX = 0d;
break;
case HorizontalAlignment.Center:
if (orientation == Orientation.Horizontal) {
offsetX = (availableSize.Width - extentInfo.ItemsPerRow * _itemWidth) / 2d;
} else {
offsetX = Math.Max(availableSize.Width - extentInfo.TotalRows * _itemWidth, 0d) / 2d;
}
break;
case HorizontalAlignment.Right:
if (orientation == Orientation.Horizontal) {
offsetX = availableSize.Width - extentInfo.ItemsPerRow * _itemWidth;
} else {
offsetX = Math.Max(availableSize.Width - extentInfo.TotalRows * _itemWidth, 0d);
}
break;
default:
throw new ArgumentOutOfRangeException();
}
switch (VerticalContentAlignment) {
case VerticalAlignment.Top:
case VerticalAlignment.Stretch:
offsetY = 0d;
break;
case VerticalAlignment.Center:
if (orientation == Orientation.Horizontal) {
offsetY = Math.Max(availableSize.Height - extentInfo.TotalRows * _itemHeight, 0d) / 2d;
} else {
offsetY = (availableSize.Height - extentInfo.ItemsPerRow * _itemHeight) / 2d;
}
break;
case VerticalAlignment.Bottom:
if (orientation == Orientation.Horizontal) {
offsetY = Math.Max(availableSize.Height - extentInfo.TotalRows * _itemHeight, 0d);
} else {
offsetY = availableSize.Height - extentInfo.ItemsPerRow * _itemHeight;
}
break;
default:
throw new ArgumentOutOfRangeException();
}
using (_itemsGenerator.StartAt(generatorStartPosition, GeneratorDirection.Forward, true)) {
for (var itemIndex = layoutInfo.FirstRealizedItemIndex; itemIndex <= layoutInfo.LastRealizedItemIndex; itemIndex++, visualIndex++) {
bool newlyRealized;
var child = (UIElement)_itemsGenerator.GenerateNext(out newlyRealized);
SetVirtualItemIndex(child, itemIndex);
if (newlyRealized) {
InsertInternalChild(visualIndex, child);
} else {
// check if item needs to be moved into a new position in the Children collection
if (visualIndex < Children.Count) {
if (!ReferenceEquals(Children[visualIndex], child)) {
var childCurrentIndex = Children.IndexOf(child);
if (childCurrentIndex >= 0) {
RemoveInternalChildRange(childCurrentIndex, 1);
}
InsertInternalChild(visualIndex, child);
}
} else {
// we know that the child can't already be in the children collection
// because we've been inserting children in correct visualIndex order,
// and this child has a visualIndex greater than the Children.Count
AddInternalChild(child);
}
}
// only prepare the item once it has been added to the visual tree
_itemsGenerator.PrepareItemContainer(child);
child.Measure(new Size(_itemWidth, _itemHeight));
_childLayouts.Add(child, new Rect(currentX + offsetX, currentY + offsetY, _itemWidth, _itemHeight));
if (orientation == Orientation.Horizontal) {
if (currentX + _itemWidth * 2 >= availableSize.Width) {
// wrap to a new line
currentY += _itemHeight;
currentX = 0;
} else {
currentX += _itemWidth;
}
} else {
if (currentY + _itemHeight * 2 >= availableSize.Height) {
// wrap to a new column
currentX += _itemWidth;
currentY = 0;
} else {
currentY += _itemHeight;
}
}
}
}
RemoveRedundantChildren();
UpdateScrollInfo(availableSize, extentInfo);
var desiredSize = new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width, double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height);
_isInMeasure = false;
return desiredSize;
}