diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 81d01ff74f..63f3fb647b 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -68,6 +68,7 @@ namespace Avalonia.Controls.Primitives private PopupRoot _popupRoot; private TopLevel _topLevel; private IDisposable _nonClientListener; + bool _ignoreIsOpenChanged = false; /// /// Initializes static members of the class. @@ -220,7 +221,11 @@ namespace Avalonia.Controls.Primitives PopupRootCreated?.Invoke(this, EventArgs.Empty); _popupRoot.Show(); + + _ignoreIsOpenChanged = true; IsOpen = true; + _ignoreIsOpenChanged = false; + Opened?.Invoke(this, EventArgs.Empty); } @@ -268,8 +273,13 @@ namespace Avalonia.Controls.Primitives { base.OnDetachedFromLogicalTree(e); _topLevel = null; - _popupRoot?.Dispose(); - _popupRoot = null; + + if (_popupRoot != null) + { + ((ISetLogicalParent)_popupRoot).SetParent(null); + _popupRoot.Dispose(); + _popupRoot = null; + } } /// @@ -278,13 +288,16 @@ namespace Avalonia.Controls.Primitives /// The event args. private void IsOpenChanged(AvaloniaPropertyChangedEventArgs e) { - if ((bool)e.NewValue) - { - Open(); - } - else + if (!_ignoreIsOpenChanged) { - Close(); + if ((bool)e.NewValue) + { + Open(); + } + else + { + Close(); + } } } diff --git a/src/Avalonia.Themes.Default/DropDown.xaml b/src/Avalonia.Themes.Default/DropDown.xaml index c33e4af4f4..5a3d44360c 100644 --- a/src/Avalonia.Themes.Default/DropDown.xaml +++ b/src/Avalonia.Themes.Default/DropDown.xaml @@ -10,10 +10,10 @@ BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> - + { }; + + root.Child = null; + + Assert.False(((ILogical)target).IsAttachedToLogicalTree); + Assert.False(((ILogical)rectangle).IsAttachedToLogicalTree); + } + private FuncControlTemplate GetTemplate() { return new FuncControlTemplate(parent => @@ -26,8 +71,7 @@ namespace Avalonia.Controls.UnitTests { new ContentControl { - Name = "contentControl", - [~ContentPresenter.ContentProperty] = parent[~DropDown.SelectionBoxItemProperty], + [!ContentControl.ContentProperty] = parent[!DropDown.SelectionBoxItemProperty], }, new ToggleButton { @@ -35,7 +79,12 @@ namespace Avalonia.Controls.UnitTests }, new Popup { - Name = "popup", + Name = "PART_Popup", + Child = new ItemsPresenter + { + Name = "PART_ItemsPresenter", + [!ItemsPresenter.ItemsProperty] = parent[!DropDown.ItemsProperty], + } } } }; diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index 5581087b5f..13d97920ee 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -166,6 +166,24 @@ namespace Avalonia.Controls.UnitTests.Primitives } } + [Fact] + public void PopupRoot_Should_Be_Detached_From_Logical_Tree_When_Popup_Is_Detached() + { + using (CreateServices()) + { + var target = new Popup(); + var root = new TestRoot { Child = target }; + + target.Open(); + + var popupRoot = (ILogical)target.PopupRoot; + + Assert.True(popupRoot.IsAttachedToLogicalTree); + root.Child = null; + Assert.False(((ILogical)target).IsAttachedToLogicalTree); + } + } + [Fact] public void PopupRoot_Should_Have_Template_Applied() {