UCDeviceConfig.xaml.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. using MV485.Dlg;
  2. using MV485.helper;
  3. using MV485.model;
  4. using MV485.util;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using System.Windows;
  12. using System.Windows.Controls;
  13. using System.Windows.Data;
  14. using System.Windows.Documents;
  15. using System.Windows.Input;
  16. using System.Windows.Media;
  17. using System.Windows.Media.Imaging;
  18. using System.Windows.Navigation;
  19. using System.Windows.Shapes;
  20. using Path = System.IO.Path;
  21. namespace MV485.uc
  22. {
  23. /// <summary>
  24. /// UCDeviceConfig.xaml 的交互逻辑
  25. /// </summary>
  26. public partial class UCDeviceConfig : UserControl
  27. {
  28. private static readonly string LogFilePath =
  29. Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Documents", "config_log.txt");
  30. private RWBasicConfig _rwBaseConfig = null;
  31. private List<LogEntry> _logEntries = new List<LogEntry>();
  32. private BasicConfig _readConfig;
  33. public UCDeviceConfig()
  34. {
  35. InitializeComponent();
  36. InitLoad();
  37. LoadConfigLog();
  38. }
  39. //初始化加载
  40. private void LoadSerialPorts()
  41. {
  42. Dispatcher.BeginInvoke(new Action(() =>
  43. {
  44. cmbPortNames.ItemsSource = SerialHelper.GetSerialPortsWithDetails();
  45. if (cmbPortNames.Items.Count > 0)
  46. cmbPortNames.SelectedIndex = 0;
  47. var portName = ConfigManager.Instance.GetConfigValue(ConfigKey.ConfigPortName, "");
  48. cmbPortNames.SelectedValue = portName;
  49. }));
  50. }
  51. private void InitLoad()
  52. {
  53. //与设备通信的参数
  54. cmbBaudrate.ItemsSource = SerialHelper.BaudRates;
  55. var baudrates = ConfigManager.Instance.GetConfigValue(ConfigKey.ConfigBaudrate, "9600");
  56. cmbBaudrate.SelectedValue = baudrates;
  57. cmbDevId.ItemsSource = Enumerable.Range(1, 247).ToList();
  58. var devId = ConfigManager.Instance.GetConfigValue(ConfigKey.ConfigDevId, "1");
  59. cmbDevId.Text = devId;
  60. //从设备读取或要设置的参数
  61. cmbDevBaudrate.ItemsSource = SerialHelper.BaudRates;
  62. cmbDevAddress.ItemsSource = Enumerable.Range(1, 247).ToList();
  63. LoadSerialPorts();
  64. InitConfiView();
  65. }
  66. private void btnRefreshPorts_Click(object sender, RoutedEventArgs e)
  67. {
  68. LoadSerialPorts();
  69. AppendLog("串口列表已刷新");
  70. }
  71. private void CmbPortNames_SelectionChanged(object sender, SelectionChangedEventArgs e)
  72. {
  73. //var portName = cmbPortNames.SelectedValue.ToString();
  74. //ConfigManager.Instance.UpdateConfig(ConfigKey.ConfigPortName, portName);
  75. }
  76. private async void BtnReadConfig_Click(object sender, RoutedEventArgs e)
  77. {
  78. //串口号
  79. if(cmbPortNames.SelectedItem == null)
  80. {
  81. MessageBox.Show(Application.Current.MainWindow, "请选择串口", "提示",
  82. MessageBoxButton.OK, MessageBoxImage.Warning);
  83. return;
  84. }
  85. var portName = cmbPortNames.SelectedValue.ToString();
  86. ConfigManager.Instance.UpdateConfig(ConfigKey.ConfigPortName, portName);
  87. //波特率
  88. if(cmbBaudrate.SelectedItem == null)
  89. {
  90. MessageBox.Show(Application.Current.MainWindow, "请选择波特率", "提示",
  91. MessageBoxButton.OK, MessageBoxImage.Warning);
  92. return;
  93. }
  94. var sBaudrate = cmbBaudrate.SelectedValue.ToString();
  95. ConfigManager.Instance.UpdateConfig(ConfigKey.ConfigBaudrate, sBaudrate);
  96. if(!byte.TryParse(cmbDevId.Text,out byte devid) || devid < 0 || devid > 247){
  97. MessageBox.Show(Application.Current.MainWindow, "请输入正确的设备地址", "提示",
  98. MessageBoxButton.OK, MessageBoxImage.Warning);
  99. return;
  100. }
  101. ConfigManager.Instance.UpdateConfig(ConfigKey.ConfigDevId, devid.ToString());
  102. //开始读取RS485设备的参数
  103. _rwBaseConfig = new RWBasicConfig();
  104. int baudrate = int.Parse(sBaudrate);
  105. //显示等待串口
  106. string titleInfo = "正在读取设备的基本参数";
  107. WaitWindow waitWindow = new WaitWindow(titleInfo)
  108. {
  109. Owner = Application.Current.MainWindow,
  110. WindowStartupLocation = WindowStartupLocation.CenterOwner
  111. };
  112. waitWindow.Show();
  113. InitConfiView();
  114. try
  115. {
  116. _rwBaseConfig = new RWBasicConfig();
  117. _rwBaseConfig.RWLog += _rwBaseConfig_RWLog;
  118. _rwBaseConfig.SerialConnected += _rwBaseConfig_SerialConnected;
  119. _rwBaseConfig.SerialStatusChanged += _rwBaseConfig_SerialStatusChanged;
  120. BasicConfig basicConfig = await Task.Run(() => _rwBaseConfig.ReadBasicConfig(portName, baudrate, devid));
  121. _readConfig = basicConfig; //记录读取的配置
  122. if (basicConfig != null)
  123. {
  124. LoadViewWithBasicConfig(basicConfig);
  125. cmbDevBaudrate.IsEnabled = true;
  126. cmbDevAddress.IsEnabled = true;
  127. txtResult.Text = "已成功读取设备参数";
  128. txtResult.Foreground = Brushes.Green;
  129. AppendLog("已成功读取设备参数");
  130. }
  131. else
  132. {
  133. txtResult.Text = "读取设备参数失败";
  134. txtResult.Foreground = Brushes.Red;
  135. AppendLog("读取设备参数失败");
  136. }
  137. }
  138. catch { }
  139. finally
  140. {
  141. waitWindow.Close();
  142. }
  143. }
  144. //根据配置值加载页面
  145. private void LoadViewWithBasicConfig(BasicConfig config)
  146. {
  147. InitConfiView();
  148. txtDevType.Text = config.DeviceType;
  149. txtDevSn.Text = config.DeviceSn;
  150. txtFireware.Text = config.FireWare;
  151. txtParty.Text = config.ParityName;
  152. txtDataBits.Text = config.DataBitsName;
  153. txtStopBits.Text = config.StopbitsName;
  154. cmbDevBaudrate.SelectedValue = config.BaudRate.ToString();
  155. cmbDevAddress.Text = config.DeviceAddress.ToString();
  156. btnSetConifg.IsEnabled = true;
  157. //cmbDevBaudrate.IsEnabled = true;
  158. //cmbDevAddress.IsEnabled = true;
  159. }
  160. private void InitConfiView()
  161. {
  162. txtDevType.Text = "";
  163. txtDevSn.Text = "";
  164. txtFireware.Text = "";
  165. txtParty.Text = "";
  166. txtDataBits.Text = "";
  167. txtStopBits.Text = "";
  168. cmbDevBaudrate.SelectedItem = null;
  169. cmbDevAddress.Text = "";
  170. cmbDevBaudrate.IsEnabled = false;
  171. cmbDevAddress.IsEnabled = false;
  172. txtResult.Text = "";
  173. btnSetConifg.IsEnabled = false;
  174. }
  175. private void _rwBaseConfig_RWLog(string message)
  176. {
  177. AppendLog(message);
  178. }
  179. private void _rwBaseConfig_SerialConnected(bool obj)
  180. {
  181. //throw new NotImplementedException();
  182. }
  183. private void _rwBaseConfig_SerialStatusChanged(bool obj)
  184. {
  185. //throw new NotImplementedException();
  186. }
  187. private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
  188. {
  189. if (e.Text.All(char.IsDigit))
  190. {
  191. e.Handled = false; // 如果是数字,允许输入
  192. }
  193. else
  194. {
  195. // 如果当前输入的字符不是数字,并且是中文输入法的拼音或候选字,禁止输入
  196. e.Handled = true;
  197. }
  198. }
  199. private async void BtnSetConifg_Click(object sender, RoutedEventArgs e)
  200. {
  201. if (!LicenseMana.mIsLicensed)
  202. {
  203. MessageBox.Show(Application.Current.MainWindow, "软件未注册,不能使用此功能。", "提示",
  204. MessageBoxButton.OK, MessageBoxImage.Information);
  205. return;
  206. }
  207. //bool isRead = _rwBaseConfig?.IsRead ?? false;
  208. //if (!isRead)
  209. if(_readConfig == null)
  210. {
  211. MessageBox.Show(Application.Current.MainWindow, "请先读取参数", "提示",
  212. MessageBoxButton.OK, MessageBoxImage.Warning);
  213. return;
  214. }
  215. if(cmbDevBaudrate.SelectedItem == null)
  216. {
  217. MessageBox.Show(Application.Current.MainWindow, "请选择波特率", "提示",
  218. MessageBoxButton.OK, MessageBoxImage.Warning);
  219. return;
  220. }
  221. var sBaudrate = cmbBaudrate.SelectedValue.ToString();
  222. if (!byte.TryParse(cmbDevAddress.Text, out byte devAddress) || devAddress < 0 || devAddress > 247)
  223. {
  224. MessageBox.Show(Application.Current.MainWindow, "请输入正确的设备地址", "提示",
  225. MessageBoxButton.OK, MessageBoxImage.Warning);
  226. return;
  227. }
  228. string sBaudRate = cmbDevBaudrate.SelectedValue.ToString();
  229. int baudRate = int.Parse(sBaudRate);
  230. BasicConfig writeConfig = new BasicConfig()
  231. {
  232. BaudRate = baudRate,
  233. DeviceAddress = devAddress
  234. };
  235. //判断是否有变化
  236. if(_readConfig.BaudRate == writeConfig.BaudRate &&
  237. _readConfig.DeviceAddress == writeConfig.DeviceAddress)
  238. {
  239. MessageBox.Show(Application.Current.MainWindow, "设置值与读取值无变化,设置无效", "提示",
  240. MessageBoxButton.OK, MessageBoxImage.Warning);
  241. return;
  242. }
  243. //显示等待串口
  244. string titleInfo = "正在设置设备的基本参数";
  245. WaitWindow waitWindow = new WaitWindow(titleInfo)
  246. {
  247. Owner = Application.Current.MainWindow,
  248. WindowStartupLocation = WindowStartupLocation.CenterOwner
  249. };
  250. waitWindow.Show();
  251. //InitConfiView();
  252. //btnSetConifg.IsEnabled = false;
  253. try
  254. {
  255. bool blSuccess= await Task.Run(() => _rwBaseConfig.WriteBasicConfig(_readConfig,writeConfig));
  256. //bool blSuccess = await _rwBaseConfig.WriteBasicConfig(_readConfig, writeConfig);
  257. if (blSuccess)
  258. {
  259. cmbDevBaudrate.IsEnabled = true;
  260. cmbDevAddress.IsEnabled = true;
  261. txtResult.Text = "已成功设置设备参数";
  262. txtResult.Foreground = Brushes.Green;
  263. AppendLog("已成功设置设备参数");
  264. //自动回填读参数列表
  265. if (chkFillReadParams.IsChecked == true)
  266. {
  267. if(_readConfig.BaudRate != writeConfig.BaudRate)
  268. {
  269. cmbBaudrate.SelectedValue = writeConfig.BaudRate.ToString();
  270. AppendLog($"回填波特率{_readConfig.BaudRate}->{writeConfig.BaudRate}");
  271. }
  272. if(_readConfig.DeviceAddress != writeConfig.DeviceAddress)
  273. {
  274. cmbDevId.Text = writeConfig.DeviceAddress.ToString();
  275. AppendLog($"回填设备地址{_readConfig.DeviceAddress}->{writeConfig.DeviceAddress}");
  276. }
  277. _readConfig.BaudRate = writeConfig.BaudRate;
  278. _readConfig.DeviceAddress = writeConfig.DeviceAddress;
  279. btnSetConifg.IsEnabled = true;
  280. }
  281. else
  282. {
  283. cmbDevBaudrate.IsEnabled = false;
  284. cmbDevAddress.IsEnabled = false;
  285. btnSetConifg.IsEnabled = false;
  286. _readConfig = null;
  287. }
  288. }
  289. else
  290. {
  291. txtResult.Text = "设置设备参数失败";
  292. txtResult.Foreground = Brushes.Red;
  293. AppendLog("设置设备参数失败");
  294. btnSetConifg.IsEnabled = true;
  295. }
  296. }
  297. catch { }
  298. finally
  299. {
  300. waitWindow.Close();
  301. }
  302. }
  303. private void btnClearLog_Click(object sender, RoutedEventArgs e)
  304. {
  305. _logEntries.Clear();
  306. lvLogs.ItemsSource = null;
  307. File.WriteAllText(LogFilePath, "");
  308. AppendLog("日志已清空");
  309. }
  310. private void AppendLog(string message)
  311. {
  312. Dispatcher.Invoke(() =>
  313. {
  314. var logEntry = new LogEntry { Time = DateTime.Now.ToString("HH:mm:ss.fff"), Message = message };
  315. _logEntries.Add(logEntry);
  316. lvLogs.ItemsSource = null;
  317. lvLogs.ItemsSource = _logEntries;
  318. lvLogs.ScrollIntoView(logEntry);
  319. // 确保 Logs 目录存在
  320. Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath));
  321. //File.AppendAllText("config_log.txt", $"{logEntry.Time} - {logEntry.Message}\n");
  322. // 追加日志
  323. File.AppendAllText(LogFilePath, $"{logEntry.Time} - {logEntry.Message}\n");
  324. });
  325. }
  326. //读取并加载日志
  327. private void LoadConfigLog()
  328. {
  329. Dispatcher.BeginInvoke(new Action(() =>
  330. {
  331. LoadLogs();
  332. }));
  333. }
  334. private void LoadLogs()
  335. {
  336. if (!File.Exists(LogFilePath))
  337. return;
  338. _logEntries.Clear(); // 先清空已有的日志记录
  339. //var lines = File.ReadAllLines("config_log.txt");
  340. var lines = File.ReadAllLines(LogFilePath);
  341. foreach (var line in lines)
  342. {
  343. var parts = line.Split(new[] { " - " }, 2, StringSplitOptions.None);
  344. if (parts.Length == 2)
  345. {
  346. _logEntries.Add(new LogEntry { Time = parts[0], Message = parts[1] });
  347. }
  348. }
  349. // 更新 ListView
  350. lvLogs.ItemsSource = null;
  351. lvLogs.ItemsSource = _logEntries;
  352. // 滚动到最后一条
  353. if (_logEntries.Count > 0)
  354. {
  355. lvLogs.ScrollIntoView(_logEntries[_logEntries.Count - 1]);
  356. }
  357. }
  358. private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
  359. {
  360. double totalWidth = lvLogs.ActualWidth;
  361. double timeColumnWidth = 120; // 时间列固定宽度
  362. double minMessageWidth = 200; // 消息列的最小宽度
  363. double newMessageWidth = Math.Max(minMessageWidth, totalWidth - timeColumnWidth - 40); // 计算新宽度
  364. ((GridView)lvLogs.View).Columns[1].Width = newMessageWidth;
  365. }
  366. private void MenuItem_CopyMessage_Click(object sender, RoutedEventArgs e)
  367. {
  368. if (lvLogs.SelectedItem is LogEntry logEntry)
  369. {
  370. if (!LicenseMana.mIsLicensed)
  371. {
  372. MessageBox.Show(Application.Current.MainWindow, "软件未注册,不能使用此功能。", "提示",
  373. MessageBoxButton.OK, MessageBoxImage.Information);
  374. return;
  375. }
  376. Clipboard.SetText(logEntry.Message);
  377. }
  378. }
  379. //-----------------------------------------------------------------------------
  380. }
  381. }