Browse Source

Schedule opening popup if cannot be opened right now

Przemysław Onak 5 years ago
parent
commit
de5dd5096e

+ 18 - 3
src/Avalonia.Controls/Primitives/Popup.cs

@@ -128,6 +128,7 @@ namespace Avalonia.Controls.Primitives
         public static readonly StyledProperty<bool> TopmostProperty =
             AvaloniaProperty.Register<Popup, bool>(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();
         }
 
+
+        /// <inheritdoc/>
+        protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+        {
+            base.OnAttachedToVisualTree(e);
+            if (_isOpenRequested)
+            {
+                Open();
+            }
+        }
+
         /// <inheritdoc/>
         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())

+ 28 - 0
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()
         {