protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) { var anchorIndex = context.RecommendedAnchorIndex; SuggestedAnchor = anchorIndex < 0 ? null : context.GetOrCreateElementAt(anchorIndex); return(base.MeasureOverride(context, availableSize)); }
// Figure out the extent of the layout by getting the number of items remaining // above and below the realized elements and getting an estimation based on // average item heights seen so far. private Rect EstimateExtent(VirtualizingLayoutContext context, Size availableSize) { double averageHeight = m_totalHeightForEstimation / m_numItemsUsedForEstimation; Rect extent = new Rect(0, 0, availableSize.Width, context.ItemCount * averageHeight); if (context.ItemCount > 0 && m_realizedElementBounds.Count > 0) { extent.Y = m_firstRealizedDataIndex == 0 ? m_realizedElementBounds[0].Y : m_realizedElementBounds[0].Y - (m_firstRealizedDataIndex - 1) * averageHeight; int lastRealizedIndex = m_firstRealizedDataIndex + m_realizedElementBounds.Count; if (lastRealizedIndex == context.ItemCount - 1) { var lastBounds = m_realizedElementBounds[m_realizedElementBounds.Count - 1]; extent.Y = lastBounds.Bottom; } else { var lastBounds = m_realizedElementBounds[m_realizedElementBounds.Count - 1]; int lastRealizedDataIndex = m_firstRealizedDataIndex + m_realizedElementBounds.Count; int numItemsAfterLastRealizedIndex = context.ItemCount - lastRealizedDataIndex; extent.Height = lastBounds.Bottom + numItemsAfterLastRealizedIndex * averageHeight - extent.Y; } } DebugTrace("Extent " + extent + " with average height " + averageHeight); return(extent); }
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) { var realizationRect = context.RealizationRect; int itemCount = context.ItemCount; int firstRealizedIndex = FirstRealizedIndexInRect(realizationRect, itemCount); int lastRealizedIndex = LastRealizedIndexInRect(realizationRect, itemCount); Debug.WriteLine("Measure:" + realizationRect.ToString()); // Viewport + Buffer Rect. for (int currentIndex = firstRealizedIndex; currentIndex <= lastRealizedIndex; currentIndex++) { var element = context.GetOrCreateElementAt(currentIndex); element.Measure(new Size(ItemWidth, ItemHeight)); } // Anchor var anchorIndex = context.RecommendedAnchorIndex; if (anchorIndex >= 0) { var anchorElement = context.GetOrCreateElementAt(anchorIndex); anchorElement.Measure(new Size(ItemWidth, ItemHeight)); } return(new Size(ItemWidth, context.ItemCount * ItemHeight)); }
// The data collection has changed, since we are maintaining the bounds of elements // in the viewport, we will update the list to account for the collection change. protected override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args) { InvalidateMeasure(); if (m_realizedElementBounds.Count > 0) { switch (args.Action) { case NotifyCollectionChangedAction.Add: OnItemsAdded(args.NewStartingIndex, args.NewItems.Count); break; case NotifyCollectionChangedAction.Replace: OnItemsRemoved(args.OldStartingIndex, args.OldItems.Count); OnItemsAdded(args.NewStartingIndex, args.NewItems.Count); break; case NotifyCollectionChangedAction.Remove: OnItemsRemoved(args.OldStartingIndex, args.OldItems.Count); break; case NotifyCollectionChangedAction.Reset: m_realizedElementBounds.Clear(); m_firstRealizedDataIndex = 0; break; default: throw new NotImplementedException(); } } }
protected override Rect GetExtent( Size availableSize, VirtualizingLayoutContext context, UIElement firstRealized, int firstRealizedItemIndex, Rect firstRealizedLayoutBounds, UIElement lastRealized, int lastRealizedItemIndex, Rect lastRealizedLayoutBounds) { var extent = base.GetExtent( availableSize, context, firstRealized, firstRealizedItemIndex, firstRealizedLayoutBounds, lastRealized, lastRealizedItemIndex, lastRealizedLayoutBounds); return(GetExtentFunc != null?GetExtentFunc( availableSize, context, firstRealized, firstRealizedItemIndex, firstRealizedLayoutBounds, lastRealized, lastRealizedItemIndex, lastRealizedLayoutBounds, extent) : extent); }
protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) { var realizationRect = context.RealizationRect; int itemCount = context.ItemCount; int firstRealizedIndex = FirstRealizedIndexInRect(realizationRect, itemCount); int lastRealizedIndex = LastRealizedIndexInRect(realizationRect, itemCount); Debug.WriteLine("Arrange:" + realizationRect.ToString()); // Viewport + Buffer Rect. for (int currentIndex = firstRealizedIndex; currentIndex <= lastRealizedIndex; currentIndex++) { var element = context.GetOrCreateElementAt(currentIndex); var arrangeRect = new Rect(0, currentIndex * ItemHeight, ItemWidth, ItemHeight); element.Arrange(arrangeRect); Debug.WriteLine(" Arrange:" + currentIndex + " :" + arrangeRect); } // Anchor var anchorIndex = context.RecommendedAnchorIndex; if (anchorIndex >= 0) { var anchor = context.GetOrCreateElementAt(anchorIndex); var arrangeRect = new Rect(0, anchorIndex * ItemHeight, ItemWidth, ItemHeight); anchor.Arrange(arrangeRect); Debug.WriteLine(" Arrange:" + anchorIndex + " :" + arrangeRect); } return(finalSize); }
protected override void UninitializeForContextCore(VirtualizingLayoutContext context) { base.UninitializeForContextCore(context); if (OnDetatchedFunc != null) { OnDetatchedFunc(context); } }
protected override void InitializeForContextCore(VirtualizingLayoutContext context) { base.InitializeForContextCore(context); if (OnAttachedFunc != null) { OnAttachedFunc(context); } }
// Figure out which index to use as the anchor and start laying out around. private int GetStartIndex(VirtualizingLayoutContext context, Size availableSize) { int startDataIndex = -1; var anchorIndex = context.RecommendedAnchorIndex; bool isAnchorValid = anchorIndex != -1; if (isAnchorValid) { if (IsRealized(anchorIndex)) { startDataIndex = anchorIndex; } else { ClearRealizedRange(); startDataIndex = anchorIndex; } } else { // find first realized element that is visible in the viewport. startDataIndex = GetFirstRealizedDataIndexInViewport(context.RealizationRect); if (startDataIndex < 0) { startDataIndex = EstimateIndexForViewport(context.RealizationRect, context.ItemCount); ClearRealizedRange(); } } // We have an anchorIndex, realize and measure it and // figure out its bounds. if (startDataIndex != -1 & context.ItemCount > 0) { if (m_realizedElementBounds.Count == 0) { m_firstRealizedDataIndex = startDataIndex; } var newAnchor = EnsureRealized(startDataIndex); DebugTrace("Measuring start index " + startDataIndex); var desiredSize = MeasureElement(context, startDataIndex, availableSize); var bounds = new Rect( 0, newAnchor ? (m_totalHeightForEstimation / m_numItemsUsedForEstimation) * startDataIndex : GetCachedBoundsForDataIndex(startDataIndex).Y, availableSize.Width, desiredSize.Height); SetCachedBoundsForDataIndex(startDataIndex, bounds); } return(startDataIndex); }
protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) { DebugTrace("ArrangeOverride: Viewport" + context.RealizationRect); for (int realizationIndex = 0; realizationIndex < m_realizedElementBounds.Count; realizationIndex++) { int currentDataIndex = m_firstRealizedDataIndex + realizationIndex; DebugTrace("Arranging " + currentDataIndex); // Arrange the child. If any alignment needs to be done, it // can be done here. var child = context.GetOrCreateElementAt(currentDataIndex); var arrangeBounds = m_realizedElementBounds[realizationIndex]; arrangeBounds.X -= m_lastExtent.X; arrangeBounds.Y -= m_lastExtent.Y; child.Arrange(arrangeBounds); } return(finalSize); }
private Size MeasureElement(VirtualizingLayoutContext context, int index, Size availableSize) { var child = context.GetOrCreateElementAt(index); child.Measure(availableSize); int estimationBufferIndex = index % m_estimationBuffer.Count; bool alreadyMeasured = m_estimationBuffer[estimationBufferIndex] != 0; if (!alreadyMeasured) { m_numItemsUsedForEstimation++; } m_totalHeightForEstimation -= m_estimationBuffer[estimationBufferIndex]; m_totalHeightForEstimation += child.DesiredSize.Height; m_estimationBuffer[estimationBufferIndex] = child.DesiredSize.Height; return(child.DesiredSize); }
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) { var viewport = context.RealizationRect; DebugTrace("MeasureOverride: Viewport " + viewport); // Remove bounds for elements that are now outside the viewport. // Proactive recycling elements means we can reuse it during this measure pass again. RemoveCachedBoundsOutsideViewport(viewport); // Find the index of the element to start laying out from - the anchor int startIndex = GetStartIndex(context, availableSize); // Measure and layout elements starting from the start index, forward and backward. Generate(context, availableSize, startIndex, forward: true); Generate(context, availableSize, startIndex, forward: false); // Estimate the extent size. Note that this can have a non 0 origin. m_lastExtent = EstimateExtent(context, availableSize); context.LayoutOrigin = new Point(m_lastExtent.X, m_lastExtent.Y); return(new Size(m_lastExtent.Width, m_lastExtent.Height)); }
private void Generate(VirtualizingLayoutContext context, Size availableSize, int anchorDataIndex, bool forward) { // Generate forward or backward from anchorIndex until we hit the end of the viewport int step = forward ? 1 : -1; int previousDataIndex = anchorDataIndex; int currentDataIndex = previousDataIndex + step; var viewport = context.RealizationRect; while (IsDataIndexValid(currentDataIndex, context.ItemCount) && ShouldContinueFillingUpSpace(previousDataIndex, forward, viewport)) { EnsureRealized(currentDataIndex); DebugTrace("Measuring " + currentDataIndex); var desiredSize = MeasureElement(context, currentDataIndex, availableSize); var previousBounds = GetCachedBoundsForDataIndex(previousDataIndex); Rect currentBounds = new Rect(0, forward ? previousBounds.Y + previousBounds.Height : previousBounds.Y - desiredSize.Height, availableSize.Width, desiredSize.Height); SetCachedBoundsForDataIndex(currentDataIndex, currentBounds); previousDataIndex = currentDataIndex; currentDataIndex += step; } }
protected override void OnElementMeasured(UIElement element, int index, Size availableSize, Size measureSize, Size desiredSize, Size provisionalArrangeSize, VirtualizingLayoutContext context) { base.OnElementMeasured(element, index, availableSize, measureSize, desiredSize, provisionalArrangeSize, context); if (OnElementMeasuredFunc != null) { OnElementMeasuredFunc(element, index, availableSize, measureSize, desiredSize, provisionalArrangeSize, context); } }
protected override void OnLineArranged(int startIndex, int countInLine, double lineSize, VirtualizingLayoutContext context) { base.OnLineArranged(startIndex, countInLine, lineSize, context); if (OnLineArrangedFunc != null) { OnLineArrangedFunc(startIndex, countInLine, lineSize, context); } }
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) { var extent = base.MeasureOverride(context, availableSize); return(MeasureLayoutFunc != null?MeasureLayoutFunc(availableSize, context, extent) : extent); }
protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) { var extent = base.ArrangeOverride(context, finalSize); return(ArrangeLayoutFunc != null?ArrangeLayoutFunc(finalSize, context, extent) : extent); }
protected override FlowLayoutAnchorInfo GetAnchorForRealizationRect(Size availableSize, VirtualizingLayoutContext context) { var anchorInfo = base.GetAnchorForRealizationRect(availableSize, context); return(GetAnchorForRealizationRectFunc != null?GetAnchorForRealizationRectFunc(availableSize, context, anchorInfo) : anchorInfo); }
protected override FlowLayoutAnchorInfo GetAnchorForTargetElement(int targetIndex, Size availableSize, VirtualizingLayoutContext context) { var anchorInfo = base.GetAnchorForTargetElement(targetIndex, availableSize, context); return(GetAnchorForTargetElementFunc != null?GetAnchorForTargetElementFunc(targetIndex, availableSize, context, anchorInfo) : anchorInfo); }