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.

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