using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace GeoSigmaDrawLib { /// /// 提供一个通用的、线程安全的UI调度器(Dispatcher)。 /// 它允许任何后台线程安全地、解耦地在UI线程上执行代码, /// 支持“即发即忘”(Post) 和 “请求/响应”(RequestAsync) 模式。 /// /// /// 此类是一个单例,必须在UI线程上通过调用 方法进行初始化。 /// public class UiDispatcher { private static readonly UiDispatcher InstanceValue = new UiDispatcher(); private SynchronizationContext uiContext = null; private UiDispatcher() { } /// /// 获取 UiDispatcher 的全局单例实例。 /// public static UiDispatcher Instance => InstanceValue; /// /// 初始化调度器。此方法必须在主UI线程上(例如 Program.cs 或主窗体的构造函数/Load事件中)调用一次。 /// /// UI线程的同步上下文。请传入 。 public void Initialize(SynchronizationContext uiContext) { this.uiContext = uiContext ?? throw new ArgumentNullException(nameof(uiContext)); } /// /// [即发即忘] 异步地在UI线程上执行一个无参数的委托。 /// 调用方线程不会等待执行完成。 /// /// 要在UI线程上执行的 。 public void Post(Action action) { CheckInitialized(); uiContext.Post(_ => action(), null); } /// /// [即发即忘] 异步地在UI线程上执行一个带参数的委托。 /// 调用方线程不会等待执行完成。 /// /// 参数的类型。 /// 要在UI线程上执行的 。 /// 要传递给委托的参数(状态)。 public void Post(Action action, T state) { CheckInitialized(); uiContext.Post(s => action((T)s), state); } /// /// [请求/响应] 异步地在UI线程上执行一个“无参数、有返回值”的委托。 /// 调用方(任何线程)可以 await 此方法以非阻塞的方式获取UI线程的执行结果。 /// /// UI线程委托返回值的类型。 /// 要在UI线程上执行并返回结果的 。 /// 一个表示异步操作的任务(Task),其结果 TResult 为UI线程委托的返回值。 public Task RequestAsync(Func func) { CheckInitialized(); var tcs = new TaskCompletionSource(); uiContext.Post( _ => { try { TResult result = func(); tcs.SetResult(result); } catch (Exception ex) { tcs.SetException(ex); } }, null); return tcs.Task; } /// /// [请求/响应] 异步地在UI线程上执行一个“有参数、有返回值”的委托。 /// 调用方(任何线程)可以 await 此方法以非阻塞的方式获取UI线程的执行结果。 /// /// 输入参数的类型。 /// UI线程委托返回值的类型。 /// 要在UI线程上执行并返回结果的 。 /// 要传递给UI线程委托的参数。 /// 一个表示异步操作的任务(Task),其结果 TResult 为UI线程委托的返回值。 public Task RequestAsync(Func func, TInput input) { CheckInitialized(); var tcs = new TaskCompletionSource(); uiContext.Post( state => { try { TResult result = func((TInput)state); tcs.SetResult(result); } catch (Exception ex) { tcs.SetException(ex); } }, input); return tcs.Task; } /// /// [同步请求/响应] 同步地在UI线程上执行一个委托并立即返回结果。 /// /// 警告:此方法会 阻塞 调用方线程(如果是非UI线程),直到UI线程处理完毕。 /// 过度使用可能导致性能问题或线程死锁。请优先使用 。 /// /// /// 返回值的类型。 /// 要在UI线程上执行并返回结果的 。 /// UI线程委托的返回值。 public TResult RequestSend(Func func) { CheckInitialized(); TResult result = default; // 使用 Send 方法进行同步(阻塞)调用 uiContext.Send( _ => { result = func(); }, null); return result; } /// /// 检查调度器是否已成功初始化。 /// /// 如果调度器尚未通过 方法初始化,则抛出此异常。 private void CheckInitialized() { if (uiContext == null) { throw new InvalidOperationException("UiDispatcher尚未初始化。请确保在主UI线程上调用了 Initialize(SynchronizationContext.Current)。"); } } } }