diff --git a/src/Avalonia.Controls/SelectionModel.cs b/src/Avalonia.Controls/SelectionModel.cs index a40e0a62f4..314c36d28d 100644 --- a/src/Avalonia.Controls/SelectionModel.cs +++ b/src/Avalonia.Controls/SelectionModel.cs @@ -46,14 +46,25 @@ namespace Avalonia.Controls if (_rootNode.Source != null) { - using (var operation = new Operation(this)) + // Temporarily prevent auto-select when switching source. + var restoreAutoSelect = _autoSelect; + _autoSelect = false; + + try + { + using (var operation = new Operation(this)) + { + ClearSelection(resetAnchor: true); + } + } + finally { - ClearSelection(resetAnchor: true); + _autoSelect = restoreAutoSelect; } } _rootNode.Source = value; - ApplyAutoSelect(); + ApplyAutoSelect(true); RaisePropertyChanged("Source"); @@ -111,7 +122,7 @@ namespace Avalonia.Controls if (_autoSelect != value) { _autoSelect = value; - ApplyAutoSelect(); + ApplyAutoSelect(true); } } } @@ -185,7 +196,6 @@ namespace Avalonia.Controls using var operation = new Operation(this); ClearSelection(resetAnchor: true); SelectWithPathImpl(value, select: true); - ApplyAutoSelect(); } } } @@ -381,21 +391,18 @@ namespace Avalonia.Controls { using var operation = new Operation(this); SelectImpl(index, select: false); - ApplyAutoSelect(); } public void Deselect(int groupIndex, int itemIndex) { using var operation = new Operation(this); SelectWithGroupImpl(groupIndex, itemIndex, select: false); - ApplyAutoSelect(); } public void DeselectAt(IndexPath index) { using var operation = new Operation(this); SelectWithPathImpl(index, select: false); - ApplyAutoSelect(); } public bool IsSelected(int index) => _rootNode.IsSelected(index); @@ -562,7 +569,6 @@ namespace Avalonia.Controls { using var operation = new Operation(this); ClearSelection(resetAnchor: true); - ApplyAutoSelect(); } public IDisposable Update() => new Operation(this); @@ -589,7 +595,7 @@ namespace Avalonia.Controls } OnSelectionChanged(e); - ApplyAutoSelect(); + ApplyAutoSelect(true); } internal IObservable? ResolvePath(object data, IndexPath dataIndexPath) @@ -816,6 +822,8 @@ namespace Avalonia.Controls if (--_operationCount == 0) { + ApplyAutoSelect(false); + var changes = new List(); _rootNode.EndOperation(changes); @@ -837,7 +845,7 @@ namespace Avalonia.Controls } } - private void ApplyAutoSelect() + private void ApplyAutoSelect(bool createOperation) { if (AutoSelect) { @@ -845,8 +853,15 @@ namespace Avalonia.Controls if (SelectedIndex == default && _rootNode.ItemsSourceView?.Count > 0) { - using var operation = new Operation(this); - SelectImpl(0, true); + if (createOperation) + { + using var operation = new Operation(this); + SelectImpl(0, true); + } + else + { + SelectImpl(0, true); + } } } } diff --git a/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs b/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs index 59552e7f93..24e82a69d0 100644 --- a/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs @@ -1754,6 +1754,30 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(0, raised); } + [Fact] + public void AutoSelect_Is_Applied_At_End_Of_Batch_Update() + { + var data = new[] { "foo", "bar", "baz" }; + var target = new SelectionModel { AutoSelect = true, Source = data }; + + using (target.Update()) + { + target.ClearSelection(); + + Assert.Equal(new IndexPath(), target.SelectedIndex); + Assert.Empty(target.SelectedIndices); + Assert.Null(target.SelectedItem); + Assert.Empty(target.SelectedItems); + } + + Assert.Equal(new IndexPath(0), target.SelectedIndex); + Assert.Equal(new[] { new IndexPath(0) }, target.SelectedIndices); + Assert.Equal("foo", target.SelectedItem); + Assert.Equal(new[] { "foo" }, target.SelectedItems); + + Assert.Equal(new IndexPath(0), target.SelectedIndex); + } + [Fact] public void Can_Replace_Parent_Children_Collection() {