From 4c1edc2d1e3a6418fa61982bd683ac32b718e21e Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Wed, 5 Feb 2025 11:16:35 -0500 Subject: [PATCH] Fix - Complete window dialog task when dialog is hidden (#18047) * complete window dialog task when dialog is hidden * change window IsVisible behavior for dialogs to hide window instead. update tests * unset owner before hiding window to prevent OS from updating owner visibility or window order --- src/Avalonia.Controls/Window.cs | 51 ++++++++++--------- .../WindowTests.cs | 10 +--- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 2b21c1f37b..9b0428d446 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -201,6 +201,7 @@ namespace Avalonia.Controls private bool _showingAsDialog; private bool _positionWasSet; private bool _wasShownBefore; + private IDisposable? _modalSubscription; /// /// Initializes static members of the class. @@ -612,11 +613,12 @@ namespace Avalonia.Controls } } + Owner = null; PlatformImpl?.Hide(); IsVisible = false; - _shown = false; - Owner = null; + _modalSubscription?.Dispose(); + _shown = false; } } @@ -645,14 +647,7 @@ namespace Avalonia.Controls } else { - if (_showingAsDialog) - { - Close(false); - } - else - { - Hide(); - } + Hide(); } } } @@ -706,7 +701,7 @@ namespace Avalonia.Controls using (FreezeVisibilityChangeHandling()) { EnsureStateBeforeShow(); - + if (modal && owner == null) { throw new ArgumentNullException(nameof(owner)); @@ -738,14 +733,14 @@ namespace Avalonia.Controls var initialSize = new Size( double.IsNaN(Width) ? ClientSize.Width : Width, double.IsNaN(Height) ? ClientSize.Height : Height); - + initialSize = new Size( MathUtilities.Clamp(initialSize.Width, MinWidth, MaxWidth), MathUtilities.Clamp(initialSize.Height, MinHeight, MaxHeight)); var clientSizeChanged = initialSize != ClientSize; ClientSize = initialSize; // ClientSize is required for Measure and Arrange - + // this will call ArrangeSetBounds LayoutManager.ExecuteInitialLayoutPass(); @@ -762,21 +757,21 @@ namespace Avalonia.Controls clientSizeChanged |= initialSize != ClientSize; ClientSize = initialSize; } - + Owner = owner; SetWindowStartupLocation(owner); - + DesktopScalingOverride = null; - + if (clientSizeChanged || ClientSize != PlatformImpl?.ClientSize) { // Previously it was called before ExecuteInitialLayoutPass PlatformImpl?.Resize(ClientSize, WindowResizeReason.Layout); - + // we do not want PlatformImpl?.Resize to trigger HandleResized yet because it will set Width and Height. // So perform some important actions from HandleResized - + Renderer.Resized(ClientSize); OnResized(new WindowResizedEventArgs(ClientSize, WindowResizeReason.Layout)); @@ -788,8 +783,8 @@ namespace Avalonia.Controls FrameSize = PlatformImpl?.FrameSize; - _canHandleResized = true; - + _canHandleResized = true; + StartRendering(); PlatformImpl?.Show(ShowActivated, modal); @@ -798,22 +793,32 @@ namespace Avalonia.Controls { var tcs = new TaskCompletionSource(); - Observable.FromEventPattern( + var disposables = new CompositeDisposable( + [ + Observable.FromEventPattern( x => Closed += x, x => Closed -= x) .Take(1) .Subscribe(_ => { + _modalSubscription?.Dispose(); + }), + Disposable.Create(() => + { + _modalSubscription = null; owner!.Activate(); tcs.SetResult((TResult)(_dialogResult ?? default(TResult)!)); - }); + }) + ]); + + _modalSubscription = disposables; result = tcs.Task; } OnOpened(EventArgs.Empty); if (!modal) _wasShownBefore = true; - + return result; } } diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index 30d9cec449..705076ff25 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -1060,7 +1060,7 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void IsVisible_Should_Close_DialogWindow() + public void Hiding_DialogWindow_Should_Complete_Task() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { @@ -1068,18 +1068,12 @@ namespace Avalonia.Controls.UnitTests parent.Show(); var target = new Window(); - - var raised = false; var task = target.ShowDialog(parent); - - target.Closed += (sender, args) => raised = true; target.IsVisible = false; - - Assert.True(raised); - Assert.False(task.Result); + Assert.True(task.IsCompletedSuccessfully); } }