Browse Source

Fix selection in combination with move.

pull/9677/head
Steven Kirk 3 years ago
parent
commit
17f7541fdd
  1. 7
      src/Avalonia.Controls/Presenters/PanelContainerGenerator.cs
  2. 1
      src/Avalonia.Controls/Selection/SelectionModel.cs
  3. 1
      src/Avalonia.Controls/Selection/SelectionNodeBase.cs
  4. 72
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
  5. 50
      tests/Avalonia.Controls.UnitTests/Selection/SelectionModelTests_Multiple.cs
  6. 46
      tests/Avalonia.Controls.UnitTests/Selection/SelectionModelTests_Single.cs

7
src/Avalonia.Controls/Presenters/PanelContainerGenerator.cs

@ -81,9 +81,11 @@ namespace Avalonia.Controls.Presenters
{
for (var i = 0; i < count; ++i)
{
var c = children[i];
var c = children[index + i];
if (!c.IsSet(ItemIsOwnContainerProperty))
itemsControl.RemoveLogicalChild(children[i + index]);
else
generator.ClearItemContainer(c);
}
children.RemoveRange(index, count);
@ -103,9 +105,6 @@ namespace Avalonia.Controls.Presenters
Remove(e.OldStartingIndex, e.OldItems!.Count);
break;
case NotifyCollectionChangedAction.Replace:
Remove(e.OldStartingIndex, e.OldItems!.Count);
Add(e.NewStartingIndex, e.NewItems!);
break;
case NotifyCollectionChangedAction.Move:
Remove(e.OldStartingIndex, e.OldItems!.Count);
Add(e.NewStartingIndex, e.NewItems!);

1
src/Avalonia.Controls/Selection/SelectionModel.cs

@ -439,6 +439,7 @@ namespace Avalonia.Controls.Selection
if ((e.Action == NotifyCollectionChangedAction.Remove && e.OldStartingIndex <= oldSelectedIndex) ||
(e.Action == NotifyCollectionChangedAction.Replace && e.OldStartingIndex == oldSelectedIndex) ||
(e.Action == NotifyCollectionChangedAction.Move && e.OldStartingIndex == oldSelectedIndex) ||
e.Action == NotifyCollectionChangedAction.Reset)
{
RaisePropertyChanged(nameof(SelectedItem));

1
src/Avalonia.Controls/Selection/SelectionNodeBase.cs

@ -256,6 +256,7 @@ namespace Avalonia.Controls.Selection
break;
}
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Move:
{
var removeChange = OnItemsRemoved(e.OldStartingIndex, e.OldItems!);
var addChange = OnItemsAdded(e.NewStartingIndex, e.NewItems!);

72
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@ -637,6 +637,78 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.False(items.Single().IsSelected);
}
[Fact]
public void Replacing_Selected_Item_Should_Clear_Selection()
{
var items = new AvaloniaList<Item>
{
new Item(),
new Item(),
};
var target = new SelectingItemsControl
{
Items = items,
Template = Template(),
};
Prepare(target);
target.SelectedIndex = 1;
Assert.Equal(items[1], target.SelectedItem);
Assert.Equal(1, target.SelectedIndex);
SelectionChangedEventArgs receivedArgs = null;
target.SelectionChanged += (_, args) => receivedArgs = args;
var removed = items[1];
items[1] = new Item();
Assert.Null(target.SelectedItem);
Assert.Equal(-1, target.SelectedIndex);
Assert.NotNull(receivedArgs);
Assert.Empty(receivedArgs.AddedItems);
Assert.Equal(new[] { removed }, receivedArgs.RemovedItems);
Assert.All(items, x => Assert.False(x.IsSelected));
}
[Fact]
public void Moving_Selected_Item_Should_Clear_Selection()
{
var items = new AvaloniaList<Item>
{
new Item(),
new Item(),
};
var target = new SelectingItemsControl
{
Items = items,
Template = Template(),
};
Prepare(target);
target.SelectedIndex = 1;
Assert.Equal(items[1], target.SelectedItem);
Assert.Equal(1, target.SelectedIndex);
SelectionChangedEventArgs receivedArgs = null;
target.SelectionChanged += (_, args) => receivedArgs = args;
var removed = items[1];
items.Move(1, 0);
Assert.Null(target.SelectedItem);
Assert.Equal(-1, target.SelectedIndex);
Assert.NotNull(receivedArgs);
Assert.Empty(receivedArgs.AddedItems);
Assert.Equal(new[] { removed }, receivedArgs.RemovedItems);
Assert.All(items, x => Assert.False(x.IsSelected));
}
[Fact]
public void Resetting_Items_Collection_Should_Clear_Selection()
{

50
tests/Avalonia.Controls.UnitTests/Selection/SelectionModelTests_Multiple.cs

@ -1259,6 +1259,56 @@ namespace Avalonia.Controls.UnitTests.Selection
Assert.Equal(0, indexesChangedRaised);
}
[Fact]
public void Moving_Selected_Item_Updates_State()
{
var target = CreateTarget();
var data = (AvaloniaList<string>)target.Source!;
var selectionChangedRaised = 0;
var selectedIndexRaised = 0;
var selectedItemRaised = 0;
var indexesChangedRaised = 0;
target.Source = data;
target.SelectRange(1, 4);
target.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(target.SelectedIndex))
{
++selectedIndexRaised;
}
if (e.PropertyName == nameof(target.SelectedItem))
{
++selectedItemRaised;
}
};
target.IndexesChanged += (s, e) => ++indexesChangedRaised;
target.SelectionChanged += (s, e) =>
{
Assert.Empty(e.DeselectedIndexes);
Assert.Equal(new[] { "bar" }, e.DeselectedItems);
Assert.Empty(e.SelectedIndexes);
Assert.Empty(e.SelectedItems);
++selectionChangedRaised;
};
data.Move(1, 0);
Assert.Equal(2, target.SelectedIndex);
Assert.Equal(new[] { 2, 3, 4 }, target.SelectedIndexes);
Assert.Equal("baz", target.SelectedItem);
Assert.Equal(new[] { "baz", "qux", "quux" }, target.SelectedItems);
Assert.Equal(2, target.AnchorIndex);
Assert.Equal(1, selectionChangedRaised);
Assert.Equal(1, selectedIndexRaised);
Assert.Equal(1, selectedItemRaised);
Assert.Equal(0, indexesChangedRaised);
}
[Fact]
public void Resetting_Source_Updates_State()
{

46
tests/Avalonia.Controls.UnitTests/Selection/SelectionModelTests_Single.cs

@ -1079,6 +1079,52 @@ namespace Avalonia.Controls.UnitTests.Selection
Assert.Equal(1, selectedItemRaised);
}
[Fact]
public void Moving_Selected_Item_Updates_State()
{
var target = CreateTarget();
var data = (AvaloniaList<string>)target.Source!;
var selectionChangedRaised = 0;
var selectedIndexRaised = 0;
var selectedItemRaised = 0;
target.Source = data;
target.Select(1);
target.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(target.SelectedIndex))
{
++selectedIndexRaised;
}
if (e.PropertyName == nameof(target.SelectedItem))
{
++selectedItemRaised;
}
};
target.SelectionChanged += (s, e) =>
{
Assert.Empty(e.DeselectedIndexes);
Assert.Equal(new[] { "bar" }, e.DeselectedItems);
Assert.Empty(e.SelectedIndexes);
Assert.Empty(e.SelectedItems);
++selectionChangedRaised;
};
data.Move(1, 0);
Assert.Equal(-1, target.SelectedIndex);
Assert.Empty(target.SelectedIndexes);
Assert.Null(target.SelectedItem);
Assert.Empty(target.SelectedItems);
Assert.Equal(-1, target.AnchorIndex);
Assert.Equal(1, selectionChangedRaised);
Assert.Equal(1, selectedIndexRaised);
Assert.Equal(1, selectedItemRaised);
}
[Fact]
public void Resetting_Source_Updates_State()
{

Loading…
Cancel
Save