You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

335 rivejä
10 KiB

  1. using ModbusDemo.Device;
  2. using ModbusDemo.Event;
  3. using ModbusDemo.Model;
  4. using Prism.Commands;
  5. using Prism.Events;
  6. using Prism.Mvvm;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO.Ports;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using System.Windows;
  14. namespace ModbusDemo.VIewModel
  15. {
  16. class RegisterUCViewModel : BindableBase
  17. {
  18. //事件聚合器
  19. private readonly IEventAggregator _eventAggregator;
  20. //定义数据库操作类
  21. private ModbusDbContext _modbusDbContext;
  22. //获取读线圈的类
  23. private IModbusRTU _modbusRTU;
  24. //定义读线圈的命令
  25. public DelegateCommand ReadRegisterCmm { get; set; }
  26. //定义写线圈操作
  27. public DelegateCommand WriteRegisterCmm { get; set; }
  28. //获取当前使用的串口
  29. private SerialPort _serialPort;
  30. //按钮是否可以点击
  31. private bool _isEnable;
  32. public bool IsEnable
  33. {
  34. get { return _isEnable; }
  35. set
  36. {
  37. _isEnable = value;
  38. RaisePropertyChanged();
  39. }
  40. }
  41. //显示当前链接串口的信息
  42. public string SerialPortInfo
  43. {
  44. get
  45. {
  46. return "当前为读写寄存器:" + "串口号:" + _serialPort.PortName + ",波特率:" + _serialPort.BaudRate
  47. + ",数据位:" + _serialPort.DataBits + ",校验位:" + _serialPort.Parity + ",停止位:" + _serialPort.StopBits;
  48. }
  49. }
  50. #region 读取定义
  51. //读取的从站id
  52. private string _slaveAddress;
  53. public string SlaveAddress
  54. {
  55. get { return _slaveAddress; }
  56. set
  57. {
  58. _slaveAddress = value;
  59. RaisePropertyChanged();
  60. }
  61. }
  62. //读取的起始地址
  63. private string _startAddress;
  64. public string StartAddress
  65. {
  66. get { return _startAddress; }
  67. set
  68. {
  69. _startAddress = value;
  70. RaisePropertyChanged();
  71. }
  72. }
  73. //读取的位数
  74. private string _numberOfPoints;
  75. public string NumberOfPoints
  76. {
  77. get { return _numberOfPoints; }
  78. set
  79. {
  80. _numberOfPoints = value;
  81. RaisePropertyChanged();
  82. }
  83. }
  84. private string _readResult;
  85. //读取的结果
  86. public string ReadResult
  87. {
  88. get { return _readResult; }
  89. set
  90. {
  91. _readResult = value;
  92. RaisePropertyChanged();
  93. }
  94. }
  95. #endregion
  96. #region 写入定义
  97. //写入的从站id
  98. private string _writeslaveAddress;
  99. public string WriteSlaveAddress
  100. {
  101. get { return _writeslaveAddress; }
  102. set
  103. {
  104. _writeslaveAddress = value;
  105. RaisePropertyChanged();
  106. }
  107. }
  108. //写入的起始地址
  109. private string _writestartAddress;
  110. public string WriteStartAddress
  111. {
  112. get { return _writestartAddress; }
  113. set
  114. {
  115. _writestartAddress = value;
  116. RaisePropertyChanged();
  117. }
  118. }
  119. //写入的数据
  120. private string _writeData;
  121. public string WriteData
  122. {
  123. get { return _writeData; }
  124. set
  125. {
  126. _writeData = value;
  127. RaisePropertyChanged();
  128. }
  129. }
  130. #endregion
  131. private List<ModbusLog> _modbusLogList;
  132. public List<ModbusLog> ModbusLogList
  133. {
  134. get { return _modbusLogList; }
  135. set
  136. {
  137. _modbusLogList = value;
  138. RaisePropertyChanged();
  139. }
  140. }
  141. public RegisterUCViewModel()
  142. {
  143. }
  144. public RegisterUCViewModel(SerialPort serialPort, ModbusRTU modbusRTU, ModbusDbContext modbusDbContext, IEventAggregator eventAggregator)
  145. {
  146. _serialPort = serialPort;
  147. ReadRegisterCmm = new DelegateCommand(ReadRegister);
  148. _modbusRTU = modbusRTU;
  149. WriteRegisterCmm = new DelegateCommand(WriteRegister);
  150. _modbusDbContext = modbusDbContext;
  151. _eventAggregator = eventAggregator;
  152. // 订阅事件(使用弱引用,避免内存泄漏)
  153. _eventAggregator.GetEvent<SerialPortSettingsChangedEvent>().Subscribe(
  154. OnSerialPortSettingsChanged,
  155. ThreadOption.UIThread, // 在UI线程执行回调
  156. false);// 不使用强引用
  157. ModbusLogList = GetOperateRegister();
  158. IsEnable = true;
  159. }
  160. // 事件回调方法:当串口设置变更时触发
  161. private void OnSerialPortSettingsChanged()
  162. {
  163. // 强制刷新SerialPortInfo属性,触发UI更新
  164. RaisePropertyChanged(nameof(SerialPortInfo));
  165. }
  166. /// <summary>
  167. /// 线圈读取操作
  168. /// </summary>
  169. private void ReadRegister()
  170. {
  171. //将按钮设置为不可点击状态,并解析用户输入的信息
  172. IsEnable = false;
  173. if (!byte.TryParse(SlaveAddress, out byte slaveAddressValue))
  174. {
  175. MessageBox.Show("SlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  176. IsEnable = true;
  177. return;
  178. }
  179. if (!ushort.TryParse(StartAddress, out ushort startAddressValue))
  180. {
  181. MessageBox.Show("StartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  182. IsEnable = true;
  183. return;
  184. }
  185. if (!ushort.TryParse(NumberOfPoints, out ushort numberOfPointsValue))
  186. {
  187. MessageBox.Show("NumberOfPoints 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  188. IsEnable = true;
  189. return;
  190. }
  191. //使用子线程进行读取,防止ui线程卡顿
  192. Task.Run(() =>
  193. {
  194. ushort[] result = _modbusRTU.ReadRegisters(slaveAddressValue, startAddressValue, numberOfPointsValue);
  195. if (result == null)
  196. {
  197. MessageBox.Show("读取失败", "error", MessageBoxButton.OK, MessageBoxImage.Error);
  198. ModbusLogList = GetOperateRegister();
  199. IsEnable = true;
  200. return;
  201. }
  202. string temp = "";
  203. int count =0;
  204. foreach (var item in result)
  205. {
  206. count++;
  207. temp += item;
  208. temp += " ";
  209. if (count % 25 == 0)
  210. {
  211. temp += "\n";
  212. }
  213. }
  214. ReadResult = temp;
  215. MessageBox.Show("读取成功");
  216. IsEnable = true;
  217. ModbusLogList = GetOperateRegister();
  218. });
  219. }
  220. private void WriteRegister()
  221. {
  222. //将按钮设置为不可点击状态,并解析用户输入的信息
  223. IsEnable = false;
  224. if (!byte.TryParse(WriteSlaveAddress, out byte writeSlaveAddressValue))
  225. {
  226. MessageBox.Show("WriteSlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  227. IsEnable = true;
  228. return;
  229. }
  230. if (!ushort.TryParse(WriteStartAddress, out ushort WriteStartAddressValue))
  231. {
  232. MessageBox.Show("WriteStartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  233. IsEnable = true;
  234. return;
  235. }
  236. if (string.IsNullOrEmpty(WriteData))
  237. {
  238. MessageBox.Show("WriteData 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  239. IsEnable = true;
  240. return;
  241. }
  242. string[] parts = WriteData.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  243. // 3. 创建结果数组
  244. ushort[] data = new ushort[parts.Length];
  245. // 4. 遍历并转换每个部分
  246. for (int i = 0; i < parts.Length; i++)
  247. {
  248. // 尝试解析为ushort
  249. if (ushort.TryParse(parts[i], out ushort value))
  250. {
  251. data[i] = value;
  252. }
  253. else
  254. {
  255. MessageBox.Show($"无法将 '{parts[i]}' 转换为 ushort 类型");
  256. IsEnable = true;
  257. return;
  258. }
  259. }
  260. //使用子线程来去执行操作,防止ui线程卡顿
  261. Task.Run(() =>
  262. {
  263. _modbusRTU.WriteRegisters(writeSlaveAddressValue, WriteStartAddressValue, data);
  264. ModbusLogList = GetOperateRegister();
  265. ModbusLog modbusLog = ModbusLogList.FirstOrDefault();
  266. if (modbusLog != null && modbusLog.ResponseData != string.Empty && modbusLog.ResponseData[3] != '8')
  267. {
  268. MessageBox.Show("写入成功");
  269. IsEnable = true;
  270. }
  271. else
  272. {
  273. MessageBox.Show("写入失败", "error", MessageBoxButton.OK, MessageBoxImage.Error);
  274. IsEnable = true;
  275. }
  276. });
  277. }
  278. /// <summary>
  279. /// 获取展示数据
  280. /// </summary>
  281. /// <returns></returns>
  282. private List<ModbusLog> GetOperateRegister()
  283. {
  284. return _modbusDbContext.ModbusLog
  285. .Where(log => log.OperationType == "读寄存器" || log.OperationType == "写寄存器")
  286. .OrderByDescending(log => log.Time) // 按时间倒序,最新的在前
  287. .Take(20) // 只取前20条记录
  288. .ToList(); // 执行查询
  289. }
  290. }
  291. }