乐于分享
好东西不私藏

工业上位机开发没头绪?这个 WPF 模板把 SCADA 和大屏都给整明白了

工业上位机开发没头绪?这个 WPF 模板把 SCADA 和大屏都给整明白了

前言

工业现场总少不了各种仪表、泵阀和温度液位数据,可每个项目都从头写一套监控界面实在不划算。大部分时间都花在重复的通讯调试和界面布局上,真正花在业务逻辑上的精力反而被压缩了。

本文推荐一个 WPF 开发的通用 SCADA 模板项目,把 Modbus TCP 通讯、报警管理、参数读写、趋势导出这些基础能力都集成进去,下次接到新项目时直接拿过来就能用。

项目介绍

项目是一个面向工业自动化监控的桌面应用程序,核心定位是"拿来即用的 SCADA 起点"。它内置了 Modbus TCP 客户端,支持读写保持寄存器和输入寄存器,涵盖了常用的整型、浮点型数据解析。

界面部分模拟了一个小型工艺流程的监控总览,包含温度显示、泵阀状态、报警列表、参数配置面板和趋势数据导出功能。无论是做设备测试、数据采集,还是搭建正式的监控系统,这个模板都能省掉不少重复劳动。

项目功能

功能模块
具体内容
实时监控总览
显示工艺参数(温度、液位、泵频率)、设备状态列表、开关量输入输出状态
Modbus TCP 通讯
支持读取/写入保持寄存器、输入寄存器;支持 UInt16、Int16、Float32 等数据类型
参数配置与下发
在界面上修改工艺参数,通过 Modbus 批量下发到 PLC 或仪表
报警管理
实时报警列表展示,支持单条确认和全部确认,确认后报警移除
趋势数据导出
按时间范围(1/2/4/8/12/24 小时)导出 CSV 格式的趋势数据
设备维护管理
自动生成设备维护工单,列出所有非正常状态的设备
系统设置持久化
Modbus 连接参数和点位配置保存为 JSON 文件,下次启动自动加载
窗口控制
最小化、最大化/还原、退出应用程序

项目特点

开箱即用:项目包含了完整的视图模型、服务层和模拟数据,Clone 下来就能直接运行

通讯抽象清晰:Modbus 读写操作被封装成独立的 Service,调用方不需要关心 TCP 连接细节和报文组拆

数据编解码统一:通过 ModbusValueCodec 静态类处理字节序(大端/小端、字序/字节序)和数据类型的转换

异步操作安全:所有 Modbus 操作都带有忙状态锁,界面不会卡死,避免重复点击触发并发通讯冲突

实时数据刷新:每秒自动更新温度、液位等过程量,模拟运行状态下数据动态变化

配置可迁移:点位映射、寄存器地址、数据类型、倍率等信息都保存在 JSON 配置文件中,便于跨机器迁移

交互反馈及时:每个操作都有对应的操作消息提示,通讯失败时会有明确的错误信息展示

项目技术

技术项
说明
开发框架
.NET 8/WPF
UI 框架
WPF + MVVM 模式
通讯协议
Modbus TCP(基于 NModbus4 库)
数据持久化
System.Text.Json
异步编程
async / await
依赖注入
手动构造(未引入第三方 DI 容器,便于理解)
数据绑定
ObservableCollection + INotifyPropertyChanged
定时任务
DispatcherTimer(UI 线程安全)
命令绑定
RelayCommand / AsyncRelayCommand

项目代码

1、Modbus 服务层

通讯层的核心是 ModbusTcpClientService,它封装了 NModbus4 的 ModbusIpMaster,提供了读写寄存器的异步方法。

调用方只需要传入 IP、端口、站号、寄存器区和起始地址即可,不用关心连接池和异常重试细节。

publicasync Task<ushort[]> ReadRegistersAsync(string host,int port,byte unitId,    ModbusRegisterArea area,ushort startAddress,ushort length){await EnsureConnectedAsync(host, port);return area == ModbusRegisterArea.HoldingRegister        ? await master.ReadHoldingRegistersAsync(unitId, startAddress, length)        : await master.ReadInputRegistersAsync(unitId, startAddress, length);}

2、数据编解码器

工业通讯中最头疼的就是字节序问题。ModbusValueCodec 把不同数据类型的编码解码逻辑集中处理,支持大端/小端字节序、字序调整,以及 Float32、Int16、UInt16 的相互转换。

publicstaticdoubleDecode(ushort[] registers, ModbusPoint point){var bytes = registers.SelectMany(BitConverter.GetBytes).ToArray();// 根据 ByteOrder 调整字节序列// 根据 WordOrder 调整字序列// 根据 DataType 调用对应的转换方法return rawValue * point.Scale;}

3、主视图模型

MainViewModel 承担了界面状态管理和业务逻辑编排。它维护了设备集合、报警消息、Modbus 点位列表,以及启动/停止、参数读写、报警确认等命令。所有界面操作最终都会收敛到这个类中,便于后续维护和单元测试。

privateasync Task ExecuteModbusAsync(Func<Task> action){try    {        IsModbusBusy = true;await action();    }catch (Exception ex)    {        OperationMessage = $"Modbus TCP 操作失败:{ex.Message}";    }finally    {        IsModbusBusy = false;    }}

4、配置持久化

系统设置和点位映射通过 JSON 文件保存,加载时反序列化到内存对象,保存时从界面状态生成文档结构。这样在不同设备之间迁移配置就变得非常简单。

publicsealedclassModbusSettingsDocument{publicstring Host { getset; } = "127.0.0.1";publicint Port { getset; } = 502;publicint UnitId { getset; } = 1;public List<ModbusPointSettings> Points { getset; } = new();}

项目效果

运行起来后,主界面分为几个核心区域:

顶部状态栏:显示当前时间、系统运行状态(运行中/已停止)、操作消息提示

顶部导航栏:监控总览、参数配置、报警记录、趋势曲线、设备维护、系统设置六个页面入口

监控总览:展示两路温度数值、液位百分比、泵阀开关状态、设备列表(含状态指示灯)和开关量状态

参数配置页面:列出所有 Modbus 点位,可修改数值后点击"写入参数"下发到设备,也可以点击"读取参数"从设备拉取最新值

报警记录页面:表格展示报警时间、设备名称、报警内容,每条报警右侧有确认按钮,顶部有一键全部确认

趋势曲线页面:可以选择 1/2/4/8/12/24 小时时间范围,点击导出生成 CSV 文件

设备维护页面:点击生成工单,系统自动扫描所有非正常状态的设备,生成包含设备名称、状态、描述和当前值的文本工单

界面配色以深色为基调,状态指示灯用绿色(正常)、黄色(警告)、红色(故障)、灰色(离线)区分,看起来比较符合工业监控软件的调性。

项目源码

项目结构如下

├── xxxx.csproj├── App.xaml / App.xaml.cs├── MainWindow.xaml / MainWindow.xaml.cs├── Views/                 # 页面视图│   ├── OverviewPage.xaml│   ├── ParametersPage.xaml│   ├── AlarmsPage.xaml│   ├── TrendsPage.xaml│   ├── MaintenancePage.xaml│   └── SettingsPage.xaml├── ViewModels/            # 视图模型│   ├── MainViewModel.cs│   ├── ObservableObject.cs│   └── RelayCommand.cs / AsyncRelayCommand.cs├── Models/                # 数据模型│   ├── DeviceStatus.cs│   ├── MessageItem.cs│   ├── OptionItem.cs│   ├── ParameterItem.cs│   ├── ModbusPoint.cs│   └── ModbusSettingsDocument.cs├── Services/              # 服务层│   ├── ModbusTcpClientService.cs│   └── ModbusValueCodec.cs├── Infrastructure/        # 基础设施│   ├── StatusKind.cs│   ├── ModbusEnums.cs│   └── ObservableObject.cs└── Config/                # 配置文件(运行时生成)    └── modbus-settings.json

源码中已经包含了完整的模拟数据,在没有实际 PLC 的情况下也可以直接运行体验。如果接入真实设备,只需要修改 ModbusHostModbusPort 和 ModbusUnitId,并调整点位地址和数据类型即可。 

总结

这个 SCADA 模板项目提供一个干净、可扩展的基础框架。它把工业监控系统中常见的几个痛点——通讯封装、数据解析、状态管理、配置持久化——都做了比较合理的抽象。

实际使用时,可以根据项目需要添加新的协议(如 OPC UA、MQTT)、增加历史数据存储(SQLite 或时序数据库)、完善用户权限管理等功能。框架的 MVVM 结构让这些扩展变得相对容易,不会牵一发而动全身。

如果大家正准备做一个工业监控相关的项目,可以从这套模板入手,把精力集中在业务逻辑和工艺算法上,而不是从零开始折腾通讯和界面。