From 039fb905ad6b18ab939e5863b00f4ebed9939d4d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 13 Dec 2022 13:04:32 +0100 Subject: [PATCH] Handle item move and replace. --- .../VirtualizingStackPanel.cs | 5 ++ .../VirtualizingStackPanelTests.cs | 58 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/Avalonia.Controls/VirtualizingStackPanel.cs b/src/Avalonia.Controls/VirtualizingStackPanel.cs index dba45b1505..6dec8c6327 100644 --- a/src/Avalonia.Controls/VirtualizingStackPanel.cs +++ b/src/Avalonia.Controls/VirtualizingStackPanel.cs @@ -161,6 +161,11 @@ namespace Avalonia.Controls case NotifyCollectionChangedAction.Remove: _realizedElements.ItemsRemoved(e.OldStartingIndex, e.OldItems!.Count, _updateElementIndex, _recycleElementOnItemRemoved); break; + case NotifyCollectionChangedAction.Replace: + case NotifyCollectionChangedAction.Move: + _realizedElements.ItemsRemoved(e.OldStartingIndex, e.OldItems!.Count, _updateElementIndex, _recycleElementOnItemRemoved); + _realizedElements.ItemsInserted(e.NewStartingIndex, e.NewItems!.Count, _updateElementIndex); + break; case NotifyCollectionChangedAction.Reset: _realizedElements.RecycleAllElements(_recycleElementOnItemRemoved); break; diff --git a/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs b/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs index 10cb5f8c6b..c20d4fa41a 100644 --- a/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs @@ -141,6 +141,64 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(elements, target.GetRealizedElements()); } + [Fact] + public void Updates_Elements_On_Item_Replace() + { + using var app = App(); + var (target, _, itemsControl) = CreateTarget(); + var items = (ObservableCollection)itemsControl.Items!; + + Assert.Equal(10, target.GetRealizedElements().Count); + + var toReplace = target.GetRealizedElements().ElementAt(2); + items[2] = "new"; + + // Container being replaced should have been recycled. + Assert.DoesNotContain(toReplace, target.GetRealizedElements()); + Assert.False(toReplace!.IsVisible); + + var indexes = GetRealizedIndexes(target, itemsControl); + + // Item removed from realized elements at old position and space inserted at new position. + Assert.Equal(new[] { 0, 1, -1, 3, 4, 5, 6, 7, 8, 9 }, indexes); + + Layout(target); + + indexes = GetRealizedIndexes(target, itemsControl); + + // After layout the missing container should have been created. + Assert.Equal(Enumerable.Range(0, 10), indexes); + } + + [Fact] + public void Updates_Elements_On_Item_Move() + { + using var app = App(); + var (target, _, itemsControl) = CreateTarget(); + var items = (ObservableCollection)itemsControl.Items!; + + Assert.Equal(10, target.GetRealizedElements().Count); + + var toMove = target.GetRealizedElements().ElementAt(2); + items.Move(2, 6); + + // Container being moved should have been recycled. + Assert.DoesNotContain(toMove, target.GetRealizedElements()); + Assert.False(toMove!.IsVisible); + + var indexes = GetRealizedIndexes(target, itemsControl); + + // Item removed from realized elements at old position and space inserted at new position. + Assert.Equal(new[] { 0, 1, 2, 3, 4, 5, -1, 7, 8, 9 }, indexes); + + Layout(target); + + indexes = GetRealizedIndexes(target, itemsControl); + + // After layout the missing container should have been created. + Assert.Equal(Enumerable.Range(0, 10), indexes); + } + [Fact] public void Removes_Control_Items_From_Panel_On_Item_Remove() {