refactor(scene): 将场景路由异步方法改为await调用

- 将SceneRouterBase中的AfterChange方法改为异步方法AfterChangeAsync
- 修改SceneRouterBase中的场景切换流程使用await调用异步方法
- 移除后台线程执行,直接使用同步await调用
- 更新日志记录逻辑,优化调试信息输出
- 简化异常处理流程,统一异步执行模式
This commit is contained in:
GeWuYou 2026-02-21 08:42:18 +08:00 committed by gewuyou
parent 7015ba118d
commit 608251047c
4 changed files with 208 additions and 119 deletions

View File

@ -25,7 +25,8 @@ public interface IUiRouter : ISystem
/// <param name="uiKey">UI界面的唯一标识符</param>
/// <param name="param">进入界面的参数,可为空</param>
/// <param name="policy">界面切换策略默认为Exclusive独占</param>
void Push(string uiKey, IUiPageEnterParam? param = null, UiTransitionPolicy policy = UiTransitionPolicy.Exclusive);
ValueTask PushAsync(string uiKey, IUiPageEnterParam? param = null,
UiTransitionPolicy policy = UiTransitionPolicy.Exclusive);
/// <summary>
@ -35,7 +36,7 @@ public interface IUiRouter : ISystem
/// <param name="page">已创建的UI页面行为实例</param>
/// <param name="param">进入界面的参数,可为空</param>
/// <param name="policy">界面切换策略,默认为Exclusive(独占)</param>
void Push(IUiPageBehavior page, IUiPageEnterParam? param = null,
ValueTask PushAsync(IUiPageBehavior page, IUiPageEnterParam? param = null,
UiTransitionPolicy policy = UiTransitionPolicy.Exclusive);
@ -43,7 +44,7 @@ public interface IUiRouter : ISystem
/// 弹出路由栈顶的UI界面返回到上一个界面
/// </summary>
/// <param name="policy">界面弹出策略默认为Destroy销毁</param>
void Pop(UiPopPolicy policy = UiPopPolicy.Destroy);
ValueTask PopAsync(UiPopPolicy policy = UiPopPolicy.Destroy);
/// <summary>
/// 替换当前所有页面为新页面基于uiKey
@ -52,7 +53,7 @@ public interface IUiRouter : ISystem
/// <param name="param">页面进入参数,可为空</param>
/// <param name="popPolicy">弹出页面时的销毁策略,默认为销毁</param>
/// <param name="pushPolicy">推入页面时的过渡策略,默认为独占</param>
public void Replace(
public ValueTask ReplaceAsync(
string uiKey,
IUiPageEnterParam? param = null,
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
@ -65,7 +66,7 @@ public interface IUiRouter : ISystem
/// <param name="param">页面进入参数,可为空</param>
/// <param name="popPolicy">弹出页面时的销毁策略,默认为销毁</param>
/// <param name="pushPolicy">推入页面时的过渡策略,默认为独占</param>
public void Replace(
public ValueTask ReplaceAsync(
IUiPageBehavior page,
IUiPageEnterParam? param = null,
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
@ -74,7 +75,7 @@ public interface IUiRouter : ISystem
/// <summary>
/// 清空所有UI界面重置路由状态
/// </summary>
void Clear();
ValueTask ClearAsync();
/// <summary>
/// 注册UI切换处理器

View File

@ -96,7 +96,7 @@ public abstract class SceneRouterBase
await BeforeChangeAsync(@event);
await ClearInternalAsync();
await PushInternalAsync(sceneKey, param);
AfterChange(@event);
await AfterChangeAsync(@event);
});
}
finally
@ -237,7 +237,7 @@ public abstract class SceneRouterBase
{
await BeforeChangeAsync(@event);
await PushInternalAsync(sceneKey, param);
AfterChange(@event);
await AfterChangeAsync(@event);
});
}
finally
@ -318,7 +318,7 @@ public abstract class SceneRouterBase
{
await BeforeChangeAsync(@event);
await PopInternalAsync();
AfterChange(@event);
await AfterChangeAsync(@event);
});
}
finally
@ -389,7 +389,7 @@ public abstract class SceneRouterBase
{
await BeforeChangeAsync(@event);
await ClearInternalAsync();
AfterChange(@event);
await AfterChangeAsync(@event);
});
}
finally
@ -451,25 +451,13 @@ public abstract class SceneRouterBase
/// <summary>
/// 执行转换后阶段的处理逻辑。
/// 在后台线程中异步执行,避免阻塞主线程。
/// </summary>
/// <param name="event">场景转换事件。</param>
private void AfterChange(SceneTransitionEvent @event)
private async Task AfterChangeAsync(SceneTransitionEvent @event)
{
Log.Debug("AfterChange phases started: {0}", @event.TransitionType);
_ = Task.Run(async () =>
{
try
{
await _pipeline.ExecuteAsync(@event, SceneTransitionPhases.AfterChange);
Log.Debug("AfterChange phases completed: {0}", @event.TransitionType);
}
catch (Exception ex)
{
Log.Error("AfterChange phases failed: {0}, Error: {1}",
@event.TransitionType, ex.Message);
}
});
await _pipeline.ExecuteAsync(@event, SceneTransitionPhases.AfterChange);
Log.Debug("AfterChange phases completed: {0}", @event.TransitionType);
}
/// <summary>

View File

@ -122,15 +122,14 @@ public class SceneTransitionPipeline
{
@event.Set("Phases", phases.ToString());
if (@event.FromSceneKey != null)
Log.Debug(
"Execute pipeline: Phases={0}, From={1}, To={2}, Type={3}, HandlerCount={4}",
phases,
@event.FromSceneKey,
@event.ToSceneKey ?? "None",
@event.TransitionType,
_handlers.Count
);
Log.Debug(
"Execute pipeline: Phases={0}, From={1}, To={2}, Type={3}, HandlerCount={4}",
phases,
@event.FromSceneKey ?? "None",
@event.ToSceneKey ?? "None",
@event.TransitionType,
_handlers.Count
);
var sortedHandlers = FilterAndSortHandlers(@event, phases);

View File

@ -8,64 +8,72 @@ using GFramework.Game.Abstractions.ui;
namespace GFramework.Game.ui;
/// <summary>
/// UI路由类提供页面栈管理功能
/// UI路由基类提供页面栈管理和层级UI管理功能
/// 负责UI页面的导航、显示、隐藏以及生命周期管理
/// </summary>
public abstract class UiRouterBase : AbstractSystem, IUiRouter
{
private static readonly ILogger Log = LoggerFactoryResolver.Provider.CreateLogger(nameof(UiRouterBase));
/// <summary>
/// 路由守卫列表
/// 路由守卫列表用于控制UI页面的进入和离开
/// </summary>
private readonly List<IUiRouteGuard> _guards = new();
/// <summary>
/// 层级管理非栈层级用于Overlay、Modal、Toast等浮层
/// Key: UiLayer, Value: Dictionary of InstanceId -> PageBehavior
/// 层级管理字典(非栈层级),用于管理Overlay、Modal、Toast等浮层UI
/// Key: UiLayer枚举值, Value: InstanceId到PageBehavior的映射字典
/// </summary>
private readonly Dictionary<UiLayer, Dictionary<string, IUiPageBehavior>> _layers = new();
/// <summary>
/// UI切换处理器管道
/// UI切换处理器管道用于执行UI过渡动画和逻辑
/// </summary>
private readonly UiTransitionPipeline _pipeline = new();
/// <summary>
/// 页面栈用于管理UI页面的显示顺序
/// 页面栈用于管理UI页面的显示顺序和导航历史
/// </summary>
private readonly Stack<IUiPageBehavior> _stack = new();
/// <summary>
/// UI工厂实例用于创建UI相关对象
/// UI工厂实例用于创建UI页面和相关对象
/// </summary>
private IUiFactory _factory = null!;
/// <summary>
/// 实例ID计数器用于生成唯一ID
/// 实例ID计数器用于生成唯一的UI实例标识符
/// </summary>
private int _instanceCounter;
/// <summary>
/// UI根节点引用用于添加和移除UI页面
/// </summary>
private IUiRoot _uiRoot = null!;
/// <summary>
/// 注册UI切换处理器
/// 注册UI切换处理器
/// </summary>
/// <param name="handler">UI切换处理器实例</param>
/// <param name="options">处理器选项配置</param>
public void RegisterHandler(IUiTransitionHandler handler, UiTransitionHandlerOptions? options = null)
{
_pipeline.RegisterHandler(handler, options);
}
/// <summary>
/// 注销UI切换处理器
/// 注销UI切换处理器
/// </summary>
/// <param name="handler">要注销的UI切换处理器实例</param>
public void UnregisterHandler(IUiTransitionHandler handler)
{
_pipeline.UnregisterHandler(handler);
}
/// <summary>
/// 绑定UI根节点
/// 绑定UI根节点
/// </summary>
/// <param name="root">UI根节点实例</param>
public void BindRoot(IUiRoot root)
{
_uiRoot = root;
@ -75,9 +83,12 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
#region Page Stack Management
/// <summary>
/// 将指定的UI界面压入路由栈
/// 将指定的UI界面压入路由栈
/// </summary>
public void Push(string uiKey, IUiPageEnterParam? param = null,
/// <param name="uiKey">UI页面的唯一标识键</param>
/// <param name="param">页面进入参数</param>
/// <param name="policy">UI过渡策略</param>
public async ValueTask PushAsync(string uiKey, IUiPageEnterParam? param = null,
UiTransitionPolicy policy = UiTransitionPolicy.Exclusive)
{
if (IsTop(uiKey))
@ -89,18 +100,21 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
var @event = CreateEvent(uiKey, UiTransitionType.Push, policy, param);
Log.Debug("Push UI Page: key={0}, policy={1}, stackBefore={2}", uiKey, policy, _stack.Count);
_pipeline.ExecuteAroundAsync(@event, async () =>
await _pipeline.ExecuteAroundAsync(@event, async () =>
{
BeforeChange(@event);
DoPushPageInternal(uiKey, param, policy);
AfterChange(@event);
}).GetAwaiter().GetResult();
await BeforeChangeAsync(@event);
await DoPushPageInternalAsync(uiKey, param, policy);
await AfterChangeAsync(@event);
});
}
/// <summary>
/// 将已存在的UI页面压入栈顶
/// 将已存在的UI页面压入栈顶
/// </summary>
public void Push(IUiPageBehavior page, IUiPageEnterParam? param = null,
/// <param name="page">已存在的UI页面行为实例</param>
/// <param name="param">页面进入参数</param>
/// <param name="policy">UI过渡策略</param>
public async ValueTask PushAsync(IUiPageBehavior page, IUiPageEnterParam? param = null,
UiTransitionPolicy policy = UiTransitionPolicy.Exclusive)
{
var uiKey = page.Key;
@ -114,18 +128,19 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
var @event = CreateEvent(uiKey, UiTransitionType.Push, policy, param);
Log.Debug("Push existing UI Page: key={0}, policy={1}, stackBefore={2}", uiKey, policy, _stack.Count);
_pipeline.ExecuteAroundAsync(@event, async () =>
await _pipeline.ExecuteAroundAsync(@event, async () =>
{
BeforeChange(@event);
await BeforeChangeAsync(@event);
DoPushPageInternal(page, param, policy);
AfterChange(@event);
}).GetAwaiter().GetResult();
await AfterChangeAsync(@event);
});
}
/// <summary>
/// 弹出栈顶页面
/// 弹出栈顶页面
/// </summary>
public void Pop(UiPopPolicy policy = UiPopPolicy.Destroy)
/// <param name="policy">页面弹出策略</param>
public async ValueTask PopAsync(UiPopPolicy policy = UiPopPolicy.Destroy)
{
if (_stack.Count == 0)
{
@ -135,7 +150,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
var leavingUiKey = _stack.Peek().Key;
if (!ExecuteLeaveGuardsAsync(leavingUiKey).GetAwaiter().GetResult())
if (!await ExecuteLeaveGuardsAsync(leavingUiKey))
{
Log.Warn("Pop blocked by guard: {0}", leavingUiKey);
return;
@ -144,41 +159,49 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
var nextUiKey = _stack.Count > 1 ? _stack.ElementAt(1).Key : null;
var @event = CreateEvent(nextUiKey, UiTransitionType.Pop);
_pipeline.ExecuteAroundAsync(@event, async () =>
await _pipeline.ExecuteAroundAsync(@event, async () =>
{
BeforeChange(@event);
await BeforeChangeAsync(@event);
DoPopInternal(policy);
AfterChange(@event);
}).GetAwaiter().GetResult();
await AfterChangeAsync(@event);
});
}
/// <summary>
/// 替换当前所有页面为新页面基于uiKey
/// 替换当前所有页面为新页面基于uiKey
/// </summary>
public void Replace(string uiKey, IUiPageEnterParam? param = null,
/// <param name="uiKey">新UI页面的唯一标识键</param>
/// <param name="param">页面进入参数</param>
/// <param name="popPolicy">页面弹出策略</param>
/// <param name="pushPolicy">页面压入策略</param>
public async ValueTask ReplaceAsync(string uiKey, IUiPageEnterParam? param = null,
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive)
{
var @event = CreateEvent(uiKey, UiTransitionType.Replace, pushPolicy, param);
Log.Debug("Replace UI Stack with page: key={0}, popPolicy={1}, pushPolicy={2}", uiKey, popPolicy, pushPolicy);
_pipeline.ExecuteAroundAsync(@event, async () =>
await _pipeline.ExecuteAroundAsync(@event, async () =>
{
BeforeChange(@event);
await BeforeChangeAsync(@event);
DoClearInternal(popPolicy);
var page = _factory.Create(uiKey);
Log.Debug("Get/Create UI Page instance for Replace: {0}", page.GetType().Name);
DoPushPageInternal(page, param, pushPolicy);
AfterChange(@event);
}).GetAwaiter().GetResult();
await AfterChangeAsync(@event);
});
}
/// <summary>
/// 替换当前所有页面为已存在的页面
/// 替换当前所有页面为已存在的页面
/// </summary>
public void Replace(IUiPageBehavior page, IUiPageEnterParam? param = null,
/// <param name="page">已存在的UI页面行为实例</param>
/// <param name="param">页面进入参数</param>
/// <param name="popPolicy">页面弹出策略</param>
/// <param name="pushPolicy">页面压入策略</param>
public async ValueTask ReplaceAsync(IUiPageBehavior page, IUiPageEnterParam? param = null,
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive)
{
@ -187,66 +210,72 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
Log.Debug("Replace UI Stack with existing page: key={0}, popPolicy={1}, pushPolicy={2}",
uiKey, popPolicy, pushPolicy);
_pipeline.ExecuteAroundAsync(@event, async () =>
await _pipeline.ExecuteAroundAsync(@event, async () =>
{
BeforeChange(@event);
await BeforeChangeAsync(@event);
DoClearInternal(popPolicy);
Log.Debug("Use existing UI Page instance for Replace: {0}", page.GetType().Name);
DoPushPageInternal(page, param, pushPolicy);
AfterChange(@event);
}).GetAwaiter().GetResult();
await AfterChangeAsync(@event);
});
}
/// <summary>
/// 清空所有页面栈
/// 清空所有页面栈
/// </summary>
public void Clear()
public async ValueTask ClearAsync()
{
var @event = CreateEvent(string.Empty, UiTransitionType.Clear);
Log.Debug("Clear UI Stack, stackCount={0}", _stack.Count);
_pipeline.ExecuteAroundAsync(@event, async () =>
await _pipeline.ExecuteAroundAsync(@event, async () =>
{
BeforeChange(@event);
await BeforeChangeAsync(@event);
DoClearInternal(UiPopPolicy.Destroy);
AfterChange(@event);
}).GetAwaiter().GetResult();
await AfterChangeAsync(@event);
});
}
/// <summary>
/// 获取栈顶元素的键值
/// 获取栈顶元素的键值
/// </summary>
/// <returns>栈顶UI页面的键值如果栈为空则返回空字符串</returns>
public string PeekKey()
{
return _stack.Count == 0 ? string.Empty : _stack.Peek().Key;
}
/// <summary>
/// 获取栈顶元素
/// 获取栈顶元素
/// </summary>
/// <returns>栈顶UI页面行为实例如果栈为空则返回null</returns>
public IUiPageBehavior? Peek()
{
return _stack.Count == 0 ? null : _stack.Peek();
}
/// <summary>
/// 判断栈顶是否为指定UI
/// 判断栈顶是否为指定UI
/// </summary>
/// <param name="uiKey">要检查的UI页面键值</param>
/// <returns>如果栈顶是指定UI则返回true否则返回false</returns>
public bool IsTop(string uiKey)
{
return _stack.Count != 0 && _stack.Peek().Key.Equals(uiKey);
}
/// <summary>
/// 判断栈中是否包含指定UI
/// 判断栈中是否包含指定UI
/// </summary>
/// <param name="uiKey">要检查的UI页面键值</param>
/// <returns>如果栈中包含指定UI则返回true否则返回false</returns>
public bool Contains(string uiKey)
{
return _stack.Any(p => p.Key.Equals(uiKey));
}
/// <summary>
/// 获取栈深度
/// 获取栈深度
/// </summary>
public int Count => _stack.Count;
@ -255,8 +284,13 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
#region Layer UI Management
/// <summary>
/// 在指定层级显示UI基于 uiKey
/// 在指定层级显示UI基于 uiKey
/// </summary>
/// <param name="uiKey">UI页面的唯一标识键</param>
/// <param name="layer">UI显示层级</param>
/// <param name="param">页面进入参数</param>
/// <returns>UI句柄实例</returns>
/// <exception cref="ArgumentException">当尝试在Page层级使用此方法时抛出</exception>
public UiHandle Show(string uiKey, UiLayer layer, IUiPageEnterParam? param = null)
{
if (layer == UiLayer.Page)
@ -269,8 +303,12 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 在指定层级显示UI基于实例
/// 在指定层级显示UI基于实例
/// </summary>
/// <param name="page">UI页面行为实例</param>
/// <param name="layer">UI显示层级</param>
/// <returns>UI句柄实例</returns>
/// <exception cref="ArgumentException">当尝试在Page层级使用此方法时抛出</exception>
public UiHandle Show(IUiPageBehavior page, UiLayer layer)
{
if (layer == UiLayer.Page)
@ -280,8 +318,11 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 隐藏指定层级的UI
/// 隐藏指定层级的UI
/// </summary>
/// <param name="handle">UI句柄</param>
/// <param name="layer">UI层级</param>
/// <param name="destroy">是否销毁UI实例默认为false</param>
public void Hide(UiHandle handle, UiLayer layer, bool destroy = false)
{
if (!_layers.TryGetValue(layer, out var layerDict))
@ -305,8 +346,10 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 恢复指定UI的显示
/// 恢复指定UI的显示
/// </summary>
/// <param name="handle">UI句柄</param>
/// <param name="layer">UI层级</param>
public void Resume(UiHandle handle, UiLayer layer)
{
if (!_layers.TryGetValue(layer, out var layerDict))
@ -321,8 +364,10 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 清空指定层级的所有UI
/// 清空指定层级的所有UI
/// </summary>
/// <param name="layer">要清空的UI层级</param>
/// <param name="destroy">是否销毁UI实例默认为false</param>
public void ClearLayer(UiLayer layer, bool destroy = false)
{
if (!_layers.TryGetValue(layer, out var layerDict))
@ -343,8 +388,11 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 获取指定层级的UI实例
/// 获取指定层级的UI实例
/// </summary>
/// <param name="handle">UI句柄</param>
/// <param name="layer">UI层级</param>
/// <returns>如果找到则返回UI句柄否则返回null</returns>
public UiHandle? GetFromLayer(UiHandle handle, UiLayer layer)
{
if (!_layers.TryGetValue(layer, out var layerDict))
@ -354,8 +402,11 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 获取指定 uiKey 在指定层级的所有实例
/// 获取指定 uiKey 在指定层级的所有实例
/// </summary>
/// <param name="uiKey">UI页面的唯一标识键</param>
/// <param name="layer">UI层级</param>
/// <returns>指定UI在该层级的所有实例句柄列表</returns>
public IReadOnlyList<UiHandle> GetAllFromLayer(string uiKey, UiLayer layer)
{
if (!_layers.TryGetValue(layer, out var layerDict))
@ -368,8 +419,11 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 判断指定UI是否在层级中可见
/// 判断指定UI是否在层级中可见
/// </summary>
/// <param name="handle">UI句柄</param>
/// <param name="layer">UI层级</param>
/// <returns>如果UI在层级中且可见则返回true否则返回false</returns>
public bool HasVisibleInLayer(UiHandle handle, UiLayer layer)
{
if (!_layers.TryGetValue(layer, out var layerDict))
@ -382,7 +436,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 根据UI键隐藏指定层级中的UI。
/// 根据UI键隐藏指定层级中的UI。
/// </summary>
/// <param name="uiKey">UI的唯一标识键。</param>
/// <param name="layer">要操作的UI层级。</param>
@ -407,8 +461,10 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
#region Route Guards
/// <summary>
/// 注册路由守卫
/// 注册路由守卫
/// </summary>
/// <param name="guard">路由守卫实例</param>
/// <exception cref="ArgumentNullException">当守卫实例为null时抛出</exception>
public void AddGuard(IUiRouteGuard guard)
{
ArgumentNullException.ThrowIfNull(guard);
@ -425,16 +481,19 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 注册路由守卫(泛型)
/// 注册路由守卫(泛型)
/// </summary>
/// <typeparam name="T">路由守卫类型必须实现IUiRouteGuard接口且有无参构造函数</typeparam>
public void AddGuard<T>() where T : IUiRouteGuard, new()
{
AddGuard(new T());
}
/// <summary>
/// 移除路由守卫
/// 移除路由守卫
/// </summary>
/// <param name="guard">要移除的路由守卫实例</param>
/// <exception cref="ArgumentNullException">当守卫实例为null时抛出</exception>
public void RemoveGuard(IUiRouteGuard guard)
{
ArgumentNullException.ThrowIfNull(guard);
@ -473,7 +532,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
#region Internal Helpers
/// <summary>
/// 生成唯一实例ID
/// 生成唯一实例ID
/// </summary>
/// <returns>格式为"ui_000001"的唯一实例标识符</returns>
private string GenerateInstanceId()
@ -485,8 +544,13 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
/// <summary>
/// 内部Show实现支持重入
/// 内部Show实现支持重入
/// </summary>
/// <param name="page">UI页面行为实例</param>
/// <param name="layer">UI显示层级</param>
/// <param name="param">页面进入参数</param>
/// <returns>UI句柄实例</returns>
/// <exception cref="InvalidOperationException">当UI不支持重入且已在该层级存在时抛出</exception>
private UiHandle ShowInternal(IUiPageBehavior page, UiLayer layer, IUiPageEnterParam? param)
{
var instanceId = GenerateInstanceId();
@ -521,6 +585,14 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
return handle;
}
/// <summary>
/// 创建UI过渡事件
/// </summary>
/// <param name="toUiKey">目标UI键值</param>
/// <param name="type">过渡类型</param>
/// <param name="policy">过渡策略</param>
/// <param name="param">进入参数</param>
/// <returns>UI过渡事件实例</returns>
private UiTransitionEvent CreateEvent(string? toUiKey, UiTransitionType type,
UiTransitionPolicy? policy = null, IUiPageEnterParam? param = null)
{
@ -534,33 +606,37 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
};
}
private void BeforeChange(UiTransitionEvent @event)
/// <summary>
/// 执行过渡前阶段
/// </summary>
/// <param name="event">UI过渡事件</param>
private async Task BeforeChangeAsync(UiTransitionEvent @event)
{
Log.Debug("BeforeChange phases started: {0}", @event.TransitionType);
_pipeline.ExecuteAsync(@event, UiTransitionPhases.BeforeChange).GetAwaiter().GetResult();
await _pipeline.ExecuteAsync(@event, UiTransitionPhases.BeforeChange);
Log.Debug("BeforeChange phases completed: {0}", @event.TransitionType);
}
private void AfterChange(UiTransitionEvent @event)
/// <summary>
/// 执行过渡后阶段
/// </summary>
/// <param name="event">UI过渡事件</param>
private async Task AfterChangeAsync(UiTransitionEvent @event)
{
Log.Debug("AfterChange phases started: {0}", @event.TransitionType);
_ = Task.Run<Task>(async () =>
{
try
{
await _pipeline.ExecuteAsync(@event, UiTransitionPhases.AfterChange).ConfigureAwait(false);
Log.Debug("AfterChange phases completed: {0}", @event.TransitionType);
}
catch (Exception ex)
{
Log.Error("AfterChange phases failed: {0}, Error: {1}", @event.TransitionType, ex.Message);
}
});
await _pipeline.ExecuteAsync(@event, UiTransitionPhases.AfterChange);
Log.Debug("AfterChange phases completed: {0}", @event.TransitionType);
}
private void DoPushPageInternal(string uiKey, IUiPageEnterParam? param, UiTransitionPolicy policy)
/// <summary>
/// 内部异步压入页面实现
/// </summary>
/// <param name="uiKey">UI页面键值</param>
/// <param name="param">页面进入参数</param>
/// <param name="policy">过渡策略</param>
private async Task DoPushPageInternalAsync(string uiKey, IUiPageEnterParam? param, UiTransitionPolicy policy)
{
if (!ExecuteEnterGuardsAsync(uiKey, param).GetAwaiter().GetResult())
if (!await ExecuteEnterGuardsAsync(uiKey, param))
{
Log.Warn("Push blocked by guard: {0}", uiKey);
return;
@ -571,6 +647,12 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
DoPushPageInternal(page, param, policy);
}
/// <summary>
/// 内部压入页面实现
/// </summary>
/// <param name="page">UI页面行为实例</param>
/// <param name="param">页面进入参数</param>
/// <param name="policy">过渡策略</param>
private void DoPushPageInternal(IUiPageBehavior page, IUiPageEnterParam? param, UiTransitionPolicy policy)
{
if (_stack.Count > 0)
@ -596,6 +678,10 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
page.OnShow();
}
/// <summary>
/// 内部弹出页面实现
/// </summary>
/// <param name="policy">页面弹出策略</param>
private void DoPopInternal(UiPopPolicy policy)
{
if (_stack.Count == 0)
@ -623,6 +709,10 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
}
/// <summary>
/// 内部清空页面实现
/// </summary>
/// <param name="policy">页面弹出策略</param>
private void DoClearInternal(UiPopPolicy policy)
{
Log.Debug("Clear UI Stack internal, count={0}", _stack.Count);
@ -630,6 +720,12 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
DoPopInternal(policy);
}
/// <summary>
/// 执行进入守卫检查
/// </summary>
/// <param name="uiKey">UI页面键值</param>
/// <param name="param">页面进入参数</param>
/// <returns>如果允许进入则返回true否则返回false</returns>
private async Task<bool> ExecuteEnterGuardsAsync(string uiKey, IUiPageEnterParam? param)
{
foreach (var guard in _guards)
@ -662,6 +758,11 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
return true;
}
/// <summary>
/// 执行离开守卫检查
/// </summary>
/// <param name="uiKey">UI页面键值</param>
/// <returns>如果允许离开则返回true否则返回false</returns>
private async Task<bool> ExecuteLeaveGuardsAsync(string uiKey)
{
foreach (var guard in _guards)