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.

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