Răsfoiți Sursa

Added failing test for #2660.

And a passing test too. Also added some useful methods to `TreeView` to help with this.
Steven Kirk 6 ani în urmă
părinte
comite
4e4c1918ab

+ 43 - 1
src/Avalonia.Controls/TreeView.cs

@@ -164,6 +164,48 @@ namespace Avalonia.Controls
             }
         }
 
+        /// <summary>
+        /// Expands the specified <see cref="TreeViewItem"/> all descendent <see cref="TreeViewItem"/>s.
+        /// </summary>
+        /// <param name="item">The item to expand.</param>
+        public void ExpandSubTree(TreeViewItem item)
+        {
+            item.IsExpanded = true;
+
+            var panel = item.Presenter.Panel;
+
+            if (panel != null)
+            {
+                foreach (var child in panel.Children)
+                {
+                    if (child is TreeViewItem treeViewItem)
+                    {
+                        ExpandSubTree(treeViewItem);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Selects all items in the <see cref="TreeView"/>.
+        /// </summary>
+        /// <remarks>
+        /// Note that this method only selects nodes currently visible due to their parent nodes
+        /// being expanded: it does not expand nodes.
+        /// </remarks>
+        public void SelectAll()
+        {
+            SynchronizeItems(SelectedItems, ItemContainerGenerator.Index.Items);
+        }
+
+        /// <summary>
+        /// Deselects all items in the <see cref="TreeView"/>.
+        /// </summary>
+        public void UnselectAll()
+        {
+            SelectedItems.Clear();
+        }
+
         /// <summary>
         /// Subscribes to the <see cref="SelectedItems"/> CollectionChanged event, if any.
         /// </summary>
@@ -409,7 +451,7 @@ namespace Avalonia.Controls
 
                 if (this.SelectionMode == SelectionMode.Multiple && Match(keymap.SelectAll))
                 {
-                    SynchronizeItems(SelectedItems, ItemContainerGenerator.Index.Items);
+                    SelectAll();
                     e.Handled = true;
                 }
             }

+ 66 - 1
tests/Avalonia.Controls.UnitTests/TreeViewTests.cs

@@ -11,6 +11,7 @@ using Avalonia.Data;
 using Avalonia.Data.Core;
 using Avalonia.Input;
 using Avalonia.Input.Platform;
+using Avalonia.Interactivity;
 using Avalonia.LogicalTree;
 using Avalonia.UnitTests;
 using Xunit;
@@ -740,6 +741,71 @@ namespace Avalonia.Controls.UnitTests
             }
         }
 
+        [Fact]
+        public void Right_Click_On_SelectedItem_Should_Not_Clear_Existing_Selection()
+        {
+            var tree = CreateTestTreeData();
+            var target = new TreeView
+            {
+                Template = CreateTreeViewTemplate(),
+                Items = tree,
+                ItemTemplate = new FuncDataTemplate<string>(x => new TextBlock { Width = 20, Height = 10 }),
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            var visualRoot = new TestRoot();
+            visualRoot.Child = target;
+
+            CreateNodeDataTemplate(target);
+            ApplyTemplates(target);
+            target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
+            target.SelectAll();
+
+            AssertChildrenSelected(target, tree[0]);
+            Assert.Equal(5, target.SelectedItems.Count);
+
+            _mouse.Click((Interactive)target.Presenter.Panel.Children[0], MouseButton.Right);
+
+            Assert.Equal(5, target.SelectedItems.Count);
+        }
+
+        [Fact]
+        public void Right_Click_On_UnselectedItem_Should_Clear_Existing_Selection()
+        {
+            var tree = CreateTestTreeData();
+            var target = new TreeView
+            {
+                Template = CreateTreeViewTemplate(),
+                Items = tree,
+                ItemTemplate = new FuncDataTemplate<string>(x => new TextBlock { Width = 20, Height = 10 }),
+                SelectionMode = SelectionMode.Multiple,
+            };
+
+            var visualRoot = new TestRoot();
+            visualRoot.Child = target;
+
+            CreateNodeDataTemplate(target);
+            ApplyTemplates(target);
+            target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
+
+            var rootNode = tree[0];
+            var to = rootNode.Children[0];
+            var then = rootNode.Children[1];
+
+            var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(rootNode);
+            var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
+            var thenContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(then);
+
+            ClickContainer(fromContainer, InputModifiers.None);
+            ClickContainer(toContainer, InputModifiers.Shift);
+
+            Assert.Equal(2, target.SelectedItems.Count);
+
+            _mouse.Click(thenContainer, MouseButton.Right);
+
+            Assert.Equal(1, target.SelectedItems.Count);
+        }
+
         private void ApplyTemplates(TreeView tree)
         {
             tree.ApplyTemplate();
@@ -874,7 +940,6 @@ namespace Avalonia.Controls.UnitTests
             }
         }
 
-
         private class Node : NotifyingBase
         {
             private IAvaloniaList<Node> _children;