diff --git a/GFramework.Game.Abstractions/ui/UiHandle.cs b/GFramework.Game.Abstractions/ui/UiHandle.cs index a441ad3..c10e8b9 100644 --- a/GFramework.Game.Abstractions/ui/UiHandle.cs +++ b/GFramework.Game.Abstractions/ui/UiHandle.cs @@ -41,7 +41,7 @@ public readonly struct UiHandle /// UI的键值,用于标识UI的类型或名称。 /// UI实例的唯一标识符。 /// UI所在的层级,用于控制UI的显示顺序。 - internal UiHandle(string key, string instanceId, UiLayer layer) + public UiHandle(string key, string instanceId, UiLayer layer) { Key = key; InstanceId = instanceId; diff --git a/GFramework.Game/ui/UiRouterBase.cs b/GFramework.Game/ui/UiRouterBase.cs index 0449368..ded1226 100644 --- a/GFramework.Game/ui/UiRouterBase.cs +++ b/GFramework.Game/ui/UiRouterBase.cs @@ -21,6 +21,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// /// 层级管理(非栈层级),用于Overlay、Modal、Toast等浮层 + /// Key: UiLayer, Value: Dictionary of InstanceId -> PageBehavior /// private readonly Dictionary> _layers = new(); @@ -39,13 +40,16 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// private IUiFactory _factory = null!; + /// + /// 实例ID计数器,用于生成唯一ID + /// + private int _instanceCounter; + private IUiRoot _uiRoot = null!; /// /// 注册UI切换处理器 /// - /// 处理器实例 - /// 执行选项 public void RegisterHandler(IUiTransitionHandler handler, UiTransitionHandlerOptions? options = null) { _pipeline.RegisterHandler(handler, options); @@ -54,7 +58,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// /// 注销UI切换处理器 /// - /// 处理器实例 public void UnregisterHandler(IUiTransitionHandler handler) { _pipeline.UnregisterHandler(handler); @@ -69,13 +72,11 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter Log.Debug("Bind UI Root: {0}", root.GetType().Name); } + #region Page Stack Management /// - /// 将指定的UI界面压入路由栈,显示新的UI界面 + /// 将指定的UI界面压入路由栈 /// - /// UI界面的唯一标识符 - /// 进入界面的参数,可为空 - /// 界面切换策略,默认为Exclusive(独占) public void Push(string uiKey, IUiPageEnterParam? param = null, UiTransitionPolicy policy = UiTransitionPolicy.Exclusive) { @@ -86,11 +87,7 @@ 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 - ); + Log.Debug("Push UI Page: key={0}, policy={1}, stackBefore={2}", uiKey, policy, _stack.Count); BeforeChange(@event); DoPushPageInternal(uiKey, param, policy); @@ -98,18 +95,12 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter } /// - /// 将已存在的UI页面压入栈顶并显示 + /// 将已存在的UI页面压入栈顶 /// - /// 已创建的UI页面行为实例 - /// 页面进入参数,可为空 - /// 页面切换策略 - public void Push( - IUiPageBehavior page, - IUiPageEnterParam? param = null, - UiTransitionPolicy policy = UiTransitionPolicy.Exclusive - ) + public void Push(IUiPageBehavior page, IUiPageEnterParam? param = null, + UiTransitionPolicy policy = UiTransitionPolicy.Exclusive) { - var uiKey = page.View.GetType().Name; + var uiKey = page.Key; if (IsTop(uiKey)) { @@ -118,11 +109,7 @@ 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 - ); + Log.Debug("Push existing UI Page: key={0}, policy={1}, stackBefore={2}", uiKey, policy, _stack.Count); BeforeChange(@event); DoPushPageInternal(page, param, policy); @@ -130,9 +117,8 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter } /// - /// 弹出栈顶页面并根据策略处理页面 + /// 弹出栈顶页面 /// - /// 弹出策略,默认为销毁策略 public void Pop(UiPopPolicy policy = UiPopPolicy.Destroy) { if (_stack.Count == 0) @@ -149,175 +135,350 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter return; } - // ⚠️ 注意:nextUiKey 现在是可选的 - var nextUiKey = _stack.Count > 1 - ? _stack.ElementAt(1).Key - : null; - - var @event = CreateEvent( - nextUiKey, - UiTransitionType.Pop - ); + var nextUiKey = _stack.Count > 1 ? _stack.ElementAt(1).Key : null; + var @event = CreateEvent(nextUiKey, UiTransitionType.Pop); BeforeChange(@event); - DoPopInternal(policy); - AfterChange(@event); } - /// /// 替换当前所有页面为新页面(基于uiKey) /// - /// 新UI页面标识符 - /// 页面进入参数,可为空 - /// 弹出页面时的销毁策略,默认为销毁 - /// 推入页面时的过渡策略,默认为独占 - public void Replace( - string uiKey, - IUiPageEnterParam? param = null, + public void Replace(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 - ); + Log.Debug("Replace UI Stack with page: key={0}, popPolicy={1}, pushPolicy={2}", uiKey, popPolicy, pushPolicy); BeforeChange(@event); - - // 使用内部方法清空栈,避免触发额外的Pipeline 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); } /// - /// 替换当前所有页面为已存在的页面(基于实例) + /// 替换当前所有页面为已存在的页面 /// - /// 已创建的UI页面行为实例 - /// 页面进入参数,可为空 - /// 弹出页面时的销毁策略,默认为销毁 - /// 推入页面时的过渡策略,默认为独占 - public void Replace( - IUiPageBehavior page, - IUiPageEnterParam? param = null, + public void Replace(IUiPageBehavior page, IUiPageEnterParam? param = null, UiPopPolicy popPolicy = UiPopPolicy.Destroy, UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive) { var uiKey = page.Key; var @event = CreateEvent(uiKey, UiTransitionType.Replace, pushPolicy, param); - - Log.Debug( - "Replace UI Stack with existing page: key={0}, popPolicy={1}, pushPolicy={2}", - uiKey, popPolicy, pushPolicy - ); + Log.Debug("Replace UI Stack with existing page: key={0}, popPolicy={1}, pushPolicy={2}", + uiKey, popPolicy, pushPolicy); BeforeChange(@event); - - // 清空栈 DoClearInternal(popPolicy); - Log.Debug("Use existing UI Page instance for Replace: {0}", page.GetType().Name); DoPushPageInternal(page, param, pushPolicy); - AfterChange(@event); } /// - /// 清空所有页面栈中的页面 + /// 清空所有页面栈 /// public void Clear() { var @event = CreateEvent(string.Empty, UiTransitionType.Clear); - Log.Debug("Clear UI Stack, stackCount={0}", _stack.Count); BeforeChange(@event); - - // 使用内部方法,避免触发额外的Pipeline DoClearInternal(UiPopPolicy.Destroy); - AfterChange(@event); } - /// - /// 获取页面栈顶元素的键值,但不移除该元素 + /// 获取栈顶元素的键值 /// - /// 如果页面栈为空则返回空字符串,否则返回栈顶元素的键值 public string PeekKey() { return _stack.Count == 0 ? string.Empty : _stack.Peek().Key; } /// - /// 获取页面栈顶元素,但不移除该元素 + /// 获取栈顶元素 /// - /// 返回栈顶的IUiPageBehavior元素 public IUiPageBehavior? Peek() { return _stack.Count == 0 ? null : _stack.Peek(); } - /// - /// 判断栈顶元素是否指定的UI类型 + /// 判断栈顶是否为指定UI /// - /// 要比较的UI类型名称 - /// 如果栈为空或栈顶元素类型不匹配则返回false,否则返回true public bool IsTop(string uiKey) { return _stack.Count != 0 && _stack.Peek().Key.Equals(uiKey); } /// - /// 判断栈中是否包含指定类型的UI元素 + /// 判断栈中是否包含指定UI /// - /// 要查找的UI类型名称 - /// 如果栈中存在指定类型的UI元素则返回true,否则返回false public bool Contains(string uiKey) { return _stack.Any(p => p.Key.Equals(uiKey)); } /// - /// 获取栈中元素的数量 + /// 获取栈深度 /// public int Count => _stack.Count; + #endregion + + #region Layer UI Management + /// - /// 初始化方法,在页面初始化时获取UI工厂实例 + /// 在指定层级显示UI(基于 uiKey) + /// + public UiHandle Show(string uiKey, UiLayer layer, IUiPageEnterParam? param = null) + { + if (layer == UiLayer.Page) + throw new ArgumentException("Use Push() for Page layer"); + + // 创建实例 + var page = _factory.Create(uiKey); + + return ShowInternal(page, layer, param); + } + + /// + /// 在指定层级显示UI(基于实例) + /// + public UiHandle Show(IUiPageBehavior page, UiLayer layer) + { + if (layer == UiLayer.Page) + throw new ArgumentException("Use Push() for Page layer"); + + return ShowInternal(page, layer, null); + } + + /// + /// 隐藏指定层级的UI + /// + public void Hide(UiHandle handle, UiLayer layer, bool destroy = false) + { + if (!_layers.TryGetValue(layer, out var layerDict)) + return; + + if (!layerDict.TryGetValue(handle.InstanceId, out var page)) + return; + + if (destroy) + { + page.OnExit(); + _uiRoot.RemoveUiPage(page); + layerDict.Remove(handle.InstanceId); + Log.Debug("Hide & Destroy UI: instanceId={0}, layer={1}", handle.InstanceId, layer); + } + else + { + page.OnHide(); + Log.Debug("Hide UI (suspend): instanceId={0}, layer={1}", handle.InstanceId, layer); + } + } + + /// + /// 恢复指定UI的显示 + /// + public void Resume(UiHandle handle, UiLayer layer) + { + if (!_layers.TryGetValue(layer, out var layerDict)) + return; + + if (!layerDict.TryGetValue(handle.InstanceId, out var page)) + return; + + page.OnShow(); + page.OnResume(); + Log.Debug("Resume UI: instanceId={0}, layer={1}", handle.InstanceId, layer); + } + + /// + /// 清空指定层级的所有UI + /// + public void ClearLayer(UiLayer layer, bool destroy = false) + { + if (!_layers.TryGetValue(layer, out var layerDict)) + return; + + var handles = layerDict.Keys + .Select(instanceId => + { + var page = layerDict[instanceId]; + return new UiHandle(page.Key, instanceId, layer); + }) + .ToArray(); + + foreach (var handle in handles) + Hide(handle, layer, destroy); + + Log.Debug("Cleared layer: {0}, destroyed={1}", layer, destroy); + } + + /// + /// 获取指定层级的UI实例 + /// + public UiHandle? GetFromLayer(UiHandle handle, UiLayer layer) + { + if (!_layers.TryGetValue(layer, out var layerDict)) + return null; + + return layerDict.ContainsKey(handle.InstanceId) ? handle : null; + } + + /// + /// 获取指定 uiKey 在指定层级的所有实例 + /// + public IReadOnlyList GetAllFromLayer(string uiKey, UiLayer layer) + { + if (!_layers.TryGetValue(layer, out var layerDict)) + return Array.Empty(); + + return layerDict + .Where(kvp => kvp.Value.Key.Equals(uiKey)) + .Select(kvp => new UiHandle(uiKey, kvp.Key, layer)) + .ToList(); + } + + /// + /// 判断指定UI是否在层级中可见 + /// + public bool HasVisibleInLayer(UiHandle handle, UiLayer layer) + { + if (!_layers.TryGetValue(layer, out var layerDict)) + return false; + + if (!layerDict.TryGetValue(handle.InstanceId, out var page)) + return false; + + return page.IsVisible; + } + + #endregion + + #region Route Guards + + /// + /// 注册路由守卫 + /// + public void AddGuard(IUiRouteGuard guard) + { + ArgumentNullException.ThrowIfNull(guard); + + if (_guards.Contains(guard)) + { + Log.Debug("Guard already registered: {0}", guard.GetType().Name); + return; + } + + _guards.Add(guard); + _guards.Sort((a, b) => a.Priority.CompareTo(b.Priority)); + Log.Debug("Guard registered: {0}, Priority={1}", guard.GetType().Name, guard.Priority); + } + + /// + /// 注册路由守卫(泛型) + /// + public void AddGuard() where T : IUiRouteGuard, new() + { + AddGuard(new T()); + } + + /// + /// 移除路由守卫 + /// + public void RemoveGuard(IUiRouteGuard guard) + { + ArgumentNullException.ThrowIfNull(guard); + if (_guards.Remove(guard)) + Log.Debug("Guard removed: {0}", guard.GetType().Name); + } + + #endregion + + #region Initialization + + /// + /// 初始化函数,在对象创建时调用。 + /// 该函数负责获取UI工厂实例并注册处理程序。 /// protected override void OnInit() { + // 获取UI工厂实例,并确保其不为null _factory = this.GetUtility()!; + + // 输出调试日志,记录UI路由器基类已初始化及使用的工厂类型 Log.Debug("UiRouterBase initialized. Factory={0}", _factory.GetType().Name); + + // 调用抽象方法以注册具体的处理程序 RegisterHandlers(); } /// - /// 注册默认的UI切换处理器 + /// 抽象方法,用于注册具体的处理程序。 + /// 子类必须实现此方法以完成特定的处理逻辑注册。 /// protected abstract void RegisterHandlers(); + #endregion + + #region Internal Helpers + /// - /// 创建UI切换事件 + /// 生成唯一实例ID /// - private UiTransitionEvent CreateEvent( - string? toUiKey, - UiTransitionType type, - UiTransitionPolicy? policy = null, - IUiPageEnterParam? param = null - ) + private string GenerateInstanceId() + { + return $"ui_{++_instanceCounter:D6}"; + } + + /// + /// 内部Show实现,支持重入 + /// + private UiHandle ShowInternal(IUiPageBehavior page, UiLayer layer, IUiPageEnterParam? param) + { + var instanceId = GenerateInstanceId(); + var handle = new UiHandle(page.Key, instanceId, layer); + + // 初始化层级字典 + if (!_layers.ContainsKey(layer)) + _layers[layer] = new Dictionary(); + + var layerDict = _layers[layer]; + + // 检查重入性 + if (!page.IsReentrant && layerDict.Values.Any(p => p.Key == page.Key)) + { + Log.Warn("UI {0} is not reentrant but already exists in layer {1}", page.Key, layer); + throw new InvalidOperationException( + $"UI {page.Key} does not support multiple instances in layer {layer}"); + } + + // 添加到层级管理 + layerDict[instanceId] = page; + + // 添加到UiRoot + _uiRoot.AddUiPage(page, layer); + + // 生命周期 + page.OnEnter(param); + page.OnShow(); + + Log.Debug("Show UI: key={0}, instanceId={1}, layer={2}", page.Key, instanceId, layer); + return handle; + } + + private UiTransitionEvent CreateEvent(string? toUiKey, UiTransitionType type, + UiTransitionPolicy? policy = null, IUiPageEnterParam? param = null) { return new UiTransitionEvent { @@ -329,9 +490,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter }; } - /// - /// 执行UI切换前的Handler(阻塞) - /// private void BeforeChange(UiTransitionEvent @event) { Log.Debug("BeforeChange phases started: {0}", @event.TransitionType); @@ -339,9 +497,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter Log.Debug("BeforeChange phases completed: {0}", @event.TransitionType); } - /// - /// 执行UI切换后的Handler(不阻塞) - /// private void AfterChange(UiTransitionEvent @event) { Log.Debug("AfterChange phases started: {0}", @event.TransitionType); @@ -359,31 +514,21 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter }); } - /// - /// 执行Push页面的核心逻辑(基于 uiKey) - /// private void DoPushPageInternal(string uiKey, IUiPageEnterParam? param, UiTransitionPolicy policy) { - // 执行进入守卫 if (!ExecuteEnterGuardsAsync(uiKey, param).GetAwaiter().GetResult()) { Log.Warn("Push blocked by guard: {0}", uiKey); return; } - // 使用工厂的增强方法获取实例 var page = _factory.Create(uiKey); Log.Debug("Get/Create UI Page instance: {0}", page.GetType().Name); - DoPushPageInternal(page, param, policy); } - /// - /// 执行Push页面的核心逻辑(基于 page) - /// private void DoPushPageInternal(IUiPageBehavior page, IUiPageEnterParam? param, UiTransitionPolicy policy) { - // 1. 处理当前栈顶页面 if (_stack.Count > 0) { var current = _stack.Peek(); @@ -397,273 +542,54 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter } } - // 2. 将新页面添加到UiRoot Log.Debug("Add page to UiRoot: {0}", page.View.GetType().Name); _uiRoot.AddUiPage(page); - // 3. 压入栈 _stack.Push(page); - // 4. 触发页面生命周期 - Log.Debug( - "Enter & Show page: {0}, stackAfter={1}", - page.View.GetType().Name, _stack.Count - ); - + Log.Debug("Enter & Show page: {0}, stackAfter={1}", page.View.GetType().Name, _stack.Count); page.OnEnter(param); page.OnShow(); } - /// - /// 执行Pop的核心逻辑(不触发Pipeline) - /// private void DoPopInternal(UiPopPolicy policy) { if (_stack.Count == 0) return; var top = _stack.Pop(); - - Log.Debug( - "Pop UI Page internal: {0}, policy={1}, stackAfterPop={2}", - top.GetType().Name, policy, _stack.Count - ); + Log.Debug("Pop UI Page internal: {0}, policy={1}, stackAfterPop={2}", + top.GetType().Name, policy, _stack.Count); if (policy == UiPopPolicy.Destroy) { top.OnExit(); _uiRoot.RemoveUiPage(top); } - else // Suspend + else { top.OnHide(); } - if (_stack.Count <= 0) return; - var next = _stack.Peek(); - next.OnResume(); - next.OnShow(); + if (_stack.Count > 0) + { + var next = _stack.Peek(); + next.OnResume(); + next.OnShow(); + } } - /// - /// 执行Clear的核心逻辑(不触发Pipeline) - /// - /// UI弹出策略 private void DoClearInternal(UiPopPolicy policy) { Log.Debug("Clear UI Stack internal, count={0}", _stack.Count); - // 循环执行弹出操作直到栈为空 while (_stack.Count > 0) DoPopInternal(policy); } - #region 层级管理 - - /// - /// 在指定层级显示UI(非栈管理) - /// - public void Show( - string uiKey, - UiLayer layer, - IUiPageEnterParam? param = null) - { - if (layer == UiLayer.Page) throw new ArgumentException("Use Push() for Page layer"); - - // 初始化层级字典 - if (!_layers.ContainsKey(layer)) - _layers[layer] = new Dictionary(); - - var layerDict = _layers[layer]; - - // 检查是否已存在 - if (layerDict.TryGetValue(uiKey, out var existing)) - { - Log.Debug("UI already visible in layer: {0}, layer={1}", uiKey, layer); - existing.OnEnter(param); - existing.OnShow(); - return; - } - - // 获取或创建实例 - var page = _factory.Create(uiKey); - layerDict[uiKey] = page; - - // 添加到UiRoot,传入层级Z-order - _uiRoot.AddUiPage(page, layer); - - page.OnEnter(param); - page.OnShow(); - - Log.Debug("Show UI in layer: {0}, layer={1}", uiKey, layer); - } - - /// - /// 在指定层级显示UI(基于实例) - /// - public void Show(IUiPageBehavior page, UiLayer layer) - { - if (layer == UiLayer.Page) - throw new ArgumentException("Use Push() for Page layer"); - - var uiKey = page.Key; - - if (!_layers.ContainsKey(layer)) - _layers[layer] = new Dictionary(); - - _layers[layer][uiKey] = page; - _uiRoot.AddUiPage(page, layer); - page.OnShow(); - - Log.Debug("Show existing UI instance in layer: {0}, layer={1}", uiKey, layer); - } - - /// - /// 隐藏指定层级的UI。 - /// - /// 要隐藏的UI的唯一标识符。 - /// UI所在的层级。 - /// 是否永久销毁UI。如果为true,则UI将被彻底移除;如果为false,则UI仅被隐藏,可后续恢复。 - public void Hide(string uiKey, UiLayer layer, bool destroy = false) - { - // 尝试获取指定层级的UI字典,若不存在则直接返回 - if (!_layers.TryGetValue(layer, out var layerDict)) - return; - - // 尝试获取指定UI键对应的页面对象,若不存在则直接返回 - if (!layerDict.TryGetValue(uiKey, out var page)) - return; - - if (destroy) - { - // 永久移除UI:调用OnExit方法并从UI根节点和层级字典中移除该UI - page.OnExit(); // ✅ 只在 Destroy 时 Exit - _uiRoot.RemoveUiPage(page); - layerDict.Remove(uiKey); - - Log.Debug( - "Hide & Destroy UI from layer: {0}, layer={1}", - uiKey, layer - ); - } - else - { - // 临时隐藏UI:调用OnHide方法,保留UI状态以便后续恢复 - page.OnHide(); // ✅ Hide ≠ Exit - - Log.Debug( - "Hide UI from layer (suspend): {0}, layer={1}", - uiKey, layer - ); - } - } - - /// - /// 恢复指定层级中已隐藏的UI。 - /// - /// 要恢复的UI的唯一标识符。 - /// UI所在的层级。 - public void Resume(string uiKey, UiLayer layer) - { - // 尝试获取指定层级的UI字典,若不存在则直接返回 - if (!_layers.TryGetValue(layer, out var layerDict)) - return; - - // 尝试获取指定UI键对应的页面对象,若不存在则直接返回 - if (!layerDict.TryGetValue(uiKey, out var page)) - return; - - // 调用OnShow和OnResume方法以恢复UI的显示和状态 - page.OnShow(); - page.OnResume(); - - Log.Debug("Resume UI in layer: {0}, layer={1}", uiKey, layer); - } - - /// - /// 清空指定层级的所有UI - /// - public void ClearLayer(UiLayer layer, bool destroy = false) - { - if (!_layers.TryGetValue(layer, out var layerDict)) - return; - - var keys = layerDict.Keys.ToArray(); - foreach (var key in keys) Hide(key, layer, destroy); - - Log.Debug("Cleared layer: {0}, destroyed={1}", layer, destroy); - } - - /// - /// 获取指定层级的UI实例 - /// - public IUiPageBehavior? GetFromLayer(string uiKey, UiLayer layer) - { - return _layers.TryGetValue(layer, out var layerDict) && - layerDict.TryGetValue(uiKey, out var page) - ? page - : null; - } - - /// - /// 判断指定层级是否有UI显示 - /// - public bool HasVisibleInLayer(string uiKey, UiLayer layer) - { - if (!_layers.TryGetValue(layer, out var layerDict) || - !layerDict.TryGetValue(uiKey, out var page)) - return false; - - return page.IsVisible; - } - - #endregion - - #region 路由守卫 - - /// - /// 注册路由守卫 - /// - public void AddGuard(IUiRouteGuard guard) - { - ArgumentNullException.ThrowIfNull(guard); - - if (_guards.Contains(guard)) - { - Log.Debug("Guard already registered: {0}", guard.GetType().Name); - return; - } - - _guards.Add(guard); - // 按优先级排序 - _guards.Sort((a, b) => a.Priority.CompareTo(b.Priority)); - Log.Debug("Guard registered: {0}, Priority={1}", guard.GetType().Name, guard.Priority); - } - - /// - /// 注册路由守卫(泛型方法) - /// - public void AddGuard() where T : IUiRouteGuard, new() - { - var guard = new T(); - AddGuard(guard); - } - - /// - /// 移除路由守卫 - /// - public void RemoveGuard(IUiRouteGuard guard) - { - ArgumentNullException.ThrowIfNull(guard); - - if (_guards.Remove(guard)) Log.Debug("Guard removed: {0}", guard.GetType().Name); - } - - /// - /// 执行进入守卫 - /// private async Task ExecuteEnterGuardsAsync(string uiKey, IUiPageEnterParam? param) { foreach (var guard in _guards) + { try { Log.Debug("Executing enter guard: {0} for {1}", guard.GetType().Name, uiKey); @@ -684,18 +610,18 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter catch (Exception ex) { Log.Error("Enter guard {0} failed: {1}", guard.GetType().Name, ex.Message); - if (guard.CanInterrupt) return false; + if (guard.CanInterrupt) + return false; } + } return true; } - /// - /// 执行离开守卫 - /// private async Task ExecuteLeaveGuardsAsync(string uiKey) { foreach (var guard in _guards) + { try { Log.Debug("Executing leave guard: {0} for {1}", guard.GetType().Name, uiKey); @@ -707,15 +633,19 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter return false; } - if (!guard.CanInterrupt) continue; - Log.Debug("Leave guard {0} passed, can interrupt = true", guard.GetType().Name); - return true; + if (guard.CanInterrupt) + { + Log.Debug("Leave guard {0} passed, can interrupt = true", guard.GetType().Name); + return true; + } } catch (Exception ex) { Log.Error("Leave guard {0} failed: {1}", guard.GetType().Name, ex.Message); - if (guard.CanInterrupt) return false; + if (guard.CanInterrupt) + return false; } + } return true; }