Browse Source

Implemented SelectionMode.AlwaysSelected.

pull/4533/head
Steven Kirk 6 years ago
parent
commit
1120820b7e
  1. 27
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  2. 29
      src/Avalonia.Controls/Selection/SelectionModel.cs
  3. 4
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs
  4. 32
      tests/Avalonia.Controls.UnitTests/Selection/SelectionModelTests_Multiple.cs
  5. 32
      tests/Avalonia.Controls.UnitTests/Selection/SelectionModelTests_Single.cs

27
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -634,6 +634,20 @@ namespace Avalonia.Controls.Primitives
}
}
/// <summary>
/// Called when <see cref="ISelectionModel.LostSelection"/> event is raised on
/// <see cref="Selection"/>.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private void OnSelectionModelLostSelection(object sender, EventArgs e)
{
if (AlwaysSelected)
{
SelectedIndex = 0;
}
}
/// <summary>
/// Called when a container raises the <see cref="IsSelectedChangedEvent"/>.
/// </summary>
@ -764,6 +778,7 @@ namespace Avalonia.Controls.Primitives
model.PropertyChanged += OnSelectionModelPropertyChanged;
model.SelectionChanged += OnSelectionModelSelectionChanged;
model.LostSelection += OnSelectionModelLostSelection;
if (model.SingleSelect)
{
@ -777,14 +792,10 @@ namespace Avalonia.Controls.Primitives
_oldSelectedIndex = model.SelectedIndex;
_oldSelectedItem = model.SelectedItem;
//if (model.AutoSelect)
//{
// SelectionMode |= SelectionMode.AlwaysSelected;
//}
//else
//{
// SelectionMode &= ~SelectionMode.AlwaysSelected;
//}
if (AlwaysSelected && model.Count == 0)
{
model.SelectedIndex = 0;
}
//if (Items is INotifyCollectionChanged incc)
//{

29
src/Avalonia.Controls/Selection/SelectionModel.cs

@ -320,12 +320,18 @@ namespace Avalonia.Controls.Selection
private protected override void OnSelectionChanged(IReadOnlyList<T> deselectedItems)
{
if (SelectionChanged is object || _untypedSelectionChanged is object)
// Note: We're *not* putting this in a using scope. A collection update is still in progress
// so the operation won't get commited by normal means: we have to commit it manually.
var update = BatchUpdate();
update.Operation.DeselectedItems = deselectedItems;
if (_selectedIndex == -1 && LostSelection is object)
{
var e = new SelectionModelSelectionChangedEventArgs<T>(deselectedItems: deselectedItems);
SelectionChanged?.Invoke(this, e);
_untypedSelectionChanged?.Invoke(this, e);
LostSelection(this, EventArgs.Empty);
}
CommitOperation(update.Operation);
}
private protected override CollectionChangeState OnItemsAdded(int index, IList items)
@ -613,13 +619,23 @@ namespace Avalonia.Controls.Selection
}
}
if (deselected?.Count > 0 || selected?.Count > 0)
if (deselected?.Count > 0 || selected?.Count > 0 || operation.DeselectedItems is object)
{
// If the operation was caused by Source being updated, then use a null source
// so that the items will appear as nulls.
var deselectedSource = operation.IsSourceUpdate ? null : ItemsView;
// If the operation contains DeselectedItems then we're notifying a source
// CollectionChanged event. LostFocus may have caused another item to have been
// selected, but it can't have caused a deselection (as it was called due to
// selection being lost) so we're ok to discard `deselected` here.
var deselectedItems = operation.DeselectedItems ??
SelectedItems<T>.Create(deselected, deselectedSource);
var e = new SelectionModelSelectionChangedEventArgs<T>(
SelectedIndexes<T>.Create(deselected),
SelectedIndexes<T>.Create(selected),
SelectedItems<T>.Create(deselected, deselectedSource),
deselectedItems,
SelectedItems<T>.Create(selected, ItemsView));
SelectionChanged?.Invoke(this, e);
_untypedSelectionChanged?.Invoke(this, e);
@ -689,6 +705,7 @@ namespace Avalonia.Controls.Selection
public int SelectedIndex { get; set; }
public List<IndexRange>? SelectedRanges { get; set; }
public List<IndexRange>? DeselectedRanges { get; set; }
public IReadOnlyList<T> DeselectedItems { get; set; }
}
}
}

4
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs

@ -75,8 +75,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
target.SelectedIndex = 2;
items.RemoveAt(2);
Assert.Equal(2, target.SelectedIndex);
Assert.Equal("qux", target.SelectedItem);
Assert.Equal(0, target.SelectedIndex);
Assert.Equal("foo", target.SelectedItem);
}
[Fact]

32
tests/Avalonia.Controls.UnitTests/Selection/SelectionModelTests_Multiple.cs

@ -1394,7 +1394,7 @@ namespace Avalonia.Controls.UnitTests.Selection
public class LostSelection
{
[Fact]
public void Can_Select_First_Item_On_LostSelection()
public void LostSelection_Called_On_Clear()
{
var target = CreateTarget();
var raised = 0;
@ -1417,6 +1417,36 @@ namespace Avalonia.Controls.UnitTests.Selection
target.Clear();
Assert.Equal(0, target.SelectedIndex);
Assert.Equal(1, raised);
}
[Fact]
public void LostSelection_Called_When_Selection_Removed()
{
var target = CreateTarget();
var data = (AvaloniaList<string>)target.Source!;
var raised = 0;
target.SelectRange(1, 3);
target.SelectionChanged += (s, e) =>
{
Assert.Empty(e.DeselectedIndexes);
Assert.Equal(new[] { "bar", "baz", "qux" }, e.DeselectedItems);
Assert.Equal(new[] { 0 }, e.SelectedIndexes);
Assert.Equal(new[] { "quux" }, e.SelectedItems);
++raised;
};
target.LostSelection += (s, e) =>
{
target.Select(0);
};
data.RemoveRange(0, 4);
Assert.Equal(0, target.SelectedIndex);
Assert.Equal(1, raised);
}
}

32
tests/Avalonia.Controls.UnitTests/Selection/SelectionModelTests_Single.cs

@ -1066,7 +1066,7 @@ namespace Avalonia.Controls.UnitTests.Selection
public class LostSelection
{
[Fact]
public void Can_Select_First_Item_On_LostSelection()
public void LostSelection_Called_On_Clear()
{
var target = CreateTarget();
var raised = 0;
@ -1089,6 +1089,36 @@ namespace Avalonia.Controls.UnitTests.Selection
target.Clear();
Assert.Equal(0, target.SelectedIndex);
Assert.Equal(1, raised);
}
[Fact]
public void LostSelection_Called_When_SelectedItem_Removed()
{
var target = CreateTarget();
var data = (AvaloniaList<string>)target.Source!;
var raised = 0;
target.SelectedIndex = 1;
target.SelectionChanged += (s, e) =>
{
Assert.Empty(e.DeselectedIndexes);
Assert.Equal(new[] { "bar" }, e.DeselectedItems);
Assert.Equal(new[] { 0 }, e.SelectedIndexes);
Assert.Equal(new[] { "foo" }, e.SelectedItems);
++raised;
};
target.LostSelection += (s, e) =>
{
target.Select(0);
};
data.RemoveAt(1);
Assert.Equal(0, target.SelectedIndex);
Assert.Equal(1, raised);
}
}

Loading…
Cancel
Save