950 lines
33 KiB
C#
950 lines
33 KiB
C#
using System;
|
||
using System.Collections.Concurrent;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
|
||
namespace NavisworksTransport.Core
|
||
{
|
||
/// <summary>
|
||
/// UI状态管理器 - 提供线程安全的UI更新机制
|
||
/// 解决Navisworks插件中的跨线程UI操作问题,防止崩溃和死锁
|
||
/// </summary>
|
||
public class UIStateManager
|
||
{
|
||
#region 字段和属性
|
||
|
||
private static UIStateManager _instance;
|
||
private static readonly object _instanceLock = new object();
|
||
|
||
private readonly SynchronizationContext _uiContext;
|
||
private readonly object _operationLock = new object();
|
||
private readonly ConcurrentQueue<UIUpdateOperation> _updateQueue;
|
||
private readonly int _flushInterval = 50; // 50ms最小处理间隔,与UI刷新同步
|
||
private volatile bool _isProcessing = false;
|
||
private volatile bool _isDisposed = false;
|
||
|
||
/// <summary>
|
||
/// UI操作默认超时时间(毫秒)- 60秒
|
||
/// 设置较长时间以应对程序性能异常导致的UI线程阻塞
|
||
/// </summary>
|
||
private const int DEFAULT_UI_TIMEOUT = 60000;
|
||
|
||
/// <summary>
|
||
/// 获取UIStateManager的单例实例
|
||
/// </summary>
|
||
public static UIStateManager Instance
|
||
{
|
||
get
|
||
{
|
||
if (_instance == null)
|
||
{
|
||
lock (_instanceLock)
|
||
{
|
||
if (_instance == null)
|
||
{
|
||
_instance = new UIStateManager();
|
||
}
|
||
}
|
||
}
|
||
return _instance;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前是否在UI线程中
|
||
/// </summary>
|
||
public bool IsUIThread
|
||
{
|
||
get
|
||
{
|
||
if (_uiContext != null)
|
||
{
|
||
return SynchronizationContext.Current == _uiContext;
|
||
}
|
||
|
||
// 回退到Windows Forms检查
|
||
try
|
||
{
|
||
var activeForm = Form.ActiveForm;
|
||
if (activeForm != null)
|
||
{
|
||
return !activeForm.InvokeRequired;
|
||
}
|
||
return false;
|
||
}
|
||
catch
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前等待处理的UI更新操作数量
|
||
/// </summary>
|
||
public int PendingOperationsCount => _updateQueue.Count;
|
||
|
||
#endregion
|
||
|
||
#region 构造函数和初始化
|
||
|
||
private UIStateManager()
|
||
{
|
||
try
|
||
{
|
||
// 尝试获取当前的SynchronizationContext
|
||
_uiContext = SynchronizationContext.Current;
|
||
|
||
// 在Navisworks插件环境中,完全跳过WPF Dispatcher的创建
|
||
// 因为它可能与宿主环境冲突并导致崩溃
|
||
if (_uiContext == null)
|
||
{
|
||
LogManager.Info("当前没有SynchronizationContext,UIStateManager将使用Windows Forms回退机制");
|
||
// 不尝试创建WPF Dispatcher,直接使用null让后续代码使用Windows Forms
|
||
}
|
||
|
||
_updateQueue = new ConcurrentQueue<UIUpdateOperation>();
|
||
|
||
LogManager.Info("UIStateManager初始化完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"UIStateManager初始化失败: {ex.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 手动设置UI上下文(通常在主线程初始化时调用)
|
||
/// </summary>
|
||
/// <param name="context">UI线程的SynchronizationContext</param>
|
||
public void SetUIContext(SynchronizationContext context)
|
||
{
|
||
if (context == null)
|
||
{
|
||
LogManager.Warning("尝试设置空的SynchronizationContext");
|
||
return;
|
||
}
|
||
|
||
// 只有在当前没有上下文或者在UI线程中才允许设置
|
||
if (_uiContext == null || IsUIThread)
|
||
{
|
||
var oldContext = _uiContext;
|
||
var newContext = context;
|
||
|
||
LogManager.Info($"UIStateManager上下文更新: {oldContext?.GetType()?.Name} -> {newContext.GetType().Name}");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Warning("只能在UI线程中设置SynchronizationContext");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 核心UI更新接口
|
||
|
||
/// <summary>
|
||
/// 线程安全的异步UI更新操作
|
||
/// </summary>
|
||
/// <typeparam name="T">返回值类型</typeparam>
|
||
/// <param name="operation">要执行的UI操作</param>
|
||
/// <param name="timeout">超时时间(毫秒),默认5000ms</param>
|
||
/// <returns>操作结果</returns>
|
||
public async Task<T> ExecuteUIUpdateAsync<T>(Func<T> operation, int timeout = DEFAULT_UI_TIMEOUT)
|
||
{
|
||
if (_isDisposed)
|
||
{
|
||
throw new ObjectDisposedException(nameof(UIStateManager));
|
||
}
|
||
|
||
if (operation == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(operation));
|
||
}
|
||
|
||
// 如果已经在UI线程中,直接执行
|
||
if (IsUIThread)
|
||
{
|
||
try
|
||
{
|
||
return operation();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"UI操作执行失败: {ex.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
// 创建任务完成信号
|
||
var tcs = new TaskCompletionSource<T>();
|
||
var cancellationToken = new CancellationTokenSource(timeout);
|
||
|
||
// 设置超时处理
|
||
cancellationToken.Token.Register(() =>
|
||
{
|
||
if (!tcs.Task.IsCompleted)
|
||
{
|
||
tcs.TrySetException(new TimeoutException($"UI操作超时({timeout}ms)"));
|
||
}
|
||
});
|
||
|
||
try
|
||
{
|
||
// 使用SynchronizationContext切换到UI线程
|
||
if (_uiContext != null)
|
||
{
|
||
_uiContext.Post(_ =>
|
||
{
|
||
try
|
||
{
|
||
if (!cancellationToken.Token.IsCancellationRequested)
|
||
{
|
||
var result = operation();
|
||
tcs.TrySetResult(result);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"UI线程操作异常: {ex.Message}");
|
||
tcs.TrySetException(ex);
|
||
}
|
||
}, null);
|
||
}
|
||
else
|
||
{
|
||
// 回退到Control.BeginInvoke
|
||
var mainForm = GetMainForm();
|
||
if (mainForm != null)
|
||
{
|
||
mainForm.BeginInvoke(new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
if (!cancellationToken.Token.IsCancellationRequested)
|
||
{
|
||
var result = operation();
|
||
tcs.TrySetResult(result);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"UI线程操作异常(Control.BeginInvoke): {ex.Message}");
|
||
tcs.TrySetException(ex);
|
||
}
|
||
}));
|
||
}
|
||
else
|
||
{
|
||
throw new InvalidOperationException("无法找到UI上下文来执行操作");
|
||
}
|
||
}
|
||
|
||
return await tcs.Task;
|
||
}
|
||
finally
|
||
{
|
||
// 延迟释放,给异步操作清理时间,避免"CancellationTokenSource 已释放"异常
|
||
_ = Task.Delay(100).ContinueWith(_ => cancellationToken.Dispose());
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 无返回值的异步UI更新操作
|
||
/// </summary>
|
||
/// <param name="operation">要执行的UI操作</param>
|
||
/// <param name="timeout">超时时间(毫秒),默认5000ms</param>
|
||
public async Task ExecuteUIUpdateAsync(Action operation, int timeout = DEFAULT_UI_TIMEOUT)
|
||
{
|
||
await ExecuteUIUpdateAsync<object>(() =>
|
||
{
|
||
operation();
|
||
return null;
|
||
}, timeout);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 批量UI更新接口
|
||
|
||
/// <summary>
|
||
/// 批量执行UI更新操作(原子性保证)
|
||
/// 所有操作要么全部成功,要么全部失败
|
||
/// </summary>
|
||
/// <param name="updates">要执行的UI更新操作数组</param>
|
||
/// <param name="timeout">超时时间(毫秒),默认10000ms</param>
|
||
public async Task ExecuteBatchUIUpdate(Action[] updates, int timeout = DEFAULT_UI_TIMEOUT)
|
||
{
|
||
if (updates == null || updates.Length == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
await ExecuteUIUpdateAsync(() =>
|
||
{
|
||
var exceptions = new List<Exception>();
|
||
|
||
// 执行所有更新操作
|
||
foreach (var update in updates)
|
||
{
|
||
try
|
||
{
|
||
update?.Invoke();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
exceptions.Add(ex);
|
||
LogManager.Error($"批量UI更新中的操作失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
// 如果有任何异常,抛出聚合异常
|
||
if (exceptions.Count > 0)
|
||
{
|
||
throw new AggregateException("批量UI更新过程中发生错误", exceptions);
|
||
}
|
||
}, timeout);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 批量执行UI更新操作(可变参数版本)
|
||
/// </summary>
|
||
/// <param name="updates">要执行的UI更新操作</param>
|
||
public async Task ExecuteBatchUIUpdate(params Action[] updates)
|
||
{
|
||
await ExecuteBatchUIUpdate(updates, DEFAULT_UI_TIMEOUT);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 同步版本的批量UI更新操作(用于强制同步处理)
|
||
/// 不使用异步机制,直接在当前线程中处理UI操作
|
||
/// </summary>
|
||
/// <param name="updates">要执行的UI更新操作数组</param>
|
||
/// <param name="timeout">超时时间(毫秒),默认5000ms</param>
|
||
public void ExecuteBatchUIUpdateSync(Action[] updates, int timeout = DEFAULT_UI_TIMEOUT)
|
||
{
|
||
if (updates == null || updates.Length == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
LogManager.Info($"开始同步执行{updates.Length}个UI更新操作");
|
||
|
||
var exceptions = new List<Exception>();
|
||
|
||
// 如果已经在UI线程中,直接执行
|
||
if (IsUIThread)
|
||
{
|
||
LogManager.Info("当前已在UI线程,直接同步执行批量操作");
|
||
foreach (var update in updates)
|
||
{
|
||
try
|
||
{
|
||
update?.Invoke();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
exceptions.Add(ex);
|
||
LogManager.Error($"同步批量UI更新中的操作失败: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 使用同步方式切换到UI线程
|
||
var completed = false;
|
||
Exception syncException = null;
|
||
var resetEvent = new ManualResetEventSlim(false);
|
||
|
||
LogManager.Info("切换到UI线程同步执行批量操作");
|
||
|
||
if (_uiContext != null)
|
||
{
|
||
_uiContext.Send(_ =>
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"SynchronizationContext中同步执行{updates.Length}个操作");
|
||
foreach (var update in updates)
|
||
{
|
||
try
|
||
{
|
||
update?.Invoke();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
exceptions.Add(ex);
|
||
LogManager.Error($"同步批量UI更新中的操作失败: {ex.Message}");
|
||
}
|
||
}
|
||
completed = true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
syncException = ex;
|
||
}
|
||
finally
|
||
{
|
||
resetEvent.Set();
|
||
}
|
||
}, null);
|
||
}
|
||
else
|
||
{
|
||
// 回退到Control.Invoke
|
||
var mainForm = GetMainForm();
|
||
if (mainForm != null)
|
||
{
|
||
mainForm.Invoke(new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"Control.Invoke中同步执行{updates.Length}个操作");
|
||
foreach (var update in updates)
|
||
{
|
||
try
|
||
{
|
||
update?.Invoke();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
exceptions.Add(ex);
|
||
LogManager.Error($"同步批量UI更新中的操作失败: {ex.Message}");
|
||
}
|
||
}
|
||
completed = true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
syncException = ex;
|
||
}
|
||
finally
|
||
{
|
||
resetEvent.Set();
|
||
}
|
||
}));
|
||
}
|
||
else
|
||
{
|
||
throw new InvalidOperationException("无法找到UI上下文来执行同步批量UI更新");
|
||
}
|
||
}
|
||
|
||
// 等待完成或超时
|
||
if (!resetEvent.Wait(timeout))
|
||
{
|
||
LogManager.Error($"同步批量UI更新执行超时({timeout}ms)");
|
||
throw new TimeoutException($"同步批量UI更新执行超时({timeout}ms)");
|
||
}
|
||
|
||
// 检查执行结果
|
||
if (syncException != null)
|
||
{
|
||
throw new Exception("同步批量UI更新执行失败", syncException);
|
||
}
|
||
|
||
if (!completed)
|
||
{
|
||
throw new InvalidOperationException("同步批量UI更新未正确完成");
|
||
}
|
||
}
|
||
|
||
// 如果有任何异常,抛出聚合异常
|
||
if (exceptions.Count > 0)
|
||
{
|
||
LogManager.Error($"同步批量UI更新过程中发生{exceptions.Count}个错误");
|
||
throw new AggregateException("同步批量UI更新过程中发生错误", exceptions);
|
||
}
|
||
|
||
LogManager.Info($"同步批量UI更新成功完成{updates.Length}个操作");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 更新队列管理
|
||
|
||
/// <summary>
|
||
/// 将UI更新操作加入队列(用于批量处理)
|
||
/// </summary>
|
||
/// <param name="operation">UI更新操作</param>
|
||
/// <param name="priority">操作优先级</param>
|
||
public void QueueUIUpdate(Action operation, UIUpdatePriority priority = UIUpdatePriority.Normal, bool forceSync = false)
|
||
{
|
||
if (_isDisposed || operation == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var updateOperation = new UIUpdateOperation
|
||
{
|
||
Id = Guid.NewGuid(),
|
||
Operation = operation,
|
||
Priority = priority,
|
||
QueueTime = DateTime.UtcNow
|
||
};
|
||
|
||
_updateQueue.Enqueue(updateOperation);
|
||
|
||
// 如果当前没有在处理,根据参数选择处理方式
|
||
if (!_isProcessing)
|
||
{
|
||
if (forceSync || priority == UIUpdatePriority.Critical)
|
||
{
|
||
// 强制同步处理:直接处理队列,不依赖Task.Run
|
||
LogManager.Info($"强制同步处理UI队列,优先级: {priority}, 队列长度: {_updateQueue.Count}");
|
||
try
|
||
{
|
||
ProcessQueuedUpdates(forcedSync: true).GetAwaiter().GetResult();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"强制同步处理队列失败: {ex.Message}");
|
||
// 回退到异步处理
|
||
_ = Task.Run(() => ProcessQueuedUpdates(forcedSync: false));
|
||
EnsureIdleProcessorRunning();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 普通异步处理 + 保底定时器
|
||
_ = Task.Run(() => ProcessQueuedUpdates(forcedSync: false));
|
||
EnsureIdleProcessorRunning();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 强制同步处理UI更新操作(便捷方法)
|
||
/// 操作会先入队,然后立即同步处理整个队列
|
||
/// </summary>
|
||
/// <param name="operation">UI更新操作</param>
|
||
/// <param name="priority">操作优先级</param>
|
||
/// <param name="operationType">操作类型描述,用于日志记录</param>
|
||
public void QueueUIUpdateWithForcedSync(Action operation, UIUpdatePriority priority = UIUpdatePriority.High, string operationType = "强制同步UI更新")
|
||
{
|
||
LogManager.Info($"*** 开始{operationType},优先级: {priority} ***");
|
||
QueueUIUpdate(operation, priority, forceSync: true);
|
||
LogManager.Info($"*** {operationType}完成 ***");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 强制刷新当前队列中的所有操作(不添加新操作)
|
||
/// 直接同步处理现有队列,代替Task.Run
|
||
/// </summary>
|
||
/// <param name="operationType">操作类型描述,用于日志记录</param>
|
||
public void ForceFlushQueue(string operationType = "强制刷新队列")
|
||
{
|
||
if (_updateQueue.IsEmpty)
|
||
{
|
||
LogManager.Info($"{operationType}: 队列为空,无需处理");
|
||
return;
|
||
}
|
||
|
||
if (_isProcessing)
|
||
{
|
||
LogManager.Info($"{operationType}: 已在处理中,跳过");
|
||
return;
|
||
}
|
||
|
||
LogManager.Info($"*** 开始{operationType},当前队列长度: {_updateQueue.Count} ***");
|
||
|
||
try
|
||
{
|
||
ProcessQueuedUpdates(forcedSync: true).GetAwaiter().GetResult();
|
||
LogManager.Info($"*** {operationType}成功完成 ***");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"*** {operationType}失败: {ex.Message} ***");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 立即执行UI更新操作,绕过队列机制
|
||
/// 用于关键UI事件(如RouteGenerated)需要立即响应的场景
|
||
/// </summary>
|
||
/// <param name="operation">要执行的UI操作</param>
|
||
/// <param name="operationType">操作类型描述,用于日志记录</param>
|
||
/// <param name="timeout">超时时间(毫秒),默认2000ms</param>
|
||
public void ExecuteImmediateUIUpdate(Action operation, string operationType = "立即UI更新", int timeout = DEFAULT_UI_TIMEOUT)
|
||
{
|
||
if (_isDisposed || operation == null)
|
||
{
|
||
LogManager.Warning($"跳过{operationType}:UIStateManager已释放或操作为null");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
LogManager.Info($"*** 开始立即执行{operationType} ***");
|
||
|
||
// 如果已经在UI线程中,直接执行
|
||
if (IsUIThread)
|
||
{
|
||
LogManager.Info($"*** 当前已在UI线程,直接执行{operationType} ***");
|
||
operation();
|
||
LogManager.Info($"*** {operationType}立即执行完成 ***");
|
||
return;
|
||
}
|
||
|
||
// 创建同步等待信号
|
||
var completed = false;
|
||
Exception exception = null;
|
||
var resetEvent = new ManualResetEventSlim(false);
|
||
|
||
LogManager.Info($"*** 切换到UI线程执行{operationType} ***");
|
||
|
||
// 使用同步方式切换到UI线程
|
||
if (_uiContext != null)
|
||
{
|
||
_uiContext.Send(_ =>
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"*** SynchronizationContext中执行{operationType} ***");
|
||
operation();
|
||
completed = true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
exception = ex;
|
||
LogManager.Error($"{operationType}在UI线程中执行失败: {ex.Message}");
|
||
}
|
||
finally
|
||
{
|
||
resetEvent.Set();
|
||
}
|
||
}, null);
|
||
}
|
||
else
|
||
{
|
||
// 回退到Control.Invoke
|
||
var mainForm = GetMainForm();
|
||
if (mainForm != null)
|
||
{
|
||
mainForm.Invoke(new Action(() =>
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"*** Control.Invoke中执行{operationType} ***");
|
||
operation();
|
||
completed = true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
exception = ex;
|
||
LogManager.Error($"{operationType}在UI线程中执行失败(Control.Invoke): {ex.Message}");
|
||
}
|
||
finally
|
||
{
|
||
resetEvent.Set();
|
||
}
|
||
}));
|
||
}
|
||
else
|
||
{
|
||
throw new InvalidOperationException($"无法找到UI上下文来执行{operationType}");
|
||
}
|
||
}
|
||
|
||
// 等待完成或超时
|
||
if (!resetEvent.Wait(timeout))
|
||
{
|
||
LogManager.Error($"*** {operationType}执行超时({timeout}ms) ***");
|
||
throw new TimeoutException($"{operationType}执行超时({timeout}ms)");
|
||
}
|
||
|
||
// 检查执行结果
|
||
if (exception != null)
|
||
{
|
||
throw new Exception($"{operationType}执行失败", exception);
|
||
}
|
||
|
||
if (!completed)
|
||
{
|
||
throw new InvalidOperationException($"{operationType}未正确完成");
|
||
}
|
||
|
||
LogManager.Info($"*** {operationType}立即执行成功完成 ***");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"*** {operationType}立即执行失败: {ex.Message} ***", ex);
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 确保Idle处理器在运行(处理可能积压的UI操作)
|
||
/// 作为队列处理的保底机制,防止Task.Run失败导致的队列积压
|
||
/// </summary>
|
||
private void EnsureIdleProcessorRunning()
|
||
{
|
||
try
|
||
{
|
||
// 如果队列为空,则不需要启动
|
||
if (_updateQueue.IsEmpty)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 注册到IdleEventManager
|
||
const string taskId = "UIStateManager_QueueProcessor";
|
||
|
||
IdleEventManager.Instance.RegisterTask(
|
||
taskId,
|
||
ProcessQueueOnIdle,
|
||
_flushInterval, // 最小间隔50ms
|
||
10 // 高优先级,UI更新很重要
|
||
);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"注册Idle处理器失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Idle事件处理器 - 检查并处理积压的队列
|
||
/// </summary>
|
||
private void ProcessQueueOnIdle()
|
||
{
|
||
try
|
||
{
|
||
// 如果没有积压的操作,取消注册Idle任务
|
||
if (_updateQueue.IsEmpty)
|
||
{
|
||
IdleEventManager.Instance.UnregisterTask("UIStateManager_QueueProcessor");
|
||
return;
|
||
}
|
||
|
||
// 如果当前正在处理,等待下次检查
|
||
if (_isProcessing)
|
||
{
|
||
return;
|
||
}
|
||
|
||
LogManager.Info($"Idle事件检测到队列积压({_updateQueue.Count}个操作),开始处理");
|
||
|
||
// 强制启动队列处理(Idle事件使用异步处理)
|
||
_ = Task.Run(() => ProcessQueuedUpdates(forcedSync: false));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"Idle队列处理失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止Idle队列处理器
|
||
/// </summary>
|
||
private void StopIdleProcessor()
|
||
{
|
||
try
|
||
{
|
||
IdleEventManager.Instance.UnregisterTask("UIStateManager_QueueProcessor");
|
||
LogManager.Info("已停止Idle队列处理器");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"停止Idle队列处理器失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理队列中的UI更新操作
|
||
/// </summary>
|
||
/// <param name="forcedSync">是否强制同步处理(不使用异步)</param>
|
||
private async Task ProcessQueuedUpdates(bool forcedSync = false)
|
||
{
|
||
lock (_operationLock)
|
||
{
|
||
if (_isProcessing)
|
||
{
|
||
return; // 防止重入
|
||
}
|
||
_isProcessing = true;
|
||
}
|
||
|
||
try
|
||
{
|
||
var operations = new List<UIUpdateOperation>();
|
||
|
||
// 收集当前队列中的所有操作
|
||
while (_updateQueue.TryDequeue(out var operation))
|
||
{
|
||
operations.Add(operation);
|
||
}
|
||
|
||
if (operations.Count == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 按优先级排序
|
||
operations = operations.OrderByDescending(op => op.Priority).ToList();
|
||
|
||
LogManager.Info($"开始处理{operations.Count}个排队的UI更新操作,强制同步: {forcedSync}");
|
||
|
||
// 批量执行操作
|
||
var actions = operations.Select(op => op.Operation).ToArray();
|
||
|
||
if (forcedSync)
|
||
{
|
||
// 使用同步版本的批量更新
|
||
LogManager.Info("使用同步方式处理UI更新队列");
|
||
ExecuteBatchUIUpdateSync(actions);
|
||
LogManager.Info($"同步处理{operations.Count}个UI更新操作完成");
|
||
}
|
||
else
|
||
{
|
||
// 使用异步版本的批量更新
|
||
LogManager.Info("使用异步方式处理UI更新队列");
|
||
await ExecuteBatchUIUpdate(actions);
|
||
LogManager.Info($"异步处理{operations.Count}个UI更新操作完成");
|
||
}
|
||
|
||
// 处理完成后,如果队列为空,停止保底定时器
|
||
if (_updateQueue.IsEmpty)
|
||
{
|
||
StopIdleProcessor();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"处理UI更新队列时发生错误: {ex.Message}");
|
||
}
|
||
finally
|
||
{
|
||
lock (_operationLock)
|
||
{
|
||
_isProcessing = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空待处理的UI更新队列
|
||
/// </summary>
|
||
public void ClearUpdateQueue()
|
||
{
|
||
var count = 0;
|
||
while (_updateQueue.TryDequeue(out _))
|
||
{
|
||
count++;
|
||
}
|
||
|
||
if (count > 0)
|
||
{
|
||
LogManager.Info($"清空了{count}个待处理的UI更新操作");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 辅助方法
|
||
|
||
/// <summary>
|
||
/// 获取主窗体用于线程调用
|
||
/// </summary>
|
||
/// <returns>主窗体或null</returns>
|
||
private Control GetMainForm()
|
||
{
|
||
try
|
||
{
|
||
// 尝试获取当前活动窗体
|
||
var activeForm = Form.ActiveForm;
|
||
if (activeForm != null)
|
||
{
|
||
return activeForm;
|
||
}
|
||
|
||
// 尝试获取应用程序主窗体
|
||
if (Application.OpenForms.Count > 0)
|
||
{
|
||
return Application.OpenForms[0];
|
||
}
|
||
|
||
return null;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"获取主窗体失败: {ex.Message}");
|
||
return null;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region IDisposable实现
|
||
|
||
/// <summary>
|
||
/// 释放资源
|
||
/// </summary>
|
||
public void Dispose()
|
||
{
|
||
if (_isDisposed)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_isDisposed = true;
|
||
|
||
// 停止并清理保底定时器
|
||
StopIdleProcessor();
|
||
|
||
// 清空队列
|
||
ClearUpdateQueue();
|
||
|
||
LogManager.Info("UIStateManager已释放");
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
#region 支持类和枚举
|
||
|
||
/// <summary>
|
||
/// UI更新操作封装
|
||
/// </summary>
|
||
internal class UIUpdateOperation
|
||
{
|
||
public Guid Id { get; set; }
|
||
public Action Operation { get; set; }
|
||
public UIUpdatePriority Priority { get; set; }
|
||
public DateTime QueueTime { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// UI更新操作优先级
|
||
/// </summary>
|
||
public enum UIUpdatePriority
|
||
{
|
||
/// <summary>
|
||
/// 低优先级 - 非关键UI更新
|
||
/// </summary>
|
||
Low = 0,
|
||
|
||
/// <summary>
|
||
/// 普通优先级 - 标准UI更新
|
||
/// </summary>
|
||
Normal = 1,
|
||
|
||
/// <summary>
|
||
/// 高优先级 - 重要UI更新
|
||
/// </summary>
|
||
High = 2,
|
||
|
||
/// <summary>
|
||
/// 关键优先级 - 关键UI更新,最优先处理
|
||
/// </summary>
|
||
Critical = 3
|
||
}
|
||
|
||
#endregion
|
||
} |