diff --git a/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs b/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs index a7c7a17e6a..3e4fee20b7 100644 --- a/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs +++ b/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs @@ -194,10 +194,16 @@ namespace Avalonia.Controls.Primitives // TODO12: mark PrivateAPI or internal. [Unstable("PopupHost is considered an internal API. Use Popup or any Popup-based controls (Flyout, Tooltip) instead.")] public static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver) + => CreatePopupHost(target, dependencyResolver, false); + + internal static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver, bool shouldUseOverlayLayer) { - if (TopLevel.GetTopLevel(target) is { } topLevel && topLevel.PlatformImpl?.CreatePopup() is { } popupImpl) + if (!shouldUseOverlayLayer) { - return new PopupRoot(topLevel, popupImpl, dependencyResolver); + if (TopLevel.GetTopLevel(target) is { } topLevel && topLevel.PlatformImpl?.CreatePopup() is { } popupImpl) + { + return new PopupRoot(topLevel, popupImpl, dependencyResolver); + } } if (OverlayLayer.GetOverlayLayer(target) is { } overlayLayer) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 8f377f44c5..a90b1fb3b6 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -141,8 +141,21 @@ namespace Avalonia.Controls.Primitives public static readonly AttachedProperty TakesFocusFromNativeControlProperty = AvaloniaProperty.RegisterAttached(nameof(TakesFocusFromNativeControl), true); + /// + /// Defines the property. + /// + public static readonly StyledProperty ShouldUseOverlayLayerProperty = + AvaloniaProperty.Register(nameof(ShouldUseOverlayLayer)); + + /// + /// Defines the property. + /// + public static readonly DirectProperty IsUsingOverlayLayerProperty = AvaloniaProperty.RegisterDirect( + nameof(IsUsingOverlayLayer), o => o.IsUsingOverlayLayer); + private bool _isOpenRequested; private bool _ignoreIsOpenChanged; + private bool _isUsingOverlayLayer; private PopupOpenState? _openState; private Action? _popupHostChangedHandler; @@ -386,6 +399,29 @@ namespace Avalonia.Controls.Primitives set => SetValue(TakesFocusFromNativeControlProperty, value); } + /// + /// Gets or sets a value that indicates whether the popup should be shown in the overlay layer of the parent window. + /// + /// + /// When is "false" implementation depends on the platform. + /// Use to get actual popup behavior. + /// This is an equvalent of `OverlayPopups` property of the platform options, but settable independently per each popup. + /// + public bool ShouldUseOverlayLayer + { + get => GetValue(ShouldUseOverlayLayerProperty); + set => SetValue(ShouldUseOverlayLayerProperty, value); + } + + /// + /// Gets a value that indicates whether the popup is shown in the overlay layer of the parent window. + /// + public bool IsUsingOverlayLayer + { + get => _isUsingOverlayLayer; + private set => SetAndRaise(IsUsingOverlayLayerProperty, ref _isUsingOverlayLayer, value); + } + IPopupHost? IPopupHostProvider.PopupHost => Host; event Action? IPopupHostProvider.PopupHostChanged @@ -423,7 +459,7 @@ namespace Avalonia.Controls.Primitives _isOpenRequested = false; - var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver); + var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver, ShouldUseOverlayLayer); var handlerCleanup = new CompositeDisposable(7); UpdateHostSizing(popupHost, topLevel, placementTarget); @@ -541,6 +577,7 @@ namespace Avalonia.Controls.Primitives WindowManagerAddShadowHintChanged(popupHost, WindowManagerAddShadowHint); popupHost.Show(); + IsUsingOverlayLayer = popupHost is OverlayPopupHost; if (TakesFocusFromNativeControl) popupHost.TakeFocus(); diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index 29671f0766..86eb5f83a4 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -1260,6 +1260,38 @@ namespace Avalonia.Controls.UnitTests.Primitives return result; } + [Fact] + public void Popup_Open_With_Correct_IsUsingOverlayLayer_And_Disabled_OverlayLayer() + { + using (CreateServices()) + { + var target = new Popup(); + target.IsOpen = true; + target.ShouldUseOverlayLayer = false; + + var window = PreparedWindow(target); + window.Show(); + + Assert.Equal(UsePopupHost, target.IsUsingOverlayLayer); + } + } + + [Fact] + public void Popup_Open_With_Correct_IsUsingOverlayLayer_And_Enabled_OverlayLayer() + { + using (CreateServices()) + { + var target = new Popup(); + target.IsOpen = true; + target.ShouldUseOverlayLayer = true; + + var window = PreparedWindow(target); + window.Show(); + + Assert.Equal(true, target.IsUsingOverlayLayer); + } + } + private IDisposable CreateServices() { return UnitTestApplication.Start(TestServices.StyledWindow.With(