|
|
@@ -276,8 +276,38 @@ namespace Avalonia.Layout
|
|
|
|
|
|
case NotifyCollectionChangedAction.Replace:
|
|
|
{
|
|
|
- OnItemsRemoved(args.OldStartingIndex, args.OldItems.Count);
|
|
|
- OnItemsAdded(args.NewStartingIndex, args.NewItems.Count);
|
|
|
+ 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++)
|
|
|
+ {
|
|
|
+ var elementRef = _realizedElements[realizedIndex];
|
|
|
+
|
|
|
+ if (elementRef != null)
|
|
|
+ {
|
|
|
+ _context.RecycleElement(elementRef);
|
|
|
+ _realizedElements[realizedIndex] = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ OnItemsRemoved(oldStartIndex, oldSize);
|
|
|
+ OnItemsAdded(newStartIndex, newSize);
|
|
|
+ }
|
|
|
}
|
|
|
break;
|
|
|
|