Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

353 linhas
10 KiB

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