Browse Source

Handle null SelectionModel.Source.

pull/3470/head
Steven Kirk 7 years ago
parent
commit
04f8516c32
  1. 20
      src/Avalonia.Controls/SelectionModel.cs
  2. 28
      src/Avalonia.Controls/SelectionModelChangeSet.cs
  3. 7
      src/Avalonia.Controls/SelectionNode.cs
  4. 42
      tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs

20
src/Avalonia.Controls/SelectionModel.cs

@ -36,13 +36,29 @@ namespace Avalonia.Controls
get => _rootNode?.Source; get => _rootNode?.Source;
set set
{ {
using (var operation = new Operation(this)) var wasNull = _rootNode.Source == null;
if (_rootNode.Source != null)
{ {
ClearSelection(resetAnchor: true); using (var operation = new Operation(this))
{
ClearSelection(resetAnchor: true);
}
} }
_rootNode.Source = value; _rootNode.Source = value;
RaisePropertyChanged("Source"); RaisePropertyChanged("Source");
if (wasNull)
{
var e = new SelectionModelSelectionChangedEventArgs(
null,
SelectedIndices,
null,
SelectedItems);
OnSelectionChanged(e);
}
} }
} }

28
src/Avalonia.Controls/SelectionModelChangeSet.cs

@ -16,30 +16,38 @@ namespace Avalonia.Controls
public SelectionModelSelectionChangedEventArgs CreateEventArgs() public SelectionModelSelectionChangedEventArgs CreateEventArgs()
{ {
var deselectedCount = 0; var deselectedIndexCount = 0;
var selectedCount = 0; var selectedIndexCount = 0;
var deselectedItemCount = 0;
var selectedItemCount = 0;
foreach (var change in _changes) foreach (var change in _changes)
{ {
deselectedCount += change.DeselectedCount; deselectedIndexCount += change.DeselectedCount;
selectedCount += change.SelectedCount; selectedIndexCount += change.SelectedCount;
if (change.Items != null)
{
deselectedItemCount += change.DeselectedCount;
selectedItemCount += change.SelectedCount;
}
} }
var deselectedIndices = new SelectedItems<IndexPath, SelectionNodeOperation>( var deselectedIndices = new SelectedItems<IndexPath, SelectionNodeOperation>(
_changes, _changes,
deselectedCount, deselectedIndexCount,
GetDeselectedIndexAt); GetDeselectedIndexAt);
var selectedIndices = new SelectedItems<IndexPath, SelectionNodeOperation>( var selectedIndices = new SelectedItems<IndexPath, SelectionNodeOperation>(
_changes, _changes,
selectedCount, selectedIndexCount,
GetSelectedIndexAt); GetSelectedIndexAt);
var deselectedItems = new SelectedItems<object?, SelectionNodeOperation>( var deselectedItems = new SelectedItems<object?, SelectionNodeOperation>(
_changes, _changes,
deselectedCount, deselectedItemCount,
GetDeselectedItemAt); GetDeselectedItemAt);
var selectedItems = new SelectedItems<object?, SelectionNodeOperation>( var selectedItems = new SelectedItems<object?, SelectionNodeOperation>(
_changes, _changes,
selectedCount, selectedItemCount,
GetSelectedItemAt); GetSelectedItemAt);
return new SelectionModelSelectionChangedEventArgs( return new SelectionModelSelectionChangedEventArgs(
@ -71,7 +79,7 @@ namespace Avalonia.Controls
List<SelectionNodeOperation> infos, List<SelectionNodeOperation> infos,
int index) int index)
{ {
static int GetCount(SelectionNodeOperation info) => info.DeselectedCount; static int GetCount(SelectionNodeOperation info) => info.Items != null ? info.DeselectedCount : 0;
static List<IndexRange>? GetRanges(SelectionNodeOperation info) => info.DeselectedRanges; static List<IndexRange>? GetRanges(SelectionNodeOperation info) => info.DeselectedRanges;
return GetItemAt(infos, index, GetCount, GetRanges); return GetItemAt(infos, index, GetCount, GetRanges);
} }
@ -80,7 +88,7 @@ namespace Avalonia.Controls
List<SelectionNodeOperation> infos, List<SelectionNodeOperation> infos,
int index) int index)
{ {
static int GetCount(SelectionNodeOperation info) => info.SelectedCount; static int GetCount(SelectionNodeOperation info) => info.Items != null ? info.SelectedCount : 0;
static List<IndexRange>? GetRanges(SelectionNodeOperation info) => info.SelectedRanges; static List<IndexRange>? GetRanges(SelectionNodeOperation info) => info.SelectedRanges;
return GetItemAt(infos, index, GetCount, GetRanges); return GetItemAt(infos, index, GetCount, GetRanges);
} }

7
src/Avalonia.Controls/SelectionNode.cs

@ -48,8 +48,11 @@ namespace Avalonia.Controls
{ {
if (_source != value) if (_source != value)
{ {
ClearSelection(); if (_source != null)
UnhookCollectionChangedHandler(); {
ClearSelection();
UnhookCollectionChangedHandler();
}
_source = value; _source = value;

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

@ -1424,6 +1424,48 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(2, raised); Assert.Equal(2, raised);
} }
[Fact]
public void Raises_SelectionChanged_With_No_Source()
{
var target = new SelectionModel();
var raised = 0;
target.SelectionChanged += (s, e) =>
{
Assert.Empty(e.DeselectedIndices);
Assert.Empty(e.DeselectedItems);
Assert.Equal(new[] { new IndexPath(1) }, e.SelectedIndices);
Assert.Empty(e.SelectedItems);
++raised;
};
target.Select(1);
Assert.Equal(new[] { new IndexPath(1) }, target.SelectedIndices);
Assert.Empty(target.SelectedItems);
}
[Fact]
public void Raises_SelectionChanged_With_Items_After_Source_Is_Set()
{
var target = new SelectionModel();
var raised = 0;
target.Select(1);
target.SelectionChanged += (s, e) =>
{
Assert.Empty(e.DeselectedIndices);
Assert.Empty(e.DeselectedItems);
Assert.Equal(new[] { new IndexPath(1) }, e.SelectedIndices);
Assert.Equal(new[] { "bar" }, e.SelectedItems);
++raised;
};
target.Source = new[] { "foo", "bar", "baz" };
Assert.Equal(1, raised);
}
private int GetSubscriberCount(AvaloniaList<object> list) private int GetSubscriberCount(AvaloniaList<object> list)
{ {
return ((INotifyCollectionChangedDebug)list).GetCollectionChangedSubscribers()?.Length ?? 0; return ((INotifyCollectionChangedDebug)list).GetCollectionChangedSubscribers()?.Length ?? 0;

Loading…
Cancel
Save