Browse Source

Fix selection after deleting an item.

`SelectionModel` needs to subscribe to `CollectionChanged` on the items before `ItemsControl` in order for the selection to be correct when we come to setting the selected state.

Because `SelectionModel.Source` isn't subscribed during initialization in `ItemsChanged`, we also need to make sure we don't subscribe `ItemsControl` to the collection changes during initialization. Instead subscribe in `OnInitialized` (this requires a few tests to be rooted in order to be called).

Fixes #4293
Steven Kirk 5 years ago
parent
commit
6555a51f5a

+ 9 - 2
src/Avalonia.Controls/ItemsControl.cs

@@ -70,7 +70,6 @@ namespace Avalonia.Controls
         public ItemsControl()
         {
             PseudoClasses.Add(":empty");
-            SubscribeToItems(_items);
         }
 
         /// <summary>
@@ -265,6 +264,11 @@ namespace Avalonia.Controls
         {
         }
 
+        protected override void OnInitialized()
+        {
+            SubscribeToItems(_items);
+        }
+
         /// <summary>
         /// Handles directional navigation within the <see cref="ItemsControl"/>.
         /// </summary>
@@ -330,7 +334,10 @@ namespace Avalonia.Controls
                 Presenter.Items = newValue;
             }
 
-            SubscribeToItems(newValue);
+            if (IsInitialized)
+            {
+                SubscribeToItems(newValue);
+            }
         }
 
         /// <summary>

+ 3 - 0
tests/Avalonia.Controls.UnitTests/CarouselTests.cs

@@ -4,6 +4,7 @@ using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
 using Avalonia.LogicalTree;
+using Avalonia.UnitTests;
 using Avalonia.VisualTree;
 using Xunit;
 
@@ -155,6 +156,7 @@ namespace Avalonia.Controls.UnitTests
                 IsVirtualized = false
             };
 
+            var root = new TestRoot(target);
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 
@@ -247,6 +249,7 @@ namespace Avalonia.Controls.UnitTests
                 IsVirtualized = false
             };
 
+            var root = new TestRoot(target);
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 

+ 4 - 0
tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

@@ -131,6 +131,7 @@ namespace Avalonia.Controls.UnitTests
             var child = new Control();
             var items = new AvaloniaList<Control>(child);
 
+            var root = new TestRoot(target);
             target.Template = GetTemplate();
             target.Items = items;
             items.RemoveAt(0);
@@ -283,6 +284,7 @@ namespace Avalonia.Controls.UnitTests
             var items = new AvaloniaList<string> { "Foo" };
             var called = false;
 
+            var root = new TestRoot(target);
             target.Template = GetTemplate();
             target.Items = items;
             target.ApplyTemplate();
@@ -303,6 +305,7 @@ namespace Avalonia.Controls.UnitTests
             var items = new AvaloniaList<string> { "Foo", "Bar" };
             var called = false;
 
+            var root = new TestRoot(target);
             target.Template = GetTemplate();
             target.Items = items;
             target.ApplyTemplate();
@@ -376,6 +379,7 @@ namespace Avalonia.Controls.UnitTests
                 Items = new[] { 1, 2, 3 },
             };
 
+            var root = new TestRoot(target);
             Assert.DoesNotContain(":empty", target.Classes);
         }
 

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

@@ -170,6 +170,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 SelectionMode = SelectionMode.Single | SelectionMode.AlwaysSelected
             };
 
+            var root = new TestRoot(listBox);
+
             listBox.BeginInit();
 
             listBox.SelectedIndex = 1;
@@ -480,6 +482,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 Template = Template(),
             };
 
+            var root = new TestRoot(target);
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
             items.Add(new Item { IsSelected = true });
@@ -919,6 +922,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 Items = items,
             };
 
+            var root = new TestRoot(target);
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 

+ 4 - 0
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs

@@ -1014,6 +1014,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 SelectionMode = SelectionMode.Multiple,
             };
 
+            var root = new TestRoot(target);
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 
@@ -1043,6 +1044,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 SelectionMode = SelectionMode.Multiple,
             };
 
+            var root = new TestRoot(target);
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 
@@ -1076,6 +1078,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 SelectionMode = SelectionMode.Multiple,
             };
 
+            var root = new TestRoot(target);
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 
@@ -1199,6 +1202,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 Template = Template(),
             };
 
+            var root = new TestRoot(target);
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
             items.Add(new ItemContainer { IsSelected = true });