Browse Source

Merge pull request #5817 from AvaloniaUI/fixes/selecteditems-binding

Don't update SelectedItems when setting items source.
pull/5407/head
Steven Kirk 5 years ago
committed by GitHub
parent
commit
222860cde2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      src/Avalonia.Controls/Selection/InternalSelectionModel.cs
  2. 28
      tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

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

@ -80,10 +80,12 @@ namespace Avalonia.Controls.Selection
try
{
_ignoreSelectedItemsChanges = true;
++_ignoreModelChanges;
base.SetSource(value);
}
finally
{
--_ignoreModelChanges;
_ignoreSelectedItemsChanges = false;
}
@ -93,17 +95,14 @@ namespace Avalonia.Controls.Selection
}
else
{
foreach (var i in oldSelection)
{
var index = ItemsView!.IndexOf(i);
Select(index);
}
SyncFromSelectedItems();
}
}
private void SyncToSelectedItems()
{
if (_writableSelectedItems is object)
if (_writableSelectedItems is object &&
!SequenceEqual(_writableSelectedItems, base.SelectedItems))
{
try
{
@ -224,6 +223,7 @@ namespace Avalonia.Controls.Selection
if (_isResetting)
{
--_ignoreModelChanges;
_isResetting = false;
}
}
@ -310,5 +310,27 @@ namespace Avalonia.Controls.Selection
return -1;
}
private static bool SequenceEqual(IList first, IReadOnlyList<object?> second)
{
if (first is IEnumerable<object?> e)
{
return e.SequenceEqual(second);
}
var comparer = EqualityComparer<object?>.Default;
var e1 = first.GetEnumerator();
using var e2 = second.GetEnumerator();
while (e1.MoveNext())
{
if (!(e2.MoveNext() && comparer.Equals(e1.Current, e2.Current)))
{
return false;
}
}
return !e2.MoveNext();
}
}
}

28
tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

@ -1,3 +1,4 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Subjects;
using Avalonia.Collections;
@ -457,6 +458,33 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact]
public void Initial_Binding_Of_SelectedItems_Should_Not_Cause_Write_To_SelectedItems()
{
var target = new ListBox
{
[!ListBox.ItemsProperty] = new Binding("Items"),
[!ListBox.SelectedItemsProperty] = new Binding("SelectedItems"),
};
var viewModel = new
{
Items = new[] { "Foo", "Bar", "Baz " },
SelectedItems = new ObservableCollection<string> { "Bar" },
};
var raised = 0;
viewModel.SelectedItems.CollectionChanged += (s, e) => ++raised;
target.DataContext = viewModel;
Assert.Equal(0, raised);
Assert.Equal(new[] { "Bar" }, viewModel.SelectedItems);
Assert.Equal(new[] { "Bar" }, target.SelectedItems);
Assert.Equal(new[] { "Bar" }, target.Selection.SelectedItems);
}
private FuncControlTemplate ListBoxTemplate()
{
return new FuncControlTemplate<ListBox>((parent, scope) =>

Loading…
Cancel
Save