Browse Source

Raise SelectionChanged when nested children change.

pull/3923/head
Steven Kirk 6 years ago
parent
commit
d5f0110ca6
  1. 22
      src/Avalonia.Controls/SelectionNode.cs
  2. 148
      tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs

22
src/Avalonia.Controls/SelectionNode.cs

@ -8,6 +8,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using Avalonia.Controls.Utils;
#nullable enable
@ -214,7 +215,21 @@ namespace Avalonia.Controls
public void SetChildrenObservable(IObservable<object?> resolver)
{
_childrenSubscription = resolver.Subscribe(x => Source = x);
_childrenSubscription = resolver.Subscribe(x =>
{
if (Source != null)
{
using (_manager.Update())
{
SelectionTreeHelper.Traverse(
this,
realizeChildren: false,
info => info.Node.Clear());
}
}
Source = x;
});
}
public int SelectedCount { get; private set; }
@ -544,11 +559,14 @@ namespace Avalonia.Controls
private void ClearChildNodes()
{
foreach (var child in _childrenNodes)
for (int i = 0; i < _childrenNodes.Count; i++)
{
var child = _childrenNodes[i];
if (child != null && child != _manager.SharedLeafNode)
{
child.Dispose();
_childrenNodes[i] = null;
}
}

148
tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs

@ -1929,19 +1929,61 @@ namespace Avalonia.Controls.UnitTests
}
[Fact]
public void Can_Replace_Children_Collection()
public void Can_Replace_Parent_Children_Collection()
{
var root = new Node("Root");
var target = new SelectionModel { Source = new[] { root } };
var raised = 0;
target.ChildrenRequested += (s, e) => e.Children = ((Node)e.Source).WhenAnyValue(x => x.Children);
target.Select(0, 9);
Assert.Equal("Child 9", ((Node)target.SelectedItem).Header);
var selected = (Node)target.SelectedItem;
Assert.Equal("Child 9", selected.Header);
target.SelectionChanged += (s, e) =>
{
Assert.Equal(new[] { Path(0, 9) }, e.DeselectedIndices);
Assert.Equal(new[] { selected }, e.DeselectedItems);
Assert.Empty(e.SelectedIndices);
Assert.Empty(e.SelectedItems);
++raised;
};
root.ReplaceChildren();
Assert.Null(target.SelectedItem);
Assert.Equal(1, raised);
}
[Fact]
public void Can_Replace_Grandparent_Children_Collection()
{
var root = new Node("Root");
var target = new SelectionModel { Source = new[] { root } };
var raised = 0;
target.ChildrenRequested += (s, e) => e.Children = ((Node)e.Source).WhenAnyValue(x => x.Children);
target.SelectAt(Path(0, 9, 1));
var selected = (Node)target.SelectedItem;
Assert.Equal("Child 1", selected.Header);
target.SelectionChanged += (s, e) =>
{
Assert.Equal(new[] { Path(0, 9, 1) }, e.DeselectedIndices);
Assert.Equal(new[] { selected }, e.DeselectedItems);
Assert.Empty(e.SelectedIndices);
Assert.Empty(e.SelectedItems);
++raised;
};
root.ReplaceChildren();
Assert.Null(target.SelectedItem);
Assert.Equal(1, raised);
}
[Fact]
@ -1979,57 +2021,6 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(0, node.PropertyChangedSubscriptions);
}
private class Node : INotifyPropertyChanged
{
private ObservableCollection<Node> _children;
private PropertyChangedEventHandler _propertyChanged;
public Node(string header)
{
Header = header;
}
public string Header { get; }
public ObservableCollection<Node> Children
{
get => _children ??= CreateChildren(10);
private set
{
_children = value;
_propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Children)));
}
}
public event PropertyChangedEventHandler PropertyChanged
{
add
{
_propertyChanged += value;
++PropertyChangedSubscriptions;
}
remove
{
_propertyChanged -= value;
--PropertyChangedSubscriptions;
}
}
public int PropertyChangedSubscriptions { get; private set; }
public void ReplaceChildren()
{
Children = CreateChildren(5);
}
private ObservableCollection<Node> CreateChildren(int count)
{
return new ObservableCollection<Node>(
Enumerable.Range(0, count).Select(x => new Node("Child " + x)));
}
}
private int GetSubscriberCount(AvaloniaList<object> list)
{
return ((INotifyCollectionChangedDebug)list).GetCollectionChangedSubscribers()?.Length ?? 0;
@ -2396,6 +2387,57 @@ namespace Avalonia.Controls.UnitTests
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
private class Node : INotifyPropertyChanged
{
private ObservableCollection<Node> _children;
private PropertyChangedEventHandler _propertyChanged;
public Node(string header)
{
Header = header;
}
public string Header { get; }
public ObservableCollection<Node> Children
{
get => _children ??= CreateChildren(10);
private set
{
_children = value;
_propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Children)));
}
}
public event PropertyChangedEventHandler PropertyChanged
{
add
{
_propertyChanged += value;
++PropertyChangedSubscriptions;
}
remove
{
_propertyChanged -= value;
--PropertyChangedSubscriptions;
}
}
public int PropertyChangedSubscriptions { get; private set; }
public void ReplaceChildren()
{
Children = CreateChildren(5);
}
private ObservableCollection<Node> CreateChildren(int count)
{
return new ObservableCollection<Node>(
Enumerable.Range(0, count).Select(x => new Node("Child " + x)));
}
}
}
class CustomSelectionModel : SelectionModel

Loading…
Cancel
Save