- 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>
79 lines
2.0 KiB
C#
79 lines
2.0 KiB
C#
using System.ComponentModel;
|
|
using Sim.Host;
|
|
|
|
namespace System.Windows.Forms;
|
|
|
|
/// <summary>窗体定时器:Tick 事件总是在界面线程上触发,上一次 Tick 处理完之前不会重复排队</summary>
|
|
public class Timer : Component
|
|
{
|
|
private System.Threading.Timer? _timer;
|
|
private int _interval = 100;
|
|
private bool _enabled;
|
|
private int _tickQueued;
|
|
|
|
public Timer() { }
|
|
|
|
public Timer(IContainer container) : this() => container.Add(this);
|
|
|
|
public int Interval
|
|
{
|
|
get => _interval;
|
|
set
|
|
{
|
|
if (value < 1) throw new ArgumentOutOfRangeException(nameof(value), $"值“{value}”对于 Interval 无效。Interval 必须大于 0。");
|
|
_interval = value;
|
|
if (_enabled) _timer?.Change(value, value);
|
|
}
|
|
}
|
|
|
|
public bool Enabled
|
|
{
|
|
get => _enabled;
|
|
set
|
|
{
|
|
if (_enabled == value) return;
|
|
_enabled = value;
|
|
if (value)
|
|
{
|
|
_timer ??= new System.Threading.Timer(_ => QueueTick());
|
|
_timer.Change(_interval, _interval);
|
|
}
|
|
else
|
|
{
|
|
_timer?.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
|
|
}
|
|
}
|
|
}
|
|
|
|
public object? Tag { get; set; }
|
|
|
|
public event EventHandler? Tick;
|
|
|
|
public void Start() => Enabled = true;
|
|
|
|
public void Stop() => Enabled = false;
|
|
|
|
protected virtual void OnTick(EventArgs e) => Tick?.Invoke(this, e);
|
|
|
|
private void QueueTick()
|
|
{
|
|
if (System.Threading.Interlocked.Exchange(ref _tickQueued, 1) == 1) return;
|
|
SimHost.Ui.Post(() =>
|
|
{
|
|
_tickQueued = 0;
|
|
if (_enabled) OnTick(EventArgs.Empty);
|
|
});
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
_enabled = false;
|
|
_timer?.Dispose();
|
|
_timer = null;
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
}
|