Browse Source

Fix notifications when removing parent item.

pull/3923/head
Steven Kirk 6 years ago
parent
commit
9ef91f9e10
  1. 112
      src/Avalonia.Controls/SelectionNode.cs
  2. 13
      tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs

112
src/Avalonia.Controls/SelectionNode.cs

@ -731,101 +731,67 @@ namespace Avalonia.Controls
var selectionInvalidated = false;
var removed = new List<object?>();
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);
}

13
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]

Loading…
Cancel
Save