From eeb2745db577d52d40eaaec64a179d99ea445f68 Mon Sep 17 00:00:00 2001 From: Mike Ward Date: Mon, 21 Dec 2020 10:27:28 -0600 Subject: [PATCH] Fix #5151 same as Microsoft --- src/Avalonia.Layout/ElementManager.cs | 87 +++++++++++++-------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/src/Avalonia.Layout/ElementManager.cs b/src/Avalonia.Layout/ElementManager.cs index 70805ba31c..bf5a45966b 100644 --- a/src/Avalonia.Layout/ElementManager.cs +++ b/src/Avalonia.Layout/ElementManager.cs @@ -129,7 +129,7 @@ namespace Avalonia.Layout { for (int i = 0; i < count; i++) { - // Clear from the edges so that ItemsRepeater can optimize on maintaining + // Clear from the edges so that ItemsRepeater can optimize on maintaining // realized indices without walking through all the children every time. int index = realizedIndex == 0 ? realizedIndex + i : (realizedIndex + count - 1) - i; var elementRef = _realizedElements[index]; @@ -212,7 +212,7 @@ namespace Avalonia.Layout public ILayoutable GetRealizedElement(int dataIndex) { return IsVirtualizingContext ? - GetAt(GetRealizedRangeIndexFromDataIndex(dataIndex)) : + GetAt(GetRealizedRangeIndexFromDataIndex(dataIndex)) : _context.GetOrCreateElementAt( dataIndex, ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle); @@ -252,7 +252,6 @@ namespace Avalonia.Layout (orientation == ScrollOrientation.Vertical ? ScrollOrientation.Horizontal : ScrollOrientation.Vertical) : orientation; - var windowStart = effectiveOrientation == ScrollOrientation.Vertical ? window.Y : window.X; var windowEnd = effectiveOrientation == ScrollOrientation.Vertical ? window.Y + window.Height : window.X + window.Width; var firstElementStart = effectiveOrientation == ScrollOrientation.Vertical ? firstElementBounds.Y : firstElementBounds.X; @@ -273,53 +272,53 @@ namespace Avalonia.Layout switch (args.Action) { case NotifyCollectionChangedAction.Add: - { - OnItemsAdded(args.NewStartingIndex, args.NewItems.Count); - } - break; + { + OnItemsAdded(args.NewStartingIndex, args.NewItems.Count); + } + break; case NotifyCollectionChangedAction.Replace: - { - int oldSize = args.OldItems.Count; - int newSize = args.NewItems.Count; - int oldStartIndex = args.OldStartingIndex; - int newStartIndex = args.NewStartingIndex; - - if (oldSize == newSize && - oldStartIndex == newStartIndex && - IsDataIndexRealized(oldStartIndex) && - IsDataIndexRealized(oldStartIndex + oldSize -1)) { - // Straight up replace of n items within the realization window. - // Removing and adding might causes us to lose the anchor causing us - // to throw away all containers and start from scratch. - // Instead, we can just clear those items and set the element to - // null (sentinel) and let the next measure get new containers for them. - var startRealizedIndex = GetRealizedRangeIndexFromDataIndex(oldStartIndex); - for (int realizedIndex = startRealizedIndex; realizedIndex < startRealizedIndex + oldSize; realizedIndex++) + int oldSize = args.OldItems.Count; + int newSize = args.NewItems.Count; + int oldStartIndex = args.OldStartingIndex; + int newStartIndex = args.NewStartingIndex; + + if (oldSize == newSize && + oldStartIndex == newStartIndex && + IsDataIndexRealized(oldStartIndex) && + IsDataIndexRealized(oldStartIndex + oldSize - 1)) { - var elementRef = _realizedElements[realizedIndex]; - - if (elementRef != null) + // Straight up replace of n items within the realization window. + // Removing and adding might causes us to lose the anchor causing us + // to throw away all containers and start from scratch. + // Instead, we can just clear those items and set the element to + // null (sentinel) and let the next measure get new containers for them. + var startRealizedIndex = GetRealizedRangeIndexFromDataIndex(oldStartIndex); + for (int realizedIndex = startRealizedIndex; realizedIndex < startRealizedIndex + oldSize; realizedIndex++) { - _context.RecycleElement(elementRef); - _realizedElements[realizedIndex] = null; + var elementRef = _realizedElements[realizedIndex]; + + if (elementRef != null) + { + _context.RecycleElement(elementRef); + _realizedElements[realizedIndex] = null; + } } } + else + { + OnItemsRemoved(oldStartIndex, oldSize); + OnItemsAdded(newStartIndex, newSize); + } } - else - { - OnItemsRemoved(oldStartIndex, oldSize); - OnItemsAdded(newStartIndex, newSize); - } - } - break; + break; case NotifyCollectionChangedAction.Remove: - { - OnItemsRemoved(args.OldStartingIndex, args.OldItems.Count); - } - break; + { + OnItemsRemoved(args.OldStartingIndex, args.OldItems.Count); + } + break; case NotifyCollectionChangedAction.Reset: ClearRealizedRange(); @@ -376,7 +375,7 @@ namespace Avalonia.Layout int backCutoffIndex = realizedRangeSize; for (int i = 0; - i _firstRealizedDataIndex && + if (newStartingIndex >= _firstRealizedDataIndex && newStartingIndex <= lastRealizedDataIndex) { // Inserted within the realized range int insertRangeStartIndex = newStartingIndex - _firstRealizedDataIndex; for (int i = 0; i < count; i++) { - // Insert null (sentinel) here instead of an element, that way we dont + // Insert null (sentinel) here instead of an element, that way we dont // end up creating a lot of elements only to be thrown out in the next layout. int insertRangeIndex = insertRangeStartIndex + i; int dataIndex = newStartingIndex + i;