From de5dd5096efb3a52803d4f7cb207b9565020916b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Onak?= Date: Thu, 3 Sep 2020 00:09:52 +0200 Subject: [PATCH 1/2] Schedule opening popup if cannot be opened right now --- src/Avalonia.Controls/Primitives/Popup.cs | 21 ++++++++++++-- .../Primitives/PopupTests.cs | 28 +++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index a676892384..1e5e80d144 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -128,6 +128,7 @@ namespace Avalonia.Controls.Primitives public static readonly StyledProperty TopmostProperty = AvaloniaProperty.Register(nameof(Topmost)); + private bool _isOpenRequested = false; private bool _isOpen; private bool _ignoreIsOpenChanged; private PopupOpenState? _openState; @@ -361,17 +362,19 @@ namespace Avalonia.Controls.Primitives if (placementTarget == null) { - throw new InvalidOperationException("Popup has no logical parent and PlacementTarget is null"); + _isOpenRequested = true; + return; } var topLevel = placementTarget.VisualRoot as TopLevel; if (topLevel == null) { - throw new InvalidOperationException( - "Attempted to open a popup not attached to a TopLevel"); + _isOpenRequested = true; + return; } + _isOpenRequested = false; var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver); var handlerCleanup = new CompositeDisposable(5); @@ -492,6 +495,17 @@ namespace Avalonia.Controls.Primitives return new Size(); } + + /// + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + if (_isOpenRequested) + { + Open(); + } + } + /// protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) { @@ -552,6 +566,7 @@ namespace Avalonia.Controls.Primitives private void CloseCore() { + _isOpenRequested = false; if (_openState is null) { using (BeginIgnoringIsOpen()) diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index d9176ca55d..73871cf79f 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -22,6 +22,34 @@ namespace Avalonia.Controls.UnitTests.Primitives { protected bool UsePopupHost; + + [Fact] + public void Popup_Without_TopLevel_Shouldnt_Call_Open() + { + int openedEvent = 0; + var target = new Popup(); + target.Opened += (s, a) => openedEvent++; + target.IsOpen = true; + + Assert.Equal(0, openedEvent); + } + + [Fact] + public void Opening_Popup_Shouldnt_Throw_When_Not_In_Visual_Tree() + { + var target = new Popup(); + target.IsOpen = true; + } + + [Fact] + public void Opening_Popup_Shouldnt_Throw_When_In_Tree_Without_TopLevel() + { + Control c = new Control(); + var target = new Popup(); + ((ISetLogicalParent)target).SetParent(c); + target.IsOpen = true; + } + [Fact] public void Setting_Child_Should_Set_Child_Controls_LogicalParent() { From db98c340d65532b136750cae5f5379c54b7c64a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Onak?= Date: Thu, 3 Sep 2020 20:47:52 +0200 Subject: [PATCH 2/2] Add test to check if popup is displayed correctly after window is shown --- .../Primitives/PopupTests.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index 73871cf79f..5bad646aa7 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -21,7 +21,22 @@ namespace Avalonia.Controls.UnitTests.Primitives public class PopupTests { protected bool UsePopupHost; - + + [Fact] + public void Popup_Open_Without_Target_Should_Attach_Itself_Later() + { + using (CreateServices()) + { + int openedEvent = 0; + var target = new Popup(); + target.Opened += (s, a) => openedEvent++; + target.IsOpen = true; + + var window = PreparedWindow(target); + window.Show(); + Assert.Equal(1, openedEvent); + } + } [Fact] public void Popup_Without_TopLevel_Shouldnt_Call_Open()