Files
IOT_SIM/runtime/Sim.WinForms/Host/UiDispatcher.cs
T
xuyueandClaude Opus 5.5 98be8331bc 第 0 阶段:教材项目 2 任务 1 在网页中原样运行
- runtime:仿真 WinForms 子集(Form、Button、Label、TextBox、ComboBox、
  GroupBox、Timer、MessageBox、界面线程消息循环、跨线程检查)、
  教材设备类库(DeviceCtrlHelper、LED 控件)、运行器(常驻编译服务 + 运行模式)
- server:Bun + Hono,WebSocket 会话,每次运行一个进程,消息转发
- web:Vue + Naive UI,WinForms 风格窗体渲染、MessageBox、实训台 LED 屏
- 端到端测试与 100 个程序并发的压力测试
- 教材逐任务摘要(docs/教材摘要)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 10:15:14 +08:00

81 lines
2.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace Sim.Host;
/// <summary>
/// 模拟 WinForms 的界面线程消息循环:所有用户操作、Timer.Tick、Invoke 都排队到界面线程上依次执行。
/// </summary>
public sealed class UiDispatcher
{
private readonly BlockingCollection<Action> _queue = new();
public Thread? UiThread { get; private set; }
public bool IsUiThread => Thread.CurrentThread == UiThread;
/// <summary>由运行器在启动学生程序的线程上调用一次</summary>
public void BindToCurrentThread() => UiThread = Thread.CurrentThread;
public void Post(Action action) => _queue.Add(action);
/// <summary>在界面线程上同步执行(Control.Invoke、SynchronizationContext.Send)</summary>
public void Send(Action action)
{
if (IsUiThread)
{
action();
return;
}
using var done = new ManualResetEventSlim();
Exception? error = null;
Post(() =>
{
try { action(); }
catch (Exception ex) { error = ex; }
finally { done.Set(); }
});
done.Wait();
if (error != null) throw new System.Reflection.TargetInvocationException(error);
}
/// <summary>
/// 运行消息循环,直到 <paramref name="done"/> 为真。可以嵌套:
/// Application.Run、ShowDialog、MessageBox.Show 都会在这里等待,期间 Timer 等照常执行。
/// </summary>
public void RunUntil(Func<bool> done)
{
while (!done())
{
if (_queue.TryTake(out var action, 50)) Execute(action);
}
}
/// <summary>处理队列里已有的消息后返回(Application.DoEvents)</summary>
public void DoEvents()
{
while (_queue.TryTake(out var action)) Execute(action);
}
/// <summary>唤醒等待中的消息循环,让它重新检查结束条件</summary>
public void Wake() => Post(static () => { });
private static void Execute(Action action)
{
try
{
action();
}
catch (Exception ex)
{
// 真实 WinForms 会弹出"未经处理的异常"对话框,点"继续"后程序接着运行,这里同样继续
SimHost.ReportException(ex);
}
finally
{
SimHost.FlushChanges();
}
}
}