Browse Source

Merge pull request #2689 from AvaloniaUI/fixes/2565-listbox-initial-selection

Fix ListBox initial selection
pull/2762/head
Steven Kirk 7 years ago
committed by GitHub
parent
commit
55dbe58f5c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      src/Avalonia.Controls/ListBox.cs
  2. 38
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  3. 75
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs

8
src/Avalonia.Controls/ListBox.cs

@ -68,7 +68,13 @@ namespace Avalonia.Controls
/// <inheritdoc/>
public new IList SelectedItems => base.SelectedItems;
/// <inheritdoc/>
/// <summary>
/// Gets or sets the selection mode.
/// </summary>
/// <remarks>
/// Note that the selection mode only applies to selections made via user interaction.
/// Multiple selections can be made programatically regardless of the value of this property.
/// </remarks>
public new SelectionMode SelectionMode
{
get { return base.SelectionMode; }

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

@ -222,6 +222,10 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// Gets or sets the selection mode.
/// </summary>
/// <remarks>
/// Note that the selection mode only applies to selections made via user interaction.
/// Multiple selections can be made programatically regardless of the value of this property.
/// </remarks>
protected SelectionMode SelectionMode
{
get { return GetValue(SelectionModeProperty); }
@ -338,24 +342,36 @@ namespace Avalonia.Controls.Primitives
{
base.OnContainersMaterialized(e);
var selectedIndex = SelectedIndex;
var selectedContainer = e.Containers
.FirstOrDefault(x => (x.ContainerControl as ISelectable)?.IsSelected == true);
var resetSelectedItems = false;
if (selectedContainer != null)
foreach (var container in e.Containers)
{
SelectedIndex = selectedContainer.Index;
}
else if (selectedIndex >= e.StartingIndex &&
selectedIndex < e.StartingIndex + e.Containers.Count)
{
var container = e.Containers[selectedIndex - e.StartingIndex];
if ((container.ContainerControl as ISelectable)?.IsSelected == true)
{
if (SelectedIndex == -1)
{
SelectedIndex = container.Index;
}
else
{
if (_selection.Add(container.Index))
{
resetSelectedItems = true;
}
}
if (container.ContainerControl != null)
MarkContainerSelected(container.ContainerControl, true);
}
else if (_selection.Contains(container.Index))
{
MarkContainerSelected(container.ContainerControl, true);
}
}
if (resetSelectedItems)
{
ResetSelectedItems();
}
}
/// <inheritdoc/>

75
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs

@ -53,7 +53,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
}
[Fact]
public void Assigning_SelectedItems_Should_Set_SelectedIndex()
public void Assigning_Single_SelectedItems_Should_Set_SelectedIndex()
{
var target = new TestSelector
{
@ -62,9 +62,51 @@ namespace Avalonia.Controls.UnitTests.Primitives
};
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
target.SelectedItems = new AvaloniaList<object>("bar");
Assert.Equal(1, target.SelectedIndex);
Assert.Equal(new[] { "bar" }, target.SelectedItems);
Assert.Equal(new[] { 1 }, SelectedContainers(target));
}
[Fact]
public void Assigning_Multiple_SelectedItems_Should_Set_SelectedIndex()
{
// Note that we don't need SelectionMode = Multiple here. Multiple selections can always
// be made in code.
var target = new TestSelector
{
Items = new[] { "foo", "bar", "baz" },
Template = Template(),
};
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
target.SelectedItems = new AvaloniaList<string>("foo", "bar", "baz");
Assert.Equal(0, target.SelectedIndex);
Assert.Equal(new[] { "foo", "bar", "baz" }, target.SelectedItems);
Assert.Equal(new[] { 0, 1, 2 }, SelectedContainers(target));
}
[Fact]
public void Selected_Items_Should_Be_Marked_When_Panel_Created_After_SelectedItems_Is_Set()
{
// Issue #2565.
var target = new TestSelector
{
Items = new[] { "foo", "bar", "baz" },
Template = Template(),
};
target.ApplyTemplate();
target.SelectedItems = new AvaloniaList<string>("foo", "bar", "baz");
target.Presenter.ApplyTemplate();
Assert.Equal(0, target.SelectedIndex);
Assert.Equal(new[] { "foo", "bar", "baz" }, target.SelectedItems);
Assert.Equal(new[] { 0, 1, 2 }, SelectedContainers(target));
}
[Fact]
@ -1026,6 +1068,31 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.Equal(1, target.SelectedItems.Count);
}
[Fact]
public void Adding_Selected_ItemContainers_Should_Update_Selection()
{
var items = new AvaloniaList<ItemContainer>(new[]
{
new ItemContainer(),
new ItemContainer(),
});
var target = new TestSelector
{
Items = items,
Template = Template(),
};
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
items.Add(new ItemContainer { IsSelected = true });
items.Add(new ItemContainer { IsSelected = true });
Assert.Equal(2, target.SelectedIndex);
Assert.Equal(items[2], target.SelectedItem);
Assert.Equal(new[] { items[2], items[3] }, target.SelectedItems);
}
private IEnumerable<int> SelectedContainers(SelectingItemsControl target)
{
return target.Presenter.Panel.Children
@ -1078,5 +1145,11 @@ namespace Avalonia.Controls.UnitTests.Primitives
public List<string> Items { get; }
public List<string> SelectedItems { get; }
}
private class ItemContainer : Control, ISelectable
{
public string Value { get; set; }
public bool IsSelected { get; set; }
}
}
}

Loading…
Cancel
Save