You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让System.Threading.Timer触发的EventHandler在原始线程执行Invoke

实现方案

核心依赖.NET内置的SynchronizationContext(同步上下文)实现线程调度,不需要依赖UI控件的Invoke方法。

通用实现(适用UI线程/带同步上下文的线程)

首先在调用Start方法时捕获当前线程的同步上下文,Timer回调中通过该上下文调度事件执行,修改后的代码如下:

public event EventHandler StatusChanged;
// 存储原始线程的同步上下文
private SynchronizationContext _originalSyncContext;

public void Start()
{
    StatusChanged += new EventHandler(SomethingChangedMethod);
    // 捕获调用Start方法线程的同步上下文
    _originalSyncContext = SynchronizationContext.Current ?? new SynchronizationContext();
    new Timer(Pending, null, 0, 1000);
}

private void Pending(object state)
{
    // 执行定时任务逻辑
    // Do Something
    
    // 异步调度到原始线程执行事件
    // 如果需要同步阻塞等待执行完成,可以替换为Send方法
    _originalSyncContext.Post(_ =>
    {
        StatusChanged?.Invoke(this, EventArgs.Empty);
    }, null);
}

说明:如果调用Start的是WPF/WinForm/MAUI等框架的UI线程,框架会自动提供对应同步上下文实现,上述代码直接生效,事件会自动切回原始UI线程执行。

自定义普通线程调度方案

如果调用Start的是你自己创建的普通工作线程(比如控制台程序的自定义线程),默认没有同步上下文,需要给原始线程添加消息循环,自定义同步上下文实现,示例如下:

1. 实现自定义同步上下文

public class CustomThreadSynchronizationContext : SynchronizationContext
{
    private readonly BlockingCollection<(SendOrPostCallback Callback, object State)> _taskQueue = new();

    // 启动当前线程的消息循环
    public void RunMessageLoop()
    {
        foreach (var task in _taskQueue.GetConsumingEnumerable())
        {
            task.Callback(task.State);
        }
    }

    // 停止消息循环
    public void StopMessageLoop() => _taskQueue.CompleteAdding();

    // 异步调度任务
    public override void Post(SendOrPostCallback d, object state)
    {
        _taskQueue.Add((d, state));
    }

    // 同步调度任务
    public override void Send(SendOrPostCallback d, object state)
    {
        using var waitHandle = new ManualResetEventSlim(false);
        _taskQueue.Add((s =>
        {
            d(s);
            waitHandle.Set();
        }, state));
        waitHandle.Wait();
    }
}

2. 原始线程使用方式

// 原始线程执行逻辑
// 初始化自定义同步上下文
var syncContext = new CustomThreadSynchronizationContext();
// 将上下文绑定到当前线程
SynchronizationContext.SetSynchronizationContext(syncContext);

// 在这里调用你的业务类Start方法
var businessInstance = new YourBusinessClass();
businessInstance.Start();

// 启动消息循环,后续所有调度到该上下文的任务都会在当前线程执行
syncContext.RunMessageLoop();

说明:需要停止原始线程时调用StopMessageLoop方法即可退出消息循环。

内容的提问来源于stack exchange,提问作者rkgghz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 19:27:01