Browse Source

Recycle elements early when viewport is disjunct.

pull/10892/head
Steven Kirk 4 years ago
parent
commit
9f95bd9156
  1. 11
      src/Avalonia.Controls/VirtualizingStackPanel.cs
  2. 31
      tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs

11
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -166,6 +166,10 @@ namespace Avalonia.Controls
// - Vertical layouts: U = vertical, V = horizontal // - Vertical layouts: U = vertical, V = horizontal
var viewport = CalculateMeasureViewport(items); var viewport = CalculateMeasureViewport(items);
// If the viewport is disjunct then we can recycle everything.
if (viewport.viewportIsDisjunct)
_realizedElements.RecycleAllElements(_recycleElement);
// Do the measure, creating/recycling elements as necessary to fill the viewport. Don't // Do the measure, creating/recycling elements as necessary to fill the viewport. Don't
// write to _realizedElements yet, only _measureElements. // write to _realizedElements yet, only _measureElements.
RealizeElements(items, availableSize, ref viewport); RealizeElements(items, availableSize, ref viewport);
@ -409,6 +413,7 @@ namespace Avalonia.Controls
var viewportStart = Orientation == Orientation.Horizontal ? viewport.X : viewport.Y; var viewportStart = Orientation == Orientation.Horizontal ? viewport.X : viewport.Y;
var viewportEnd = Orientation == Orientation.Horizontal ? viewport.Right : viewport.Bottom; var viewportEnd = Orientation == Orientation.Horizontal ? viewport.Right : viewport.Bottom;
// Get or estimate the anchor element from which to start realization.
var itemCount = items?.Count ?? 0; var itemCount = items?.Count ?? 0;
var (anchorIndex, anchorU) = _realizedElements.GetOrEstimateAnchorElementForViewport( var (anchorIndex, anchorU) = _realizedElements.GetOrEstimateAnchorElementForViewport(
viewportStart, viewportStart,
@ -416,12 +421,17 @@ namespace Avalonia.Controls
itemCount, itemCount,
ref _lastEstimatedElementSizeU); ref _lastEstimatedElementSizeU);
// Check if the anchor element is not within the currently realized elements.
var disjunct = anchorIndex < _realizedElements.FirstIndex ||
anchorIndex > _realizedElements.LastIndex;
return new MeasureViewport return new MeasureViewport
{ {
anchorIndex = anchorIndex, anchorIndex = anchorIndex,
anchorU = anchorU, anchorU = anchorU,
viewportUStart = viewportStart, viewportUStart = viewportStart,
viewportUEnd = viewportEnd, viewportUEnd = viewportEnd,
viewportIsDisjunct = disjunct,
}; };
} }
@ -895,6 +905,7 @@ namespace Avalonia.Controls
public double measuredV; public double measuredV;
public double realizedEndU; public double realizedEndU;
public int lastIndex; public int lastIndex;
public bool viewportIsDisjunct;
} }
} }
} }

31
tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs

@ -83,7 +83,7 @@ namespace Avalonia.Controls.UnitTests
} }
[Fact] [Fact]
public void Scrolls_To_Index() public void Scrolls_Down_To_Index()
{ {
using var app = App(); using var app = App();
var (target, scroll, itemsControl) = CreateTarget(); var (target, scroll, itemsControl) = CreateTarget();
@ -93,6 +93,35 @@ namespace Avalonia.Controls.UnitTests
AssertRealizedItems(target, itemsControl, 11, 10); AssertRealizedItems(target, itemsControl, 11, 10);
} }
[Fact]
public void Scrolls_Up_To_Index()
{
using var app = App();
var (target, scroll, itemsControl) = CreateTarget();
scroll.ScrollToEnd();
Layout(target);
Assert.Equal(90, target.FirstRealizedIndex);
target.ScrollIntoView(20);
AssertRealizedItems(target, itemsControl, 20, 10);
}
[Fact]
public void Scrolling_Up_To_Index_Does_Not_Create_A_Page_Of_Unrealized_Elements()
{
using var app = App();
var (target, scroll, itemsControl) = CreateTarget();
scroll.ScrollToEnd();
Layout(target);
target.ScrollIntoView(20);
Assert.Equal(11, target.Children.Count);
}
[Fact] [Fact]
public void Creates_Elements_On_Item_Insert_1() public void Creates_Elements_On_Item_Insert_1()
{ {

Loading…
Cancel
Save