WinForms + SQLite 实战:给工厂做一套报工系统,替掉 3 本纸质台账(10 天交付、8 个月零维护)
一、需求不是「上系统」,而是「把纸换成数据」
去年给一家做五金件的小厂看现场,车间的现状是这样的:质量一本台账、产量一本台账、异常一本台账。早班工人手写报工,午休时班长核一遍,晚上文员再逐页敲进 Excel。三本账对不上的那天,全车间一起加班找数据。
老板的诉求其实非常朴素:
- 不改变工人的操作习惯(原话是「老张五十多了,你让他学新东西他不会」)
- 月底能直接拉出报表,不用再对三本纸账
- 别搞服务器、别搞一堆部署步骤,车间那台老电脑直接就能跑
这三条约束基本就定死了技术选型。
二、为什么选 WinForms 而不是 WPF
很多人第一反应是「2026 年了还 WinForms?」,但在这个场景里 WinForms 是对的:
约束一:客户电脑是老 Win7 一体机。WinForms 对老系统的兼容性和启动速度,比 WPF 有优势(没有复杂的硬件加速依赖,老显卡不会出现渲染异常)。
约束二:界面极其简单。整个系统只有 3 个界面,最大的界面就是几个大按钮加一个输入框。WPF 的 MVVM、样式体系、数据绑定在这里是纯粹的过度设计,反而增加维护成本。
约束三:要免安装。WinForms 单文件发布后是一个 exe,双击就跑;不需要 .NET 运行时的话可以自包含发布,体积代价可接受。
如果这个项目的界面复杂、有大量动画或者需要皮肤切换,我会选 WPF。但这里是「一个大按钮 + 一张表」,选 WPF 是给自己找活。
三、四个关键实现
3.1 扫码枪:它本质上就是一个键盘
很多人以为接扫码枪要写驱动或者串口通讯,其实不是。市面上的 USB 扫码枪绝大多数工作在 HID 键盘模式——它把扫到的条码当作一串键盘按键「打」进当前焦点窗口,末尾自动补一个回车。
所以服务端只需要在窗体级别处理键盘事件,靠输入间隔把扫码和人工手打区分开:
private readonly StringBuilder _barcode = new();
private DateTime _lastKeyTime = DateTime.Now;
private void FormMain_KeyPress(object sender, KeyPressEventArgs e)
{
// 扫码枪是键盘仿真设备:极短间隔连续输入,末尾一个回车
// 人工手打间隔通常 > 300ms,以此区分
if ((DateTime.Now - _lastKeyTime).TotalMilliseconds > 300)
_barcode.Clear();
_lastKeyTime = DateTime.Now;
if (e.KeyChar == '\r') // 扫码结束
{
var code = _barcode.ToString().Trim();
_barcode.Clear();
if (code.Length > 0) SubmitReport(code);
e.Handled = true;
return;
}
if (!char.IsControl(e.KeyChar)) _barcode.Append(e.KeyChar);
}
两个容易踩的坑:
- 焦点丢失。工人点了别的地方,扫码就打到别的控件上去了。解决办法是把
KeyPreview = true,在窗体层拦截,并且在LostFocus时自动把焦点抢回来。 - 输入法。如果当前是中文输入法,条码会被输入法吞掉。上线前一定要在机器上把输入法设为英文,或者程序启动时调
ImmAssociateContext禁用输入法。
3.2 断网可用:SQLite 本地库
车间网络抽风是常态,所以数据必须先落本地。SQLite + Microsoft.Data.Sqlite 就够,日产量几百条这个量级根本不需要考虑 WAL 和并发优化(单用户单进程,写入压力可以忽略)。
private const string ConnString = "Data Source=report.db;Cache=Shared";
public static void InitDb()
{
using var conn = new SqliteConnection(ConnString);
conn.Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"
CREATE TABLE IF NOT EXISTS ReportRecord(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
WorkOrder TEXT NOT NULL,
Station TEXT NOT NULL,
Qty INTEGER NOT NULL,
CreatedAt TEXT NOT NULL -- ISO8601,方便按天/按周分组
);
CREATE INDEX IF NOT EXISTS idx_report_created ON ReportRecord(CreatedAt);";
cmd.ExecuteNonQuery();
}
时间统一存 ISO8601 字符串(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),SQLite 的 date(CreatedAt) 直接就能按天聚合,省掉一层转换。
3.3 报表导出:ClosedXML,不依赖客户装没装 Office
这是踩过的坑:最早用 COM 调 Excel 导出,客户机器上是 WPS,直接报错;换了 Microsoft.Office.Interop.Excel 也是一样的下场,而且还会残留后台进程。
最后换成 ClosedXML(纯托管库,写 .xlsx 不需要 Office):
public static void ExportDaily(string path, DateTime day)
{
var rows = QueryDaily(day); // List<(string Station, string Order, int Qty)>
using var wb = new XLWorkbook();
var ws = wb.AddWorksheet("产量日报");
ws.Cell(1, 1).Value = "工位";
ws.Cell(1, 2).Value = "工单号";
ws.Cell(1, 3).Value = "数量";
ws.Row(1).Style.Font.Bold = true;
for (int i = 0; i < rows.Count; i++)
{
ws.Cell(i + 2, 1).Value = rows[i].Station;
ws.Cell(i + 2, 2).Value = rows[i].Order;
ws.Cell(i + 2, 3).Value = rows[i].Qty;
}
ws.Columns().AdjustToContents();
ws.RangeUsed()?.SetAutoFilter(); // 文员拿到就能直接筛
wb.SaveAs(path);
}
纸质报表则用 PrintDocument 直接打,不经过 Excel 这条链路,稳定得多。
3.4 免安装部署:一行注册表搞定开机自启
车间电脑不需要「启动软件」这个动作,开机就该在跑:
using var key = Registry.CurrentUser.OpenSubKey(
@"Software\Microsoft\Windows\CurrentVersion\Run", writable: true);
key?.SetValue("WorkshopReport", Application.ExecutablePath);
部署方式:整个目录拷到车间电脑 D:\WorkshopReport\,双击一次 exe(首次会写注册表),之后开机自动运行。不做安装包——安装包在老电脑上反而容易出问题(权限、杀软拦截)。
四、结果
上线 8 个多月的数据:
| 指标 | 改造前 | 改造后 |
|---|---|---|
| 台账本数 | 3 本纸质 | 0 |
| 日汇总耗时 | 40 分钟/天 | 自动生成 |
| 月底对账 | 2 天 | 10 分钟 |
| 交付周期 | — | 10 个工作日 |
| 现场维护次数 | — | 0 |
工人侧的变化几乎为零:选工位 → 扫工单 → 点「报工」,三步。年纪最大的师傅大概 5 分钟上手。
五、什么时候不该这么做
这套方案有明确的适用边界,我不想把它说成万能药:
- 日产量上万条、多车间多班次联动:该上 MES,本地 SQLite 撑不住这种协同复杂度
- 需要和 ERP、财务系统实时打通:那必须有服务端,单机库做不了数据同步
- 界面复杂、有大量实时图表:WPF 或 Web 更合适
判断标准很简单:如果「数据只在一个车间内流转、汇总颗粒度是天」,那 WinForms + SQLite 的性价比远高于任何 B/S 方案——没有服务器成本、没有网络依赖、没有浏览器兼容问题,交付周期还能压缩到两周以内。
我是杨加林,21 年 .NET 桌面客户端研发,专注 WPF / WinForms 定制、单机小工具与上位机数据采集。如果你们的车间 / 仓库也有类似的「纸质台账 → 数据化」需求,或者有存量 WinForms / WPF 项目需要维护和性能优化,可以直接找我聊:
手机 17788568694 | 微信 17788568694(与手机同号)| QQ 76656825
沟通时最好带上这三点,我能直接给你判断方案和大致工期:① 要解决的具体问题 ② 谁用、多少人用 ③ 期望什么时候上线。

浙公网安备 33010602011771号