diff --git a/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs b/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs index f1dd874c71..55c43f6f96 100644 --- a/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; +using Avalonia.Collections; using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; using Avalonia.Data; @@ -278,6 +279,82 @@ namespace Avalonia.Controls.UnitTests Assert.Same(focused, target.GetRealizedElements().First()); } + [Fact] + public void Removing_Range_When_Scrolled_To_End_Updates_Viewport() + { + using var app = App(); + var items = new AvaloniaList(Enumerable.Range(0, 100).Select(x => $"Item {x}")); + var (target, scroll, itemsControl) = CreateTarget(items: items); + + scroll.Offset = new Vector(0, 900); + Layout(target); + + AssertRealizedItems(target, itemsControl, 90, 10); + + items.RemoveRange(0, 80); + Layout(target); + + AssertRealizedItems(target, itemsControl, 10, 10); + Assert.Equal(new Vector(0, 100), scroll.Offset); + } + + [Fact] + public void Removing_Range_To_Have_Less_Than_A_Page_Of_Items_When_Scrolled_To_End_Updates_Viewport() + { + using var app = App(); + var items = new AvaloniaList(Enumerable.Range(0, 100).Select(x => $"Item {x}")); + var (target, scroll, itemsControl) = CreateTarget(items: items); + + scroll.Offset = new Vector(0, 900); + Layout(target); + + AssertRealizedItems(target, itemsControl, 90, 10); + + items.RemoveRange(0, 95); + Layout(target); + + AssertRealizedItems(target, itemsControl, 0, 5); + Assert.Equal(new Vector(0, 0), scroll.Offset); + } + + [Fact] + public void Resetting_Collection_To_Have_Less_Items_When_Scrolled_To_End_Updates_Viewport() + { + using var app = App(); + var items = new ResettingCollection(Enumerable.Range(0, 100).Select(x => $"Item {x}")); + var (target, scroll, itemsControl) = CreateTarget(items: items); + + scroll.Offset = new Vector(0, 900); + Layout(target); + + AssertRealizedItems(target, itemsControl, 90, 10); + + items.Reset(Enumerable.Range(0, 20).Select(x => $"Item {x}")); + Layout(target); + + AssertRealizedItems(target, itemsControl, 10, 10); + Assert.Equal(new Vector(0, 100), scroll.Offset); + } + + [Fact] + public void Resetting_Collection_To_Have_Less_Than_A_Page_Of_Items_When_Scrolled_To_End_Updates_Viewport() + { + using var app = App(); + var items = new ResettingCollection(Enumerable.Range(0, 100).Select(x => $"Item {x}")); + var (target, scroll, itemsControl) = CreateTarget(items: items); + + scroll.Offset = new Vector(0, 900); + Layout(target); + + AssertRealizedItems(target, itemsControl, 90, 10); + + items.Reset(Enumerable.Range(0, 5).Select(x => $"Item {x}")); + Layout(target); + + AssertRealizedItems(target, itemsControl, 0, 5); + Assert.Equal(new Vector(0, 0), scroll.Offset); + } + private static IReadOnlyList GetRealizedIndexes(VirtualizingStackPanel target, ItemsControl itemsControl) { return target.GetRealizedElements() @@ -378,5 +455,24 @@ namespace Avalonia.Controls.UnitTests } private static IDisposable App() => UnitTestApplication.Start(TestServices.RealFocus); + + private class ResettingCollection : List, INotifyCollectionChanged + { + public ResettingCollection(IEnumerable items) + { + AddRange(items); + } + + public void Reset(IEnumerable items) + { + Clear(); + AddRange(items); + CollectionChanged?.Invoke( + this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + + public event NotifyCollectionChangedEventHandler? CollectionChanged; + } } }