diff --git a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
index f4132a5ced..32d5d9f648 100644
--- a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
@@ -212,8 +212,6 @@ namespace Avalonia.Controls
private bool _itemTemplateIsFromValueMemberBinding = true;
private bool _settingItemTemplateFromValueMemberBinding;
- private bool _isFocused = false;
-
private string? _searchText = string.Empty;
private readonly EventHandler _populateDropDownHandler;
@@ -751,28 +749,34 @@ namespace Avalonia.Controls
}
}
- ///
- /// Provides handling for the
- /// event.
- ///
- /// A
- /// that contains the event data.
+ ///
protected override void OnGotFocus(FocusChangedEventArgs e)
{
+ if (TextBox is not null && TextBoxSelectionLength <= 0)
+ {
+ TextBox.Focus();
+ TextBox.SelectAll();
+ }
+
base.OnGotFocus(e);
- FocusChanged(HasFocus());
}
- ///
- /// Provides handling for the
- /// event.
- ///
- /// A
- /// that contains the event data.
+ ///
protected override void OnLostFocus(FocusChangedEventArgs e)
{
+ SetCurrentValue(IsDropDownOpenProperty, false);
+
+ _userCalledPopulate = false;
+
+ var textBoxContextMenuIsOpen = TextBox?.ContextFlyout?.IsOpen == true || TextBox?.ContextMenu?.IsOpen == true;
+ var contextMenuIsOpen = ContextFlyout?.IsOpen == true || ContextMenu?.IsOpen == true;
+
+ if (!textBoxContextMenuIsOpen && !contextMenuIsOpen && ClearSelectionOnLostFocus)
+ {
+ ClearTextBoxSelection();
+ }
+
base.OnLostFocus(e);
- FocusChanged(HasFocus());
}
protected override AutomationPeer OnCreateAutomationPeer() => new AutoCompleteBoxAutomationPeer(this);
@@ -785,79 +789,9 @@ namespace Avalonia.Controls
/// true to indicate the
/// has focus;
/// otherwise, false.
+ [Obsolete($"Use {nameof(IsKeyboardFocusWithin)} instead.")]
protected bool HasFocus() => IsKeyboardFocusWithin;
- ///
- /// Handles the FocusChanged event.
- ///
- /// A value indicating whether the control
- /// currently has the focus.
- private void FocusChanged(bool hasFocus)
- {
- // The OnGotFocus & OnLostFocus are asynchronously and cannot
- // reliably tell you that have the focus. All they do is let you
- // know that the focus changed sometime in the past. To determine
- // if you currently have the focus you need to do consult the
- // FocusManager (see HasFocus()).
-
- bool wasFocused = _isFocused;
- _isFocused = hasFocus;
-
- if (hasFocus)
- {
-
- if (!wasFocused && TextBox != null && TextBoxSelectionLength <= 0)
- {
- TextBox.Focus();
- TextBox.SelectAll();
- }
- }
- else
- {
- // 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;
-
- var textBoxContextMenuIsOpen = TextBox?.ContextFlyout?.IsOpen == true || TextBox?.ContextMenu?.IsOpen == true;
- var contextMenuIsOpen = ContextFlyout?.IsOpen == true || ContextMenu?.IsOpen == true;
-
- if (!textBoxContextMenuIsOpen && !contextMenuIsOpen && ClearSelectionOnLostFocus)
- {
- 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;
- }
- }
-
///
/// Occurs asynchronously when the text in the portion of the
/// changes.
diff --git a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
index 4232624fad..d5bcde0c6d 100644
--- a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
@@ -584,6 +584,40 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Fact]
+ public void Losing_Focus_Closes_DropDown()
+ {
+ using var app = UnitTestApplication.Start(FocusServices);
+
+ var target1 = CreateControl();
+ target1.ItemsSource = CreateSimpleStringArray();
+ var textBox1 = GetTextBox(target1);
+
+ var target2 = CreateControl();
+
+ target1.ApplyTemplate();
+ target2.ApplyTemplate();
+
+ _ = new TestRoot
+ {
+ Child = new StackPanel
+ {
+ Children = { target1, target2 }
+ }
+ };
+
+ target1.Focus();
+ textBox1.Text = "a";
+ Dispatcher.UIThread.RunJobs(null, TestContext.Current.CancellationToken);
+ Assert.True(target1.IsDropDownOpen);
+
+ target2.Focus();
+ Dispatcher.UIThread.RunJobs(null, TestContext.Current.CancellationToken);
+
+ Assert.False(target1.IsFocused);
+ Assert.False(target1.IsDropDownOpen);
+ }
+
///
/// Retrieves a defined predicate filter through a new AutoCompleteBox
/// control instance.