diff --git a/src/Avalonia.Controls/SelectionModel.cs b/src/Avalonia.Controls/SelectionModel.cs index 303fc8766e..c7687d72fd 100644 --- a/src/Avalonia.Controls/SelectionModel.cs +++ b/src/Avalonia.Controls/SelectionModel.cs @@ -344,6 +344,7 @@ namespace Avalonia.Controls public void Dispose() { ClearSelection(resetAnchor: false); + _rootNode.Cleanup(); _rootNode.Dispose(); _selectedIndicesCached = null; _selectedItemsCached = null; @@ -796,6 +797,7 @@ namespace Avalonia.Controls } OnSelectionChanged(e); + _rootNode.Cleanup(); } private void ApplyAutoSelect() diff --git a/src/Avalonia.Controls/SelectionNode.cs b/src/Avalonia.Controls/SelectionNode.cs index 4b4a12a7e6..3d560d30c8 100644 --- a/src/Avalonia.Controls/SelectionNode.cs +++ b/src/Avalonia.Controls/SelectionNode.cs @@ -375,6 +375,19 @@ namespace Avalonia.Controls } } + public void Cleanup() + { + foreach (var child in _childrenNodes) + { + child?.Cleanup(); + + if (child?.SelectedCount == 0) + { + child.Dispose(); + } + } + } + public bool Select(int index, bool select) { return Select(index, select, raiseOnSelectionChanged: true); @@ -503,16 +516,6 @@ namespace Avalonia.Controls _selectedItems?.Clear(); SelectedCount = 0; AnchorIndex = -1; - - // This will throw away all the children SelectionNodes - // causing them to be unhooked from their data source. This - // essentially cleans up the tree. - foreach (var child in _childrenNodes) - { - child?.Dispose(); - } - - _childrenNodes.Clear(); } private bool Select(int index, bool select, bool raiseOnSelectionChanged) diff --git a/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs b/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs index c56ee64409..777bd5496e 100644 --- a/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs @@ -1185,6 +1185,29 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(1, raised); } + [Fact] + public void Clearing_Nested_Selection_Raises_SelectionChanged() + { + var target = new SelectionModel(); + var raised = 0; + + target.Source = CreateNestedData(1, 2, 3); + target.Select(1, 1); + + target.SelectionChanged += (s, e) => + { + Assert.Equal(new[] { new IndexPath(1, 1) }, e.DeselectedIndices); + Assert.Equal(new object[] { 4 }, e.DeselectedItems); + Assert.Empty(e.SelectedIndices); + Assert.Empty(e.SelectedItems); + ++raised; + }; + + target.ClearSelection(); + + Assert.Equal(1, raised); + } + [Fact] public void Changing_Source_Raises_SelectionChanged() {