Files
zeling_v2/Assets/_Game/Scripts/UI/Navigation/UIResultPanel.cs
2026-06-07 11:49:55 +08:00

61 lines
2.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Threading;
using System.Threading.Tasks;
namespace BaseGames.UI
{
/// <summary>
/// 返回结果的模态面板基类(确认框、模式 / 难度选择等)。
///
/// <para>用法(调用方走线性 await无回调嵌套</para>
/// <code>
/// bool ok = await _confirmDialog.ShowAsync("CONFIRM_OVERWRITE_TITLE", "CONFIRM_OVERWRITE_BODY", ct);
/// if (!ok) return;
/// </code>
///
/// <para>结果通道由 <see cref="TaskCompletionSource{T}"/> 承载,并对所有"提前结束"路径兜底
/// ESC 取消出栈、外部强关、所属场景卸载、CancellationToken 取消),保证 await 绝不悬挂。</para>
/// </summary>
public abstract class UIResultPanel<T> : UIPanelBase
{
private TaskCompletionSource<T> _tcs;
private CancellationTokenRegistration _ctReg;
/// <summary>取消 / 默认结果ESC、返回、销毁、场景卸载、ct 取消时以此完成。</summary>
protected abstract T CancelResult { get; }
/// <summary>由导航器 <see cref="IUINavigator.PushForResultAsync{T}"/> 调用:开启一轮结果等待。</summary>
internal Task<T> BeginResult(CancellationToken ct)
{
// 复用面板:若上一轮仍未决,先以默认值收口,避免句柄泄漏。
ResolvePending();
_tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
_ctReg = ct.CanBeCanceled ? ct.Register(ResolvePending) : default;
return _tcs.Task;
}
/// <summary>具体按钮回调:以 <paramref name="result"/> 完成并出栈自身。</summary>
protected void Complete(T result)
{
var tcs = _tcs;
if (tcs != null && tcs.TrySetResult(result))
{
_ctReg.Dispose();
GetService<IUINavigator>()?.Pop(); // 弹出自己(栈顶)
}
}
/// <summary>以取消默认值收口未决结果(幂等)。</summary>
private void ResolvePending()
{
var tcs = _tcs;
if (tcs != null && tcs.TrySetResult(CancelResult))
_ctReg.Dispose();
}
// 出栈(含 ESC 取消)会 SetActive(false) → OnDisable → OnPanelClose
// 场景卸载 / 销毁同样经 OnDisable。统一在此兜底覆盖所有提前结束路径。
protected override void OnPanelClose() => ResolvePending();
}
}