Browse Source

Fix FocusManager.SetFocusScope not doing anything (#21261)

* Add failing test for SetFocusScope

* Fix FocusManager.SetFocusScope not doing anything
release/latest
Julien Lebosquain 3 months ago
parent
commit
0ce886aaeb
  1. 10
      src/Avalonia.Base/Input/FocusManager.cs
  2. 35
      tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs

10
src/Avalonia.Base/Input/FocusManager.cs

@ -142,6 +142,9 @@ namespace Avalonia.Input
[PrivateApi]
public void SetFocusScope(IFocusScope scope)
{
if (KeyboardDevice.Instance is not { } keyboardDevice)
return;
if (GetFocusedElement(scope) is { } focused)
{
Focus(focused);
@ -153,6 +156,13 @@ namespace Avalonia.Input
// focus etc.
Focus(scopeElement);
}
else
{
// If the scope isn't focusable, make sure we still set it as the current focus root,
// otherwise it will be completely ignored
_focusRoot = scope as StyledElement;
keyboardDevice.SetFocusedElement(null, NavigationMethod.Unspecified, KeyModifiers.None, false);
}
}
[PrivateApi]

35
tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs

@ -703,6 +703,41 @@ namespace Avalonia.Base.UnitTests.Input
Assert.Same(innerButton, focusManager.GetFocusedElement());
}
// https://github.com/AvaloniaUI/Avalonia/issues/13134
[Fact]
public void SetFocusScope_On_Non_Focusable_Scope_Changes_Scope()
{
using var app = UnitTestApplication.Start(TestServices.RealFocus);
Button outerButton;
TestFocusScope innerScope;
var root = new TestRoot
{
Child = new StackPanel
{
Focusable = false,
Children =
{
(innerScope = new TestFocusScope()),
(outerButton = new Button())
}
}
};
outerButton.Focus();
var focusManager = Assert.IsType<FocusManager>(root.FocusManager);
Assert.Same(outerButton, focusManager.GetFocusedElement());
// Switch to a scope that has no previously focused element and isn't focusable itself.
// TestFocusScope is a Panel (Focusable = false) + IFocusScope.
focusManager.SetFocusScope(innerScope);
// Focus must be cleared: the scope is not focusable and has no prior focused element.
// Before the fix this was a no-op and outerButton would still be reported as focused.
Assert.Null(focusManager.GetFocusedElement());
}
[Fact]
public void Can_Get_First_Focusable_Element()
{

Loading…
Cancel
Save