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.

321 regels
9.5 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. /// <summary>
  17. /// 这是CoilUC的VM用来支持数据绑定
  18. /// </summary>
  19. public class CoilUCViewModel : BindableBase
  20. {
  21. //事件聚合器
  22. private readonly IEventAggregator _eventAggregator;
  23. //定义数据库操作
  24. private ModbusDbContext _modbusDbContext;
  25. //获取读线圈的类
  26. private IModbusRTU _modbusRTU;
  27. //定义读线圈的命令
  28. public DelegateCommand ReadCoilCmm { get; set; }
  29. //定义写线圈操作
  30. public DelegateCommand WriteCoilCmm { get; set; }
  31. //获取当前使用的串口
  32. private SerialPort _serialPort;
  33. //显示当前链接串口的信息
  34. //按钮是否可以点击
  35. private bool _isEnable;
  36. public bool IsEnable
  37. {
  38. get { return _isEnable; }
  39. set
  40. {
  41. _isEnable = value;
  42. RaisePropertyChanged();
  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. }
  131. }
  132. #endregion
  133. private List<ModbusLog> _modbusLogList;
  134. public List<ModbusLog> ModbusLogList
  135. {
  136. get { return _modbusLogList; }
  137. set
  138. {
  139. _modbusLogList = value;
  140. RaisePropertyChanged();
  141. }
  142. }
  143. public CoilUCViewModel()
  144. {
  145. }
  146. public CoilUCViewModel(SerialPort serialPort, ModbusRTU modbusRTU, ModbusDbContext modbusDbContext, IEventAggregator eventAggregator)
  147. {
  148. _serialPort = serialPort;
  149. ReadCoilCmm = new DelegateCommand(ReadCoil);
  150. _modbusRTU = modbusRTU;
  151. WriteCoilCmm = new DelegateCommand(WriteCoil);
  152. _modbusDbContext = modbusDbContext;
  153. _eventAggregator = eventAggregator;
  154. // 订阅事件(使用弱引用,避免内存泄漏)
  155. _eventAggregator.GetEvent<SerialPortSettingsChangedEvent>().Subscribe(
  156. OnSerialPortSettingsChanged,
  157. ThreadOption.UIThread, // 在UI线程执行回调
  158. false);// 不使用强引用
  159. //初始化查询操作
  160. ModbusLogList = GetOperateCoil();
  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 ReadCoil()
  173. {
  174. //将按钮设置为不可点击状态,并解析用户输入的信息
  175. IsEnable = false;
  176. if (!byte.TryParse(SlaveAddress, out byte slaveAddressValue))
  177. {
  178. MessageBox.Show("SlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  179. IsEnable = true;
  180. return;
  181. }
  182. if (!ushort.TryParse(StartAddress, out ushort startAddressValue))
  183. {
  184. MessageBox.Show("StartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  185. IsEnable = true;
  186. return;
  187. }
  188. if (!ushort.TryParse(NumberOfPoints, out ushort numberOfPointsValue))
  189. {
  190. MessageBox.Show("NumberOfPoints 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  191. IsEnable = true;
  192. return;
  193. }
  194. //使用子线程,防止ui线程卡顿
  195. Task.Run(() =>
  196. {
  197. bool[] result = _modbusRTU.ReadCoil(slaveAddressValue, startAddressValue, numberOfPointsValue);
  198. if (result == null)
  199. {
  200. MessageBox.Show("读取失败", "error", MessageBoxButton.OK, MessageBoxImage.Error);
  201. ModbusLogList = GetOperateCoil();
  202. IsEnable = true;
  203. return;
  204. }
  205. string temp = "";
  206. foreach (var item in result)
  207. {
  208. temp += item;
  209. temp += " ";
  210. }
  211. ReadResult = temp;
  212. MessageBox.Show("读取成功");
  213. IsEnable = true;
  214. ModbusLogList = GetOperateCoil();
  215. });
  216. }
  217. private void WriteCoil()
  218. {
  219. //将按钮设置为不可点击状态,并解析用户输入的信息
  220. IsEnable = false;
  221. if (!byte.TryParse(WriteSlaveAddress, out byte writeSlaveAddressValue))
  222. {
  223. MessageBox.Show("WriteSlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  224. IsEnable = true;
  225. return;
  226. }
  227. if (!ushort.TryParse(WriteStartAddress, out ushort WriteStartAddressValue))
  228. {
  229. MessageBox.Show("WriteStartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  230. IsEnable = true;
  231. return;
  232. }
  233. if (string.IsNullOrEmpty(WriteData))
  234. {
  235. MessageBox.Show("WriteData 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning);
  236. IsEnable = true;
  237. return;
  238. }
  239. //去除字符串中的空格
  240. WriteData = WriteData.Replace(" ", "");
  241. //转换为布尔数组
  242. bool[] data = WriteData.Select(m => m == '1').ToArray();
  243. //使用子线程执行,避免ui线程卡顿
  244. Task.Run(() =>
  245. {
  246. _modbusRTU.WriteCoil(writeSlaveAddressValue, WriteStartAddressValue, data);
  247. ModbusLogList = GetOperateCoil();
  248. ModbusLog modbusLog = ModbusLogList.FirstOrDefault();
  249. if (modbusLog != null && modbusLog.ResponseData != string.Empty && modbusLog.ResponseData[3] !='8')
  250. {
  251. MessageBox.Show("写入成功");
  252. IsEnable = true;
  253. }
  254. else
  255. {
  256. MessageBox.Show("写入失败", "error", MessageBoxButton.OK, MessageBoxImage.Error);
  257. IsEnable = true;
  258. }
  259. });
  260. }
  261. /// <summary>
  262. /// 获取展示数据
  263. /// </summary>
  264. /// <returns></returns>
  265. private List<ModbusLog> GetOperateCoil()
  266. {
  267. return _modbusDbContext.ModbusLog
  268. .Where(log => log.OperationType == "读线圈" || log.OperationType == "写线圈")
  269. .OrderByDescending(log => log.Time) // 按时间倒序,最新的在前
  270. .Take(20) // 只取前20条记录
  271. .ToList(); // 执行查询
  272. }
  273. }
  274. }