Browse Source

Merge pull request #5788 from AvaloniaUI/fixes/selectionmodel-reset

Correctly sync SelectedItems on collection reset.
pull/5801/head
Steven Kirk 5 years ago
committed by GitHub
parent
commit
7b5cfc04e0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 50
      src/Avalonia.Controls/Selection/InternalSelectionModel.cs
  2. 7
      tests/Avalonia.Controls.UnitTests/Selection/InternalSelectionModelTests.cs

50
src/Avalonia.Controls/Selection/InternalSelectionModel.cs

@ -13,8 +13,9 @@ namespace Avalonia.Controls.Selection
internal class InternalSelectionModel : SelectionModel<object?>
{
private IList? _writableSelectedItems;
private bool _ignoreModelChanges;
private int _ignoreModelChanges;
private bool _ignoreSelectedItemsChanges;
private bool _isResetting;
public InternalSelectionModel()
{
@ -130,17 +131,31 @@ namespace Avalonia.Controls.Selection
try
{
_ignoreModelChanges = true;
++_ignoreModelChanges;
using (BatchUpdate())
{
Clear();
Add(_writableSelectedItems);
for (var i = 0; i < _writableSelectedItems.Count; ++i)
{
var index = IndexOf(Source, _writableSelectedItems[i]);
if (index != -1)
{
Select(index);
}
else
{
_writableSelectedItems.RemoveAt(i);
--i;
}
}
}
}
finally
{
_ignoreModelChanges = false;
--_ignoreModelChanges;
}
}
@ -162,7 +177,7 @@ namespace Avalonia.Controls.Selection
private void OnSelectionChanged(object sender, SelectionModelSelectionChangedEventArgs e)
{
if (_ignoreModelChanges)
if (_ignoreModelChanges > 0)
{
return;
}
@ -191,6 +206,27 @@ namespace Avalonia.Controls.Selection
}
}
private protected override void OnSourceCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Reset)
{
++_ignoreModelChanges;
_isResetting = true;
}
base.OnSourceCollectionChanged(e);
}
protected override void OnSourceCollectionChangeFinished()
{
base.OnSourceCollectionChangeFinished();
if (_isResetting)
{
--_ignoreModelChanges;
}
}
private void OnSourceReset(object sender, EventArgs e) => SyncFromSelectedItems();
private void OnSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
@ -222,7 +258,7 @@ namespace Avalonia.Controls.Selection
{
using var operation = BatchUpdate();
_ignoreModelChanges = true;
++_ignoreModelChanges;
switch (e.Action)
{
@ -244,7 +280,7 @@ namespace Avalonia.Controls.Selection
}
finally
{
_ignoreModelChanges = false;
--_ignoreModelChanges;
}
}

7
tests/Avalonia.Controls.UnitTests/Selection/InternalSelectionModelTests.cs

@ -97,6 +97,7 @@ namespace Avalonia.Controls.UnitTests.Selection
target.WritableSelectedItems.Clear();
Assert.Empty(target.SelectedIndexes);
Assert.Empty(target.WritableSelectedItems);
}
[Fact]
@ -123,6 +124,7 @@ namespace Avalonia.Controls.UnitTests.Selection
target.WritableSelectedItems = null;
Assert.Empty(target.SelectedIndexes);
Assert.Empty(target.WritableSelectedItems);
}
[Fact]
@ -182,6 +184,7 @@ namespace Avalonia.Controls.UnitTests.Selection
target.Source = items;
Assert.Equal(1, target.SelectedIndex);
Assert.Equal(new[] { "bar" }, target.WritableSelectedItems);
}
[Fact]
@ -203,6 +206,7 @@ namespace Avalonia.Controls.UnitTests.Selection
items.Reset(new[] { "baz", "foo", "bar" });
Assert.Equal(2, target.SelectedIndex);
Assert.Equal(new[] { "bar" }, target.WritableSelectedItems);
}
[Fact]
@ -227,6 +231,7 @@ namespace Avalonia.Controls.UnitTests.Selection
Assert.Equal(-1, target.SelectedIndex);
Assert.Equal(null, target.SelectedItem);
Assert.Empty(target.WritableSelectedItems);
Assert.Contains(nameof(target.SelectedIndex), changed);
Assert.Contains(nameof(target.SelectedItem), changed);
@ -246,6 +251,7 @@ namespace Avalonia.Controls.UnitTests.Selection
Assert.Equal("foo", target.SelectedItem);
Assert.Equal(1, target.SelectedIndex);
Assert.Equal(new[] { "foo" }, target.WritableSelectedItems);
}
[Fact]
@ -257,6 +263,7 @@ namespace Avalonia.Controls.UnitTests.Selection
target.Source = new[] { "baz", "foo", "bar" };
Assert.Equal(2, target.SelectedIndex);
Assert.Equal(new[] { "bar" }, target.WritableSelectedItems);
}
private static InternalSelectionModel CreateTarget(

Loading…
Cancel
Save