Browse Source

Correctly sync SelectedItems on collection reset.

When `InternalSelectionModel`  gets a `Reset` event it tries to restore the selection from `WritableSelectedItems`, however this was causing items to be added twice to `WriteableSelectedItems`:

collection is reset
- Selection is cleared
- `InternalSelectionModel` restores selection on reset from `WritableSelectedItems`
- Which changes the selection
- Which adds the selection back to `WritableSelectedItems`, causing the selected item to appear twice in the collection
pull/5788/head
Steven Kirk 5 years ago
parent
commit
5c3218ae18
  1. 50
      src/Avalonia.Controls/Selection/InternalSelectionModel.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;
}
}

Loading…
Cancel
Save