From 8d87c3690114957773ae9b8805249871ac81d124 Mon Sep 17 00:00:00 2001 From: Magnus Lindhe Date: Sat, 3 Feb 2024 10:39:40 +0100 Subject: [PATCH] Improve NumericUpDown and AutoCompleteBox focusability (#13376) * Delegate focus to TextBox * Port FocusChanged from AutoCompleteBox to NumericUpDown * Improve focus with NumericUpDown and ButtonSpinner bindings --------- Co-authored-by: Max Katz --- .../AutoCompleteBox/AutoCompleteBox.cs | 32 ++--------------- .../NumericUpDown/NumericUpDown.cs | 34 +++++++++++++++++++ .../Controls/ButtonSpinner.xaml | 4 +++ .../Controls/NumericUpDown.xaml | 1 + .../Controls/ButtonSpinner.xaml | 4 +++ .../Controls/NumericUpDown.xaml | 1 + 6 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs index 0ac043d2e5..e37e601caa 100644 --- a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs @@ -463,6 +463,7 @@ namespace Avalonia.Controls static AutoCompleteBox() { FocusableProperty.OverrideDefaultValue(true); + IsTabStopProperty.OverrideDefaultValue(false); MinimumPopulateDelayProperty.Changed.AddClassHandler((x,e) => x.OnMinimumPopulateDelayChanged(e)); IsDropDownOpenProperty.Changed.AddClassHandler((x,e) => x.OnIsDropDownOpenChanged(e)); @@ -770,33 +771,7 @@ namespace Avalonia.Controls /// true to indicate the /// has focus; /// otherwise, false. - protected bool HasFocus() - { - Visual? focused = FocusManager.GetFocusManager(this)?.GetFocusedElement() as Visual; - - while (focused != null) - { - if (object.ReferenceEquals(focused, this)) - { - return true; - } - - // This helps deal with popups that may not be in the same - // visual tree - Visual? parent = focused.GetVisualParent(); - if (parent == null) - { - // Try the logical parent. - Control? element = focused as Control; - if (element != null) - { - parent = element.VisualParent; - } - } - focused = parent; - } - return false; - } + protected bool HasFocus() => IsKeyboardFocusWithin; /// /// Handles the FocusChanged event. @@ -820,8 +795,7 @@ namespace Avalonia.Controls if (!wasFocused && TextBox != null && TextBoxSelectionLength <= 0) { TextBox.Focus(); - TextBox.SelectionStart = 0; - TextBox.SelectionEnd = TextBox.Text?.Length ?? 0; + TextBox.SelectAll(); } } else diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs index c329ce9e8e..5cad4a6769 100644 --- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs +++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs @@ -137,6 +137,7 @@ namespace Avalonia.Controls private bool _internalValueSet; private bool _isSyncingTextAndValueProperties; private bool _isTextChangedFromUI; + private bool _isFocused; /// /// Gets the Spinner template part. @@ -344,6 +345,16 @@ namespace Avalonia.Controls TextProperty.Changed.Subscribe(OnTextChanged); TextConverterProperty.Changed.Subscribe(OnTextConverterChanged); ValueProperty.Changed.Subscribe(OnValueChanged); + + FocusableProperty.OverrideDefaultValue(true); + IsTabStopProperty.OverrideDefaultValue(false); + } + + /// + protected override void OnGotFocus(GotFocusEventArgs e) + { + base.OnGotFocus(e); + FocusChanged(IsKeyboardFocusWithin); } /// @@ -351,6 +362,7 @@ namespace Avalonia.Controls { CommitInput(true); base.OnLostFocus(e); + FocusChanged(IsKeyboardFocusWithin); } /// @@ -1164,5 +1176,27 @@ namespace Avalonia.Controls } return false; } + + 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. + + bool wasFocused = _isFocused; + _isFocused = hasFocus; + + if (hasFocus) + { + + if (!wasFocused && TextBox != null) + { + TextBox.Focus(); + TextBox.SelectAll(); + } + } + } } } diff --git a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml index 095e801d0c..f4637d26d5 100644 --- a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml @@ -93,10 +93,12 @@ MinHeight="{TemplateBinding MinHeight}">