Browse Source

Merge pull request #4308 from AvaloniaUI/fixes/4293-listbox-remove-item-selection-2

Fix selection after deleting an item - Attempt II
danwalmsley 5 years ago
parent
commit
068c1d8a43

+ 7 - 1
samples/ControlCatalog/Pages/ListBoxPage.xaml

@@ -10,7 +10,13 @@
               HorizontalAlignment="Center"
               Spacing="16">
       <StackPanel Orientation="Vertical" Spacing="8">
-        <ListBox Items="{Binding Items}" SelectedItem="{Binding SelectedItem}" AutoScrollToSelectedItem="True"  SelectionMode="{Binding SelectionMode}" Width="250" Height="350"></ListBox>
+        <ListBox Items="{Binding Items}"
+                 SelectedItem="{Binding SelectedItem}"
+                 SelectedItems="{Binding SelectedItems}"
+                 AutoScrollToSelectedItem="True"
+                 SelectionMode="{Binding SelectionMode}"
+                 Width="250"
+                 Height="350"/>
 
         <Button Command="{Binding AddItemCommand}">Add</Button>
 

+ 15 - 5
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@@ -692,14 +692,24 @@ namespace Avalonia.Controls.Primitives
                 }
             }
 
-            foreach (var i in e.SelectedIndices)
+            if (e.SelectedIndices.Count > 0 || e.DeselectedIndices.Count > 0)
             {
-                Mark(i.GetAt(0), true);
-            }
+                foreach (var i in e.SelectedIndices)
+                {
+                    Mark(i.GetAt(0), true);
+                }
 
-            foreach (var i in e.DeselectedIndices)
+                foreach (var i in e.DeselectedIndices)
+                {
+                    Mark(i.GetAt(0), false);
+                }
+            }
+            else if (e.DeselectedItems.Count > 0)
             {
-                Mark(i.GetAt(0), false);
+                // (De)selected indices being empty means that a selected item was removed from
+                // the Items (it can't tell us the index of the item because the index is no longer
+                // valid). In this case, we just update the selection state of all containers.
+                UpdateContainerSelection();
             }
 
             var newSelectedIndex = SelectedIndex;

+ 40 - 0
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@@ -531,6 +531,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
             };
 
             target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
             target.SelectedIndex = 1;
 
             Assert.Equal(items[1], target.SelectedItem);
@@ -549,6 +550,45 @@ namespace Avalonia.Controls.UnitTests.Primitives
             Assert.NotNull(receivedArgs);
             Assert.Empty(receivedArgs.AddedItems);
             Assert.Equal(new[] { removed }, receivedArgs.RemovedItems);
+            Assert.False(items.Single().IsSelected);
+        }
+
+        [Fact]
+        public void Removing_Selected_Item_Should_Clear_Selection_With_BeginInit()
+        {
+            var items = new AvaloniaList<Item>
+            {
+                new Item(),
+                new Item(),
+            };
+
+            var target = new SelectingItemsControl();
+            target.BeginInit();
+            target.Items = items;
+            target.Template = Template();
+            target.EndInit();
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+            target.SelectedIndex = 0;
+
+            Assert.Equal(items[0], target.SelectedItem);
+            Assert.Equal(0, target.SelectedIndex);
+
+            SelectionChangedEventArgs receivedArgs = null;
+
+            target.SelectionChanged += (_, args) => receivedArgs = args;
+
+            var removed = items[0];
+
+            items.RemoveAt(0);
+
+            Assert.Null(target.SelectedItem);
+            Assert.Equal(-1, target.SelectedIndex);
+            Assert.NotNull(receivedArgs);
+            Assert.Empty(receivedArgs.AddedItems);
+            Assert.Equal(new[] { removed }, receivedArgs.RemovedItems);
+            Assert.False(items.Single().IsSelected);
         }
 
         [Fact]