diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs
index 5cf1a5b71a..2dd5c7bc03 100644
--- a/src/Avalonia.Controls/TopLevel.cs
+++ b/src/Avalonia.Controls/TopLevel.cs
@@ -65,9 +65,9 @@ namespace Avalonia.Controls
/// Defines the property.
///
public static readonly DirectProperty ActualTransparencyLevelProperty =
- AvaloniaProperty.RegisterDirect(nameof(ActualTransparencyLevel),
- o => o.ActualTransparencyLevel,
- unsetValue: WindowTransparencyLevel.None);
+ AvaloniaProperty.RegisterDirect(nameof(ActualTransparencyLevel),
+ o => o.ActualTransparencyLevel,
+ unsetValue: WindowTransparencyLevel.None);
///
/// Defines the property.
@@ -78,7 +78,7 @@ namespace Avalonia.Controls
///
public static readonly StyledProperty ActualThemeVariantProperty =
ThemeVariantScope.ActualThemeVariantProperty.AddOwner();
-
+
///
public static readonly StyledProperty RequestedThemeVariantProperty =
ThemeVariantScope.RequestedThemeVariantProperty.AddOwner();
@@ -102,7 +102,7 @@ namespace Avalonia.Controls
///
/// Defines the event.
///
- public static readonly RoutedEvent BackRequestedEvent =
+ public static readonly RoutedEvent BackRequestedEvent =
RoutedEvent.Register(nameof(BackRequested), RoutingStrategies.Bubble);
private static readonly WeakEvent
@@ -131,7 +131,7 @@ namespace Avalonia.Controls
private readonly PresentationSource _source;
internal new PresentationSource PresentationSource => _source;
internal IInputRoot InputRoot => _source;
-
+
///
/// Initializes static members of the class.
///
@@ -199,9 +199,9 @@ namespace Avalonia.Controls
_scaling = ValidateScaling(impl.RenderScaling);
_actualTransparencyLevel = PlatformImpl.TransparencyLevel;
-
-
+
+
_accessKeyHandler = TryGetService(dependencyResolver);
_inputManager = TryGetService(dependencyResolver);
@@ -211,7 +211,7 @@ namespace Avalonia.Controls
_applicationThemeHost = TryGetService(dependencyResolver);
-
+
impl.Closed = HandleClosed;
impl.Paint = HandlePaint;
@@ -257,9 +257,7 @@ namespace Avalonia.Controls
impl.LostFocus += PlatformImpl_LostFocus;
-
-
- if(impl.TryGetFeature() is {} systemNavigationManager)
+ if (impl.TryGetFeature() is { } systemNavigationManager)
{
systemNavigationManager.BackRequested += (_, e) =>
{
@@ -286,14 +284,14 @@ namespace Avalonia.Controls
KeyModifiers = (KeyModifiers)rawKeyEventArgs.Modifiers,
Key = rawKeyEventArgs.Key,
PhysicalKey = rawKeyEventArgs.PhysicalKey,
- KeyDeviceType= rawKeyEventArgs.KeyDeviceType,
+ KeyDeviceType = rawKeyEventArgs.KeyDeviceType,
KeySymbol = rawKeyEventArgs.KeySymbol
};
- backRequested = keymap.Any( key => key.Matches(keyEvent));
+ backRequested = keymap.Any(key => key.Matches(keyEvent));
}
}
- else if(e is RawPointerEventArgs pointerEventArgs)
+ else if (e is RawPointerEventArgs pointerEventArgs)
{
backRequested = pointerEventArgs.Type == RawPointerEventType.XButton1Down;
}
@@ -321,7 +319,7 @@ namespace Avalonia.Controls
/// Gets or sets a method called when the TopLevel's scaling changes.
///
public event EventHandler? ScalingChanged;
-
+
///
/// Gets or sets the client size of the window.
///
@@ -359,7 +357,7 @@ namespace Avalonia.Controls
{
get => _actualTransparencyLevel;
private set => SetAndRaise(ActualTransparencyLevelProperty, ref _actualTransparencyLevel, value);
- }
+ }
///
/// Gets or sets the that transparency will blend with when transparency is not supported.
@@ -439,7 +437,7 @@ namespace Avalonia.Controls
public RendererDiagnostics RendererDiagnostics => Renderer.Diagnostics;
internal PixelPoint? LastPointerPosition => _source.GetLastPointerPosition(this);
-
+
///
/// Gets the access key handler for the window.
///
@@ -448,7 +446,7 @@ namespace Avalonia.Controls
///
/// Gets or sets the keyboard navigation handler for the window.
///
-
+
///
/// Helper for setting the color of the platform's system bars.
///
@@ -573,7 +571,7 @@ namespace Avalonia.Controls
return Disposable.Create(() => { });
}
}
-
+
///
/// Enqueues a callback to be called on the next animation tick
///
@@ -582,7 +580,7 @@ namespace Avalonia.Controls
Dispatcher.UIThread.VerifyAccess();
MediaContext.Instance.RequestAnimationFrame(action);
}
-
+
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@@ -602,7 +600,7 @@ namespace Avalonia.Controls
private void InvalidateChildInsetsPadding()
{
if (Content is Control child
- && InsetsManager is {} insetsManager)
+ && InsetsManager is { } insetsManager)
{
insetsManager.SafeAreaChanged -= InsetsManagerOnSafeAreaChanged;
_insetsPaddings?.Dispose();
@@ -643,12 +641,12 @@ namespace Avalonia.Controls
{
_source.Dispose();
StopRendering();
-
+
Debug.Assert(PlatformImpl != null);
// The PlatformImpl is completely invalid at this point
PlatformImpl = null;
_scaling = 1.0;
-
+
if (_globalStyles is object)
{
_globalStyles.GlobalStylesAdded -= ((IStyleHost)this).StylesAdded;
@@ -658,14 +656,14 @@ namespace Avalonia.Controls
{
_applicationThemeHost.ActualThemeVariantChanged -= GlobalActualThemeVariantChanged;
}
-
+
_backGestureSubscription?.Dispose();
var logicalArgs = new LogicalTreeAttachmentEventArgs(this, this, null);
((ILogical)this).NotifyDetachedFromLogicalTree(logicalArgs);
_source.RootVisual = null!;
-
+
OnClosed(EventArgs.Empty);
LayoutManager.Dispose();
@@ -781,8 +779,8 @@ namespace Avalonia.Controls
private static void OnToolTipServiceEnabledChanged(AvaloniaPropertyChangedEventArgs args)
{
if (args.GetNewValue()
- && args.Priority != BindingPriority.Inherited
- && args.Sender is Visual visual
+ && args.Priority != BindingPriority.Inherited
+ && args.Sender is Visual visual
&& GetTopLevel(visual) is { } topLevel)
{
topLevel.UpdateToolTip(visual.Bounds.Translate((Vector)visual.TranslatePoint(default, topLevel)!));
@@ -803,11 +801,7 @@ namespace Avalonia.Controls
void PlatformImpl_LostFocus()
{
- var focused = (Visual?)FocusManager?.GetFocusedElement();
- if (focused == null)
- return;
- while (focused.VisualParent != null)
- focused = focused.VisualParent;
+ var focused = TopLevel.GetTopLevel((Visual?)FocusManager?.GetFocusedElement());
if (focused == this)
KeyboardDevice.Instance?.SetFocusedElement(null, NavigationMethod.Unspecified, KeyModifiers.None, false);
diff --git a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs
index 02a880d166..470030ef0b 100644
--- a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs
@@ -253,6 +253,34 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Fact]
+ public void TopLevel_Should_Unfocus_When_Impl_Focus_Is_Lost()
+ {
+ using (UnitTestApplication.Start(TestServices.RealFocus))
+ {
+ var impl = CreateMockTopLevelImpl(true);
+ var content = new TextBox()
+ {
+ Focusable = true
+ };
+ var target = new TestTopLevel(impl.Object)
+ {
+ Template = CreateTemplate(),
+ Focusable = true,
+ Content = content
+ };
+
+ target.LayoutManager.ExecuteInitialLayoutPass();
+
+ content.Focus();
+ Assert.True(content.IsFocused);
+
+ impl.Object.LostFocus?.Invoke();
+
+ Assert.False(content.IsFocused);
+ }
+ }
+
[Fact]
public void Reacts_To_Changes_In_Global_Styles()
{