From b630f21b7e8c940f51fa341d575027041b92bd96 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 28 Nov 2023 22:40:37 +0100 Subject: [PATCH] Fix overlapping items in `VirtualizingStackPanel` (#13765) * Added failing test for #12744. * Inserting items makes the StartU unstable. This ports the fix in https://github.com/AvaloniaUI/Avalonia.Controls.TreeDataGrid/pull/229 to Avalonia. Fixes #12744 --- .../Utils/RealizedStackElements.cs | 1 + .../VirtualizingStackPanelTests.cs | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Avalonia.Controls/Utils/RealizedStackElements.cs b/src/Avalonia.Controls/Utils/RealizedStackElements.cs index 11bbaa11c4..18cba5b123 100644 --- a/src/Avalonia.Controls/Utils/RealizedStackElements.cs +++ b/src/Avalonia.Controls/Utils/RealizedStackElements.cs @@ -294,6 +294,7 @@ namespace Avalonia.Controls.Utils { // The insertion point was before the first element, update the first index. _firstIndex += count; + _startUUnstable = true; } else { diff --git a/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs b/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs index 4cbf8d2142..d0e139bedf 100644 --- a/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs @@ -843,6 +843,28 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(1, panel.VisualChildren.Count); } + [Fact] + public void Inserting_Item_Before_Viewport_Preserves_FirstRealizedIndex() + { + // Issue #12744 + using var app = App(); + var (target, scroll, itemsControl) = CreateTarget(); + var items = (IList)itemsControl.ItemsSource!; + + // Scroll down 20 items. + scroll.Offset = new Vector(0, 200); + target.UpdateLayout(); + Assert.Equal(20, target.FirstRealizedIndex); + + // Insert an item at the beginning. + items.Insert(0, "New Item"); + target.UpdateLayout(); + + // The first realized index should still be 20 as the scroll should be unchanged. + Assert.Equal(20, target.FirstRealizedIndex); + Assert.Equal(new(0, 200), scroll.Offset); + } + private static IReadOnlyList GetRealizedIndexes(VirtualizingStackPanel target, ItemsControl itemsControl) { return target.GetRealizedElements()