From c941a3d1b99839ad517178f6e88235d2ec4d0cd3 Mon Sep 17 00:00:00 2001 From: amwx Date: Mon, 5 Oct 2020 15:18:26 -0500 Subject: [PATCH 1/4] Return focus to PlacementTarget on close --- src/Avalonia.Controls/Primitives/Popup.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 1e5e80d144..69fa2dc709 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -586,6 +586,19 @@ namespace Avalonia.Controls.Primitives } Closed?.Invoke(this, EventArgs.Empty); + + if(PlacementTarget != null) + { + FocusManager.Instance?.Focus(PlacementTarget); + } + else + { + var anc = this.GetLogicalAncestors().OfType().FirstOrDefault(); + if (anc != null) + { + FocusManager.Instance?.Focus(anc); + } + } } private void ListenForNonClientClick(RawInputEventArgs e) From 273f296b47d0a0e8dd39a6ccf922fa8e075f4dbd Mon Sep 17 00:00:00 2001 From: amwx Date: Tue, 6 Oct 2020 15:39:21 -0500 Subject: [PATCH 2/4] Small fix --- src/Avalonia.Controls/Primitives/Popup.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 69fa2dc709..5d911d7727 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -358,7 +358,7 @@ namespace Avalonia.Controls.Primitives return; } - var placementTarget = PlacementTarget ?? this.GetLogicalAncestors().OfType().FirstOrDefault(); + var placementTarget = PlacementTarget ?? this.FindLogicalAncestorOfType(); if (placementTarget == null) { @@ -587,13 +587,13 @@ namespace Avalonia.Controls.Primitives Closed?.Invoke(this, EventArgs.Empty); - if(PlacementTarget != null) + if (PlacementTarget != null) { FocusManager.Instance?.Focus(PlacementTarget); } else { - var anc = this.GetLogicalAncestors().OfType().FirstOrDefault(); + var anc = this.FindLogicalAncestorOfType(); if (anc != null) { FocusManager.Instance?.Focus(anc); From 7f7db22004fd45f136bf7307c93ce2d52f0542d3 Mon Sep 17 00:00:00 2001 From: amwx Date: Tue, 6 Oct 2020 22:23:03 -0500 Subject: [PATCH 3/4] Only move focus if Popup had it --- src/Avalonia.Controls/Primitives/Popup.cs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 5d911d7727..becb489557 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -587,16 +587,23 @@ namespace Avalonia.Controls.Primitives Closed?.Invoke(this, EventArgs.Empty); - if (PlacementTarget != null) - { - FocusManager.Instance?.Focus(PlacementTarget); - } - else + var focusCheck = FocusManager.Instance?.Current; + + // Focus is set to null as part of popup closing, so we only want to + // set focus to PlacementTarget if this is the case + if (focusCheck == null) { - var anc = this.FindLogicalAncestorOfType(); - if (anc != null) + if (PlacementTarget != null) { - FocusManager.Instance?.Focus(anc); + FocusManager.Instance?.Focus(PlacementTarget); + } + else + { + var anc = this.FindLogicalAncestorOfType(); + if (anc != null) + { + FocusManager.Instance?.Focus(anc); + } } } } From 952c53cdff26960392bb5e65b1f07afa060853f1 Mon Sep 17 00:00:00 2001 From: amwx Date: Wed, 7 Oct 2020 23:06:29 -0500 Subject: [PATCH 4/4] Add tests --- .../Primitives/PopupTests.cs | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index f032186bcd..9223b08c81 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -485,6 +485,85 @@ namespace Avalonia.Controls.UnitTests.Primitives } } + [Fact] + public void Closing_Popup_Sets_Focus_On_PlacementTarget() + { + using (CreateServicesWithFocus()) + { + var window = PreparedWindow(); + + var tb = new TextBox(); + var p = new Popup + { + PlacementTarget = window, + Child = tb + }; + ((ISetLogicalParent)p).SetParent(p.PlacementTarget); + window.Show(); + + p.Open(); + + if (p.Host is OverlayPopupHost host) + { + //Need to measure/arrange for visual children to show up + //in OverlayPopupHost + host.Measure(Size.Infinity); + host.Arrange(new Rect(host.DesiredSize)); + } + + tb.Focus(); + + p.Close(); + + var focus = FocusManager.Instance?.Current; + Assert.True(focus == window); + } + } + + [Fact] + public void Prog_Close_Popup_NoLightDismiss_Doesnt_Move_Focus_To_PlacementTarget() + { + using (CreateServicesWithFocus()) + { + var window = PreparedWindow(); + + var windowTB = new TextBox(); + window.Content = windowTB; + + var popupTB = new TextBox(); + var p = new Popup + { + PlacementTarget = window, + IsLightDismissEnabled = false, + Child = popupTB + }; + ((ISetLogicalParent)p).SetParent(p.PlacementTarget); + window.Show(); + + p.Open(); + + if (p.Host is OverlayPopupHost host) + { + //Need to measure/arrange for visual children to show up + //in OverlayPopupHost + host.Measure(Size.Infinity); + host.Arrange(new Rect(host.DesiredSize)); + } + + popupTB.Focus(); + + windowTB.Focus(); + + var focus = FocusManager.Instance?.Current; + + Assert.True(focus == windowTB); + + p.Close(); + + Assert.True(focus == windowTB); + } + } + private IDisposable CreateServices() { return UnitTestApplication.Start(TestServices.StyledWindow.With(windowingPlatform: