|
|
@@ -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<realizedRangeSize &&
|
|
|
+ i < realizedRangeSize &&
|
|
|
!Intersects(window, _realizedElementLayoutBounds[i], orientation);
|
|
|
++i)
|
|
|
{
|
|
|
@@ -391,7 +390,7 @@ namespace Avalonia.Layout
|
|
|
--backCutoffIndex;
|
|
|
}
|
|
|
|
|
|
- if (backCutoffIndex<realizedRangeSize - 1)
|
|
|
+ if (backCutoffIndex < realizedRangeSize - 1)
|
|
|
{
|
|
|
ClearRealizedRange(backCutoffIndex + 1, realizedRangeSize - backCutoffIndex - 1);
|
|
|
}
|
|
|
@@ -419,14 +418,14 @@ namespace Avalonia.Layout
|
|
|
// to insert items.
|
|
|
int lastRealizedDataIndex = _firstRealizedDataIndex + GetRealizedElementCount() - 1;
|
|
|
int newStartingIndex = index;
|
|
|
- if (newStartingIndex > _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;
|