Browse Source

Fix for remaining Ghost-Item in VirtualizationStackPanel (#20784)

* Add failing test for #20688

Unit test created from issue description

* Add a failing test for wrong CacheLength handling

All items would be realized which is obviously wrong

* fix test setup used StackPanel instead of expcected

VirtualizingStackPanel

* Make sure the test actually fails

* update comment

* Fix for focusedElement and focusedIndex

* add another unit test

* Fixes for new test cases

* Addressing Review

* Update tests to match new behavior

* only recycle focused element if it is not null

* Address review

* Address copilot review

* add failing test

* fix StartU estimation

* remove unused sample file
release/11.3.13
Tim 3 months ago
committed by Julien Lebosquain
parent
commit
7eb4d9ef19
  1. 27
      src/Avalonia.Controls/VirtualizingStackPanel.cs
  2. 34
      tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs

27
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -858,7 +858,32 @@ namespace Avalonia.Controls
// Estimate the element size.
var estimatedSize = EstimateElementSizeU();
// TODO: Use _startU to work this out.
// If we have a valid StartU, use it to anchor estimates relative to the realized range.
if (_realizedElements is { } realized && !double.IsNaN(realized.StartU))
{
var first = realized.FirstIndex;
var last = realized.LastIndex;
if (index < first)
{
return realized.StartU - ((first - index) * estimatedSize);
}
if (index > last)
{
var sizes = realized.SizeU;
var realizedSpan = 0.0;
for (var i = 0; i < sizes.Count; ++i)
{
var sizeU = sizes[i];
realizedSpan += double.IsNaN(sizeU) ? estimatedSize : sizeU;
}
return realized.StartU + realizedSpan + ((index - last - 1) * estimatedSize);
}
}
return index * estimatedSize;
}

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

@ -1553,6 +1553,40 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new Rect(0, 125, 100, 25), container.Bounds);
}
[Fact]
public void Focused_Container_Is_Positioned_Correctly_When_Scrolled_Past_Items_With_Different_Heights()
{
using var app = App();
var items = Enumerable.Range(0, 20)
.Select(x => new ItemWithHeight(x, x < 10 ? 10 : 50))
.ToList();
var (target, _, _) = CreateTarget(items: items, itemTemplate: CanvasWithHeightTemplate);
var focused = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(5));
focused.Focusable = true;
focused.Focus();
target.ScrollIntoView(15);
Layout(target);
Assert.True(target.FirstRealizedIndex > 5);
var firstIndex = target.FirstRealizedIndex;
var firstRealized = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(firstIndex));
var realized = target.GetRealizedElements()
.Where(x => x is not null)
.Cast<Control>()
.ToList();
var estimatedSize = realized.Average(x => x.DesiredSize.Height);
var expectedTop = firstRealized.Bounds.Top - ((firstIndex - 5) * estimatedSize);
focused = Assert.IsType<ContentPresenter>(target.ContainerFromIndex(5));
Assert.Equal(expectedTop, focused.Bounds.Top, 3);
}
[Theory]
[InlineData(0d,
4, 7,

Loading…
Cancel
Save