feat(Dialog): improve closing logic and ensure proper cleanup of dialog state

This commit is contained in:
chinboy
2026-06-11 15:48:51 +08:00
parent 4ce8059a82
commit af3dd35ae4
3 changed files with 55 additions and 16 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "10.0.301",
"version": "10.0.300",
"rollForward": "latestFeature"
}
}
+44 -11
View File
@@ -605,6 +605,7 @@ public partial class Dialog : TemplatedControl,
}
_closing = true;
var closeCompletionPending = false;
try
{
if (Result is DialogCode code)
@@ -625,28 +626,50 @@ public partial class Dialog : TemplatedControl,
dialogAwareDataContext.NotifyClosed();
}
var result = Result;
var openState = _openState;
_openState = null;
_openState = null;
_dialogHostChangedHandler?.Invoke(null);
openState?.Dispose();
using (BeginIgnoringIsOpen())
{
SetCurrentValue(IsOpenProperty, false);
}
Closed?.Invoke(this, EventArgs.Empty);
_frameCancellationTokenSource?.Cancel();
_frameCancellationTokenSource?.Dispose();
_frameCancellationTokenSource = null;
openState?.SetClosed(Result);
if (openState is not null)
{
var closeCompletedSynchronously = false;
openState.Close(() =>
{
closeCompletedSynchronously = true;
CompleteClose(openState, result);
});
closeCompletionPending = !closeCompletedSynchronously;
}
else
{
CompleteClose(null, result);
}
}
finally
{
_closing = false;
if (!closeCompletionPending)
{
_closing = false;
}
}
}
private void CompleteClose(DialogOpenState? openState, object? result)
{
openState?.SetClosed(result);
Closed?.Invoke(this, EventArgs.Empty);
_frameCancellationTokenSource?.Cancel();
_frameCancellationTokenSource?.Dispose();
_frameCancellationTokenSource = null;
_closing = false;
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@@ -804,7 +827,8 @@ public partial class Dialog : TemplatedControl,
private class DialogOpenState : IDisposable
{
private readonly IDisposable _cleanup;
private readonly TaskCompletionSource<object?> _closedTaskSource = new();
private readonly TaskCompletionSource<object?> _closedTaskSource =
new(TaskCreationOptions.RunContinuationsAsynchronously);
public DialogOpenState(IDialogHost dialogHost,
IDisposable cleanup)
@@ -821,10 +845,19 @@ public partial class Dialog : TemplatedControl,
_closedTaskSource.TrySetResult(result);
}
public void Dispose()
public void Close(Action? closedCallback = null)
{
_cleanup.Dispose();
DialogHost.Close(() => DialogHost.Content = null);
DialogHost.Close(() =>
{
DialogHost.Content = null;
closedCallback?.Invoke();
});
}
public void Dispose()
{
Close();
}
}
@@ -291,11 +291,17 @@ internal class DialogHost : Window,
_confirmLoadingBindings?.Dispose();
_confirmLoadingBindings = null;
_dialogContent.ReleaseButtonBox();
Closed += HandleClosed;
base.Close();
// 与 BindDialog 里 SetParent(dialog) 对称:释放 Dialog ↔ DialogHost 的 logical
// parent/child 引用,避免关闭后双方互锁无法 GC。
((ISetLogicalParent)this).SetParent(null);
callback?.Invoke();
void HandleClosed(object? sender, EventArgs args)
{
Closed -= HandleClosed;
// 与 BindDialog 里 SetParent(dialog) 对称:释放 Dialog ↔ DialogHost 的 logical
// parent/child 引用,避免关闭后双方互锁无法 GC。
((ISetLogicalParent)this).SetParent(null);
callback?.Invoke();
}
}
private void BindContentProperties()