From d3b43efe161c3ff12cd8939cff6a821bbc8f94aa Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 29 Oct 2020 11:33:41 +0000 Subject: [PATCH 1/6] if TreeView has a selecteditem that isnt really part of the tree... then do not crash tab navigation. --- src/Avalonia.Controls/TreeView.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index b2bd5ab2e5..f020280496 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -378,10 +378,11 @@ namespace Avalonia.Controls { if (!this.IsVisualAncestorOf(element)) { - IControl result = _selectedItem != null ? + var result = _selectedItem != null ? ItemContainerGenerator.Index.ContainerFromItem(_selectedItem) : ItemContainerGenerator.ContainerFromIndex(0); - return (true, result); + + return (result is {}, result); // SelectedItem may not be in the treeview. } return (true, null); From 27c58c45e15847239b197a89d8407aaa56d390b1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 29 Oct 2020 11:36:08 +0000 Subject: [PATCH 2/6] treeview navigation never return handled... if returning null. --- src/Avalonia.Controls/TreeView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index f020280496..7bd82322d1 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -385,7 +385,7 @@ namespace Avalonia.Controls return (result is {}, result); // SelectedItem may not be in the treeview. } - return (true, null); + return (false, null); } return (false, null); From 3db5e1bc5abacd72e78da9d8f899b2749b7e383a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 29 Oct 2020 12:13:41 +0000 Subject: [PATCH 3/6] Revert "treeview navigation never return handled... if returning null." This reverts commit 27c58c45e15847239b197a89d8407aaa56d390b1. --- src/Avalonia.Controls/TreeView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index 7bd82322d1..f020280496 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -385,7 +385,7 @@ namespace Avalonia.Controls return (result is {}, result); // SelectedItem may not be in the treeview. } - return (false, null); + return (true, null); } return (false, null); From d3c44a89c0e5c15ac5ef0e3066fabe8b1fde80ba Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 29 Oct 2020 13:13:15 +0000 Subject: [PATCH 4/6] revert fix and add failing unit test. --- src/Avalonia.Controls/TreeView.cs | 2 +- .../TreeViewTests.cs | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index f020280496..558bcddfbe 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -382,7 +382,7 @@ namespace Avalonia.Controls ItemContainerGenerator.Index.ContainerFromItem(_selectedItem) : ItemContainerGenerator.ContainerFromIndex(0); - return (result is {}, result); // SelectedItem may not be in the treeview. + return (true, result); // SelectedItem may not be in the treeview. } return (true, null); diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index b805683393..cea77bb7c9 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -675,6 +675,50 @@ namespace Avalonia.Controls.UnitTests Assert.Same(node, focus.Current); } } + + [Fact] + public void Keyboard_Navigation_Should_Not_Crash_If_Selected_Item_Is_not_In_Tree() + { + using (Application()) + { + var focus = FocusManager.Instance; + var navigation = AvaloniaLocator.Current.GetService(); + var data = CreateTestTreeData(); + + var selectedNode = new Node { Value = "Out of Tree Selected Item" }; + + var target = new TreeView + { + Template = CreateTreeViewTemplate(), + Items = data, + SelectedItem = selectedNode + }; + + var button = new Button(); + + var root = new TestRoot + { + Child = new StackPanel + { + Children = { target, button }, + } + }; + + CreateNodeDataTemplate(target); + ApplyTemplates(target); + ExpandAll(target); + + var item = data[0].Children[0]; + var node = target.ItemContainerGenerator.Index.ContainerFromItem(item); + Assert.NotNull(node); + + target.SelectedItem = selectedNode; + node.Focus(); + Assert.Same(node, focus.Current); + + var next = KeyboardNavigationHandler.GetNext(node, NavigationDirection.Previous); + } + } [Fact] public void Pressing_SelectAll_Gesture_Should_Select_All_Nodes() From 22605e52e9d15e9127f308d8e60a70abe38a4770 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 29 Oct 2020 13:14:00 +0000 Subject: [PATCH 5/6] add fix for treeview navigation when SelectedItem is not in the tree. --- src/Avalonia.Controls/TreeView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index 558bcddfbe..f020280496 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -382,7 +382,7 @@ namespace Avalonia.Controls ItemContainerGenerator.Index.ContainerFromItem(_selectedItem) : ItemContainerGenerator.ContainerFromIndex(0); - return (true, result); // SelectedItem may not be in the treeview. + return (result is {}, result); // SelectedItem may not be in the treeview. } return (true, null); From 7a33cd4e825f70dbc1fb4cef7dabb63d98b1f009 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 2 Nov 2020 10:22:55 +0000 Subject: [PATCH 6/6] change syntax. --- src/Avalonia.Controls/TreeView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index f020280496..09742412d9 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -382,7 +382,7 @@ namespace Avalonia.Controls ItemContainerGenerator.Index.ContainerFromItem(_selectedItem) : ItemContainerGenerator.ContainerFromIndex(0); - return (result is {}, result); // SelectedItem may not be in the treeview. + return (result != null, result); // SelectedItem may not be in the treeview. } return (true, null);