跳到主要内容

第一个 WinForms 应用

这一篇带你做一个最小 WinForms 上位机窗口:输入文本,点击发送,虚拟通道回显,界面显示通道状态。

先运行示例

在仓库的 code 目录执行:

dotnet run --project samples/Zeus.Samples.WinForms.QuickStart

窗口打开后:

  1. 状态应显示 Open
  2. 输入框默认是 PING
  3. 点击“发送”。
  4. 回显区域应显示 PING

这说明 Zeus 已经把宿主生命周期、通道收发和 UI 线程切换串起来了。

你的项目需要哪些包

dotnet add package Zeus.Communications --prerelease
dotnet add package Zeus.Presentation.WinForms --prerelease

项目文件需要是 Windows 桌面目标:

<TargetFramework>net8.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>

最小窗口代码

using System.Text;
using Zeus;

public sealed class MainForm : Form
{
private readonly TextBox _input = new() { Text = "PING", Dock = DockStyle.Fill };
private readonly Button _send = new() { Text = "发送", Dock = DockStyle.Fill };
private readonly Label _state = new() { Dock = DockStyle.Fill };
private readonly Label _echo = new() { Dock = DockStyle.Fill };
private readonly IChannel _meter;

public MainForm()
{
Text = "Zeus WinForms QuickStart";

var layout = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 4 };
layout.Controls.Add(new Label { Text = "发送" }, 0, 0);
layout.Controls.Add(_input, 1, 0);
layout.Controls.Add(_send, 1, 1);
layout.Controls.Add(new Label { Text = "状态" }, 0, 2);
layout.Controls.Add(_state, 1, 2);
layout.Controls.Add(new Label { Text = "回显" }, 0, 3);
layout.Controls.Add(_echo, 1, 3);
Controls.Add(layout);

var attachment = this.AttachZeus(builder => builder.AddVirtualChannel("meter"));
_meter = attachment.Host.Channels.Get("meter");
_meter.BindState(_state);
_meter.BindTo(_echo);

_send.Click += async (_, _) =>
{
await _meter.WriteAsync(Encoding.UTF8.GetBytes(_input.Text));
};
}
}

实际示例为了更好看和更稳,会多写一些布局、异常弹窗和窗口尺寸设置。核心逻辑就是上面几行。

这段代码怎么理解

代码作用
this.AttachZeus(...)把 Zeus 宿主挂到窗体生命周期上:窗口加载时启动,关闭时释放
builder.AddVirtualChannel("meter")声明一条虚拟通道,先不用真实硬件
attachment.Host.Channels.Get("meter")取出刚才声明的通道
_meter.BindState(_state)把通道状态显示到 Label,例如 Open / Closed
_meter.BindTo(_echo)收到数据后,把文本显示到 Label
_meter.WriteAsync(...)点击按钮时向通道写入字节

为什么不用自己 Invoke

串口和 TCP 的接收事件通常不在 UI 线程上。WinForms 直接在后台线程改控件会抛跨线程异常。

BindToBindState 已经通过 Zeus 的 WinForms 适配器做了线程封送,所以你不需要在每个 DataReceived 里手写 Invoke

换成真实串口

先只改这一行:

var attachment = this.AttachZeus(builder => builder.AddSerialPort("meter", "COM3", 9600));

其它绑定代码不变。如果串口打不开,先确认:端口名、波特率、串口调试助手是否占用端口。

常见问题

现象原因处理
状态一直不是 Open宿主启动失败或通道打开失败看弹窗和控制台日志
点击发送报“当前为 Created”窗口还没完成 Load 或宿主未启动等窗口加载完成后再发,或看状态 Label
绑定后界面没刷新没用 Zeus 的绑定扩展,或控件传错确认调用了 BindTo / BindState
换真实串口后无数据程序结构没问题,问题可能在接线或参数先回到虚拟通道确认界面逻辑,再查硬件

下一步:了解 WinForms 适配器,或直接看 串口