private void RecycleItems(ItemLayoutInfo layoutInfo) { foreach (UIElement child in Children.OfType <UIElement>()) { int virtualItemIndex = GetVirtualItemIndex(child); if (virtualItemIndex < layoutInfo.FirstRealizedItemIndex || virtualItemIndex > layoutInfo.LastRealizedItemIndex) { GeneratorPosition generatorPosition = itemsGenerator.GeneratorPositionFromIndex(virtualItemIndex); if (generatorPosition.Index >= 0) { itemsGenerator.Recycle(generatorPosition, 1); } } SetVirtualItemIndex(child, -1); } }
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)); } isInMeasure = true; childLayouts.Clear(); ExtentInfo extentInfo = GetExtentInfo(availableSize); EnsureScrollOffsetIsWithinConstrains(extentInfo); ItemLayoutInfo layoutInfo = GetLayoutInfo(availableSize, ItemHeight, extentInfo); RecycleItems(layoutInfo); // Determine where the first item is in relation to previously realized items GeneratorPosition generatorStartPosition = itemsGenerator.GeneratorPositionFromIndex(layoutInfo.FirstRealizedItemIndex); var visualIndex = 0; double currentX = layoutInfo.FirstRealizedItemLeft; double currentY = layoutInfo.FirstRealizedLineTop; using (itemsGenerator.StartAt(generatorStartPosition, GeneratorDirection.Forward, true)) { for (int 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 (!Equals(Children[visualIndex], child)) { int 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, currentY, ItemWidth, ItemHeight)); if (currentX + ItemWidth * 2 >= availableSize.Width) { // wrap to a new line currentY += ItemHeight; currentX = 0; } else { currentX += ItemWidth; } } } 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); }