From 11669e3a44d324264e110f417fe3e1ffd9a638dc Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Sat, 23 Sep 2023 09:19:32 +0000 Subject: [PATCH] Fix focus loss issue with AutocompleteBox (#12883) * fix focus loss issue with autocomplete box * close dropdown when focus actually moves within the autocompletebox's focus scope * make GetFocusScope internal for now * remove GetFocusScope from focus manager --------- Co-authored-by: Max Katz --- .../AutoCompleteBox/AutoCompleteBox.cs | 31 ++++++++++++++++++- src/Avalonia.Controls/ListBoxItem.cs | 7 +++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs index a6cf363492..6790a2fc41 100644 --- a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs @@ -826,12 +826,41 @@ namespace Avalonia.Controls } else { - SetCurrentValue(IsDropDownOpenProperty, false); + // Check if we still have focus in the parent's focus scope + if (GetFocusScope() is { } scope && + (FocusManager.GetFocusManager(this)?.GetFocusedElement(scope) is not { } focused || + (focused != this && + (focused is Visual v && !this.IsVisualAncestorOf(v))))) + { + SetCurrentValue(IsDropDownOpenProperty, false); + } + _userCalledPopulate = false; ClearTextBoxSelection(); } _isFocused = hasFocus; + + IFocusScope? GetFocusScope() + { + IInputElement? c = this; + + while (c != null) + { + if (c is IFocusScope scope && + c is Visual v && + v.VisualRoot is Visual root && + root.IsVisible) + { + return scope; + } + + c = (c as Visual)?.GetVisualParent() ?? + ((c as IHostedVisualTreeRoot)?.Host as IInputElement); + } + + return null; + } } /// diff --git a/src/Avalonia.Controls/ListBoxItem.cs b/src/Avalonia.Controls/ListBoxItem.cs index 15136e5992..c4db5a1f6b 100644 --- a/src/Avalonia.Controls/ListBoxItem.cs +++ b/src/Avalonia.Controls/ListBoxItem.cs @@ -100,7 +100,14 @@ namespace Avalonia.Controls ItemsControl.ItemsControlFromItemContaner(this) is ListBox owner) { if (owner.UpdateSelectionFromPointerEvent(this, e)) + { + // As we only update selection from touch/pen on pointer release, we need to raise + // the pointer event on the owner to trigger a commit. + if (e.Pointer.Type != PointerType.Mouse) + owner.RaiseEvent(e); + e.Handled = true; + } } }