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)。");
}
}
}
}