From 9ef91f9e10640bd683d49255777b51a432c4b31c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 12 May 2020 17:59:11 +0200 Subject: [PATCH] Fix notifications when removing parent item. --- src/Avalonia.Controls/SelectionNode.cs | 112 ++++++------------ .../SelectionModelTests.cs | 13 ++ 2 files changed, 52 insertions(+), 73 deletions(-) diff --git a/src/Avalonia.Controls/SelectionNode.cs b/src/Avalonia.Controls/SelectionNode.cs index 2fa7c5f697..0b00db88c3 100644 --- a/src/Avalonia.Controls/SelectionNode.cs +++ b/src/Avalonia.Controls/SelectionNode.cs @@ -731,101 +731,67 @@ namespace Avalonia.Controls var selectionInvalidated = false; var removed = new List(); var count = items.Count; - - // Remove the items from the selection for leaf - if (ItemsSourceView!.Count > 0) - { - bool isSelected = false; + var isSelected = false; - for (int i = 0; i <= count - 1; i++) + for (int i = 0; i <= count - 1; i++) + { + if (IsSelected(index + i)) { - if (IsSelected(index + i)) - { - isSelected = true; - removed.Add(items[i]); - } + isSelected = true; + removed.Add(items[i]); } + } - if (isSelected) - { - var removeRange = new IndexRange(index, index + count - 1); - SelectedCount -= IndexRange.Remove(_selected, removeRange); - selectionInvalidated = true; - - if (_selectedItems != null) - { - foreach (var i in items) - { - _selectedItems.Remove(i); - } - } - } + if (isSelected) + { + var removeRange = new IndexRange(index, index + count - 1); + SelectedCount -= IndexRange.Remove(_selected, removeRange); + selectionInvalidated = true; - for (int i = 0; i < _selected.Count; i++) + if (_selectedItems != null) { - var range = _selected[i]; - - // The range is after the removed items, need to shift the range left - if (range.End > index) + foreach (var i in items) { - // Shift the range to the left - _selected[i] = new IndexRange(range.Begin - count, range.End - count); - selectionInvalidated = true; + _selectedItems.Remove(i); } } + } - // Update for non-leaf if we are tracking non-leaf nodes - if (_childrenNodes.Count > 0) - { - selectionInvalidated = true; - for (int i = 0; i < count; i++) - { - if (_childrenNodes[index] != null) - { - removed.AddRange(_childrenNodes[index]!.SelectedItems); - RealizedChildrenNodeCount--; - _childrenNodes[index]!.Dispose(); - } - _childrenNodes.RemoveAt(index); - } - } + for (int i = 0; i < _selected.Count; i++) + { + var range = _selected[i]; - //Adjust the anchor - if (AnchorIndex >= index) + // The range is after the removed items, need to shift the range left + if (range.End > index) { - AnchorIndex -= count; + // Shift the range to the left + _selected[i] = new IndexRange(range.Begin - count, range.End - count); + selectionInvalidated = true; } } - else - { - // No more items in the list, clear - ClearSelection(); - RealizedChildrenNodeCount = 0; - selectionInvalidated = true; - } - // Check if removing a node invalidated an ancestors - // selection state. For example if parent was partially selected before - // removing an item, it could be selected now. - if (!selectionInvalidated) + // Update for non-leaf if we are tracking non-leaf nodes + if (_childrenNodes.Count > 0) { - var parent = _parent; - - while (parent != null) + selectionInvalidated = true; + for (int i = 0; i < count; i++) { - var isSelected = parent.IsSelectedWithPartial(); - // If a parent is partially selected, then it will become selected. - // If it is selected or not selected - there is no change. - if (!isSelected.HasValue) + if (_childrenNodes[index] != null) { - selectionInvalidated = true; - break; + removed.AddRange(_childrenNodes[index]!.SelectedItems); + RealizedChildrenNodeCount--; + _childrenNodes[index]!.Dispose(); } - - parent = parent._parent; + _childrenNodes.RemoveAt(index); } } + //Adjust the anchor + if (AnchorIndex >= index) + { + AnchorIndex -= count; + } + return (selectionInvalidated, removed); } diff --git a/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs b/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs index cea41526ad..246ff723a1 100644 --- a/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs @@ -390,8 +390,21 @@ namespace Avalonia.Controls.UnitTests ValidateSelection(selectionModel, Path(0, 1), Path(0, 2)); _output.WriteLine("Remove group containing selected items"); + + var raised = 0; + + selectionModel.SelectionChanged += (s, e) => + { + Assert.Empty(e.DeselectedIndices); + Assert.Equal(new object[] { 4, 5, }, e.DeselectedItems); + Assert.Empty(e.SelectedIndices); + Assert.Empty(e.SelectedItems); + ++raised; + }; + data.RemoveAt(0); ValidateSelection(selectionModel); + Assert.Equal(1, raised); } [Fact]