Browse Source

Merge pull request #4605 from ShadowDancer/fix/allow_opening_popup_when_not_attached

Schedule opening popup if cannot be opened right now
repro/bound-listboxes
Steven Kirk 6 years ago
committed by GitHub
parent
commit
3befd1074a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      src/Avalonia.Controls/Primitives/Popup.cs
  2. 45
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

21
src/Avalonia.Controls/Primitives/Popup.cs

@ -128,6 +128,7 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<bool> TopmostProperty = public static readonly StyledProperty<bool> TopmostProperty =
AvaloniaProperty.Register<Popup, bool>(nameof(Topmost)); AvaloniaProperty.Register<Popup, bool>(nameof(Topmost));
private bool _isOpenRequested = false;
private bool _isOpen; private bool _isOpen;
private bool _ignoreIsOpenChanged; private bool _ignoreIsOpenChanged;
private PopupOpenState? _openState; private PopupOpenState? _openState;
@ -361,17 +362,19 @@ namespace Avalonia.Controls.Primitives
if (placementTarget == null) if (placementTarget == null)
{ {
throw new InvalidOperationException("Popup has no logical parent and PlacementTarget is null"); _isOpenRequested = true;
return;
} }
var topLevel = placementTarget.VisualRoot as TopLevel; var topLevel = placementTarget.VisualRoot as TopLevel;
if (topLevel == null) if (topLevel == null)
{ {
throw new InvalidOperationException( _isOpenRequested = true;
"Attempted to open a popup not attached to a TopLevel"); return;
} }
_isOpenRequested = false;
var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver); var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver);
var handlerCleanup = new CompositeDisposable(5); var handlerCleanup = new CompositeDisposable(5);
@ -492,6 +495,17 @@ namespace Avalonia.Controls.Primitives
return new Size(); return new Size();
} }
/// <inheritdoc/>
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
if (_isOpenRequested)
{
Open();
}
}
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{ {
@ -552,6 +566,7 @@ namespace Avalonia.Controls.Primitives
private void CloseCore() private void CloseCore()
{ {
_isOpenRequested = false;
if (_openState is null) if (_openState is null)
{ {
using (BeginIgnoringIsOpen()) using (BeginIgnoringIsOpen())

45
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@ -21,7 +21,50 @@ namespace Avalonia.Controls.UnitTests.Primitives
public class PopupTests public class PopupTests
{ {
protected bool UsePopupHost; 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()
{
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] [Fact]
public void Setting_Child_Should_Set_Child_Controls_LogicalParent() public void Setting_Child_Should_Set_Child_Controls_LogicalParent()
{ {

Loading…
Cancel
Save