MainWindow.xaml.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. using Panuon.WPF.UI;
  2. using SWRIS.Core;
  3. using SWRIS.Dtos;
  4. using SWRIS.Enums;
  5. using SWRIS.Events;
  6. using SWRIS.Extensions;
  7. using SWRIS.Models;
  8. using SWRIS.Models.ViewModel;
  9. using SWRIS.Pages;
  10. using SWRIS.Repository;
  11. using System;
  12. using System.ComponentModel;
  13. using System.IO;
  14. using System.Linq;
  15. using System.Reflection;
  16. using System.Speech.Synthesis;
  17. using System.Threading;
  18. using System.Threading.Tasks;
  19. using System.Windows;
  20. using System.Windows.Controls;
  21. using System.Windows.Markup;
  22. using Tools = SWRIS.Extensions.Tools;
  23. namespace SWRIS
  24. {
  25. /// <summary>
  26. /// MainWindow.xaml 的交互逻辑
  27. /// </summary>
  28. public partial class MainWindow : WindowX, IComponentConnector
  29. {
  30. // 屏幕比例阈值
  31. private const double ASPECT_RATIO_THRESHOLD = 1.5; // 大于此值视为宽屏(16:9),小于此值视为方屏(4:3)
  32. private readonly SpeechSynthesizer speech;
  33. public MainViewModel MainView { get; set; }
  34. private readonly IRecordRepository _recordRepository;
  35. private readonly IAlarmRepository _alarmRepository;
  36. public MainWindow()
  37. {
  38. InitializeComponent();
  39. _recordRepository = new RecordRepository();
  40. _alarmRepository = new AlarmRepository();
  41. speech = new SpeechSynthesizer()
  42. {
  43. Rate = 1,
  44. Volume = 100
  45. };
  46. MainView = new MainViewModel();
  47. Application.Current.MainWindow = this;
  48. App.TcpServer.ClientConnected += TcpServer_ClientConnected;
  49. App.TcpServer.ClientDisconnected += TcpServer_ClientDisconnected;
  50. App.TcpServer.LiveStreamReceived += TcpServer_LiveStreamReceived;
  51. App.TcpServer.AlarmDataReceived += TcpServer_AlarmDataReceived;
  52. App.TcpServer.DetectionDataReceived += TcpServer_DetectionDataReceived;
  53. App.TcpServer.RealTimeDataReceived += TcpServer_RealTimeDataReceived;
  54. App.TcpServer.FaultDataReceived += TcpServer_FaultDataReceived;
  55. App.TcpServer.DetectionRawDataReceived += TcpServer_DetectionRawDataReceived;
  56. App.TcpServer.DetectionRawDataResultReceived += TcpServer_DetectionRawDataResultReceived;
  57. App.TcpServer.DetectionStatusResultReceived += TcpServer_DetectionStatusResultReceived;
  58. App.TcpServer.DebugMessageReceived += TcpServer_DebugMessageReceived;
  59. App.TcpServer.HeartbeatReceived += TcpServer_HeartbeatReceived;
  60. App.TcpServer.UpgradedRequestResultReceived += TcpServer_UpgradedRequestResultReceived;
  61. App.Calibration.ConnectionStateChanged += Calibration_ConnectionStateChanged;
  62. App.Calibration.LimitStateChanged += Calibration_LimitStateChanged;
  63. App.TcpServer.Start();
  64. DataContext = MainView;
  65. }
  66. private async void TcpServer_LiveStreamReceived(object sender, LiveStreamReceivedEventArgs e)
  67. {
  68. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  69. if (equipmentData != null)
  70. {
  71. if (equipmentData.DetectionData?.DetectionNo == equipmentData.DetectionNo)
  72. {
  73. equipmentData.ClearData();
  74. }
  75. await Task.Run(() =>
  76. {
  77. equipmentData.Chart?.AddDataPoints((equipmentData.AbsolutePosition, e.LiveStream), equipmentData.InUseSensor);
  78. equipmentData.AddLiveStream(e.LiveStream);
  79. });
  80. }
  81. }
  82. /// <summary>
  83. /// 接收心跳数据
  84. /// </summary>
  85. private void TcpServer_HeartbeatReceived(object sender, HeartbeatReceviedEventArgs e)
  86. {
  87. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  88. if (equipmentData != null)
  89. {
  90. equipmentData.IsHeartbeatReceived = true;
  91. }
  92. }
  93. /// <summary>
  94. /// 接收调试信息
  95. /// </summary>
  96. private void TcpServer_DebugMessageReceived(object sender, DebugMessageReceivedEventArgs e)
  97. {
  98. if (e.IpAddress.IsNullOrEmpty() && e.SerialNo.IsNullOrEmpty())
  99. {
  100. DebugMessageShow(e.Message);
  101. }
  102. else
  103. {
  104. DebugMessageShow(e.Message, e.IpAddress, e.SerialNo);
  105. }
  106. }
  107. /// <summary>
  108. /// 显示调试信息
  109. /// </summary>
  110. /// <param name="message"> 调试信息 </param>
  111. /// <param name="ipAddress"> IP地址 </param>
  112. /// <param name="serialNo"> 序列号 </param>
  113. public void DebugMessageShow(string message, string ipAddress, string serialNo)
  114. {
  115. if (App.Config.ShowDebugMessage)
  116. {
  117. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => (!serialNo.IsNullOrEmpty() && c.SerialNo == serialNo) || c.IpAddress == ipAddress);
  118. if (equipmentData != null)
  119. {
  120. equipmentData.DebugMessage.DateTime = DateTime.Now;
  121. equipmentData.DebugMessage.Message = message;
  122. }
  123. }
  124. }
  125. /// <summary>
  126. /// 显示调试信息
  127. /// </summary>
  128. /// <param name="message"> 调试信息 </param>
  129. public void DebugMessageShow(string message)
  130. {
  131. if (App.Config.ShowDebugMessage)
  132. {
  133. MainView.DebugMessage.DateTime = DateTime.Now;
  134. MainView.DebugMessage.Message = message;
  135. }
  136. }
  137. /// <summary>
  138. /// 标定限位状态更改
  139. /// </summary>
  140. [Obfuscation(Feature = "virtualization", Exclude = false)]
  141. private void Calibration_LimitStateChanged(object sender, LimitData limitData)
  142. {
  143. foreach (var equipment in App.DataCenter.Equipments)
  144. {
  145. foreach (var limit in equipment.Limits)
  146. {
  147. if (limit.Name == limitData.Name && limit.IsEnable)
  148. {
  149. if (limitData.State == LimitState.AtLimit)
  150. {
  151. limit.State = LimitState.AtLimit;
  152. // 当前运行状态添加预标定状态
  153. equipment.RunningStatus |= RunningStatus.PreCalibration;
  154. if (App.TcpServer.SendRealTimeAbsolutePositionData(limit.SwitchIndex, (float)limitData.Position, equipment.SerialNo, equipment.ClientSocket))
  155. {
  156. DebugMessageShow($"{limitData.Name}标定成功", equipment.IpAddress, equipment.SerialNo);
  157. }
  158. }
  159. else if (limitData.State == LimitState.NotInLimit)
  160. {
  161. limit.State = LimitState.NotInLimit;
  162. }
  163. }
  164. }
  165. }
  166. }
  167. /// <summary>
  168. /// 标定模块连接状态更改
  169. /// </summary>
  170. private void Calibration_ConnectionStateChanged(object sender, bool isConnect)
  171. {
  172. foreach (var equipment in App.DataCenter.Equipments)
  173. {
  174. foreach (var limit in equipment.Limits)
  175. {
  176. if (isConnect)
  177. {
  178. if (limit.State == LimitState.Offline)
  179. {
  180. limit.State = LimitState.NotInLimit;
  181. }
  182. }
  183. else
  184. {
  185. if (limit.State != LimitState.Offline)
  186. {
  187. limit.State = LimitState.Offline;
  188. }
  189. }
  190. }
  191. }
  192. }
  193. /// <summary>
  194. /// 接收检测状态开关结果
  195. /// </summary>
  196. private void TcpServer_DetectionStatusResultReceived(object sender, DetectionStatusResultReceivedEventArgs e)
  197. {
  198. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  199. if (equipmentData != null)
  200. {
  201. if (equipmentData.RunningStatus.HasFlag(RunningStatus.PreStop))
  202. {
  203. equipmentData.RunningStatus = RunningStatus.Stopped;
  204. Application.Current.Dispatcher.Invoke(() =>
  205. {
  206. NoticeBox.Show("自动检测停止", "通知", MessageBoxIcon.Warning, true, 3000);
  207. });
  208. }
  209. else if (equipmentData.RunningStatus.HasFlag(RunningStatus.PreRunning))
  210. {
  211. equipmentData.RunningStatus = RunningStatus.SpatialNormal;
  212. Application.Current.Dispatcher.Invoke(() =>
  213. {
  214. NoticeBox.Show("自动检测恢复", "通知", MessageBoxIcon.Success, true, 3000);
  215. });
  216. }
  217. else if (equipmentData.RunningStatus.HasFlag(RunningStatus.PreCalibration))
  218. {
  219. equipmentData.RunningStatus = RunningStatus.SpatialNormal;
  220. }
  221. }
  222. }
  223. /// <summary>
  224. /// 接收故障数据
  225. /// </summary>
  226. private void TcpServer_FaultDataReceived(object sender, FaultDataReceivedEventArgs e)
  227. {
  228. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  229. equipmentData?.AddFault(e.FaultData);
  230. }
  231. /// <summary>
  232. /// 接收实时数据
  233. /// </summary>
  234. [Obfuscation(Feature = "virtualization", Exclude = false)]
  235. private void TcpServer_RealTimeDataReceived(object sender, RealTimeDataReceivedEventArgs e)
  236. {
  237. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  238. if (equipmentData != null)
  239. {
  240. equipmentData.Speed = Math.Round(e.RealTimeData.Speed * 60, 2);
  241. equipmentData.Position = e.RealTimeData.Position;
  242. equipmentData.RunningStatus = e.RealTimeData.Status;
  243. equipmentData.AbsolutePosition = e.RealTimeData.AbsolutePosition;
  244. equipmentData.LiftHeight = (equipmentData.RopeLength - equipmentData.AbsolutePosition) / equipmentData.LiftHightRatio;
  245. equipmentData.Direction = equipmentData.Speed > 0 ? DirectionState.Forward :
  246. (equipmentData.Speed == 0f ? DirectionState.Stoped : DirectionState.Reverse);
  247. equipmentData.AddSpeedData(equipmentData.Speed);
  248. }
  249. }
  250. /// <summary>
  251. /// 客户端连接成功
  252. /// </summary>
  253. [Obfuscation(Feature = "virtualization", Exclude = false)]
  254. private void TcpServer_ClientConnected(object sender, ClientConnectedEventArgs e)
  255. {
  256. var equipment = App.Config.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  257. if (equipment == null)
  258. {
  259. LogHelper.Error($"未找到设备,IP地址:{e.IpAddress}");
  260. return;
  261. }
  262. var server = (TcpServerFrame)sender;
  263. server.SendTurnLiveStreamData(true, equipment.SerialNo, e.ClientSocket);
  264. Thread.Sleep(20);
  265. server.SendSetClockData(DateTime.Now.DateTimeToTimestamp(), equipment.SerialNo, e.ClientSocket);
  266. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  267. if (equipmentData != null)
  268. {
  269. equipmentData.IsConnect = true;
  270. equipmentData.ClientSocket = e.ClientSocket;
  271. if (equipmentData.RunningStatus != RunningStatus.SpatialNormal)
  272. {
  273. equipmentData.RunningStatus |= RunningStatus.SpatialNormal;
  274. }
  275. }
  276. }
  277. /// <summary>
  278. /// 客户端连接断开
  279. /// </summary>
  280. private void TcpServer_ClientDisconnected(object sender, ClientDisconnectedEventArgs e)
  281. {
  282. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  283. if (equipmentData != null)
  284. {
  285. equipmentData.IsConnect = false;
  286. equipmentData.ClientSocket = null;
  287. equipmentData.Speed = 0;
  288. equipmentData.AbsolutePosition = 0;
  289. equipmentData.Position = 0;
  290. equipmentData.Direction = DirectionState.Stoped;
  291. }
  292. }
  293. /// <summary>
  294. /// 接收检测结果
  295. /// </summary>
  296. private void TcpServer_DetectionDataReceived(object sender, DetectionDataReceivedEventArgs e)
  297. {
  298. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  299. if (equipmentData != null)
  300. {
  301. e.DetectionData.DetectionNo = equipmentData.DetectionNo;
  302. equipmentData.DetectionData = e.DetectionData;
  303. }
  304. }
  305. /// <summary>
  306. /// 接检测原始数据结果
  307. /// </summary>
  308. private void TcpServer_DetectionRawDataResultReceived(object sender, DetectionRawDataResultReceivedEventArgs e)
  309. {
  310. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  311. if (equipmentData != null)
  312. {
  313. // 处理检测原始结果数据
  314. if (e.DetectionRawResultData.Code == 0)
  315. {
  316. if (equipmentData.DetectionData != null)
  317. {
  318. equipmentData.DetectionData.RawResultData = e.DetectionRawResultData;
  319. }
  320. }
  321. else
  322. {
  323. LogHelper.Error($"获取检测原始数据失败,错误码:{e.DetectionRawResultData.Code}");
  324. }
  325. }
  326. }
  327. /// <summary>
  328. /// 接受检测结果原始数据
  329. /// </summary>
  330. [Obfuscation(Feature = "virtualization", Exclude = false)]
  331. private async void TcpServer_DetectionRawDataReceived(object sender, DetectionRawDataReceivedEventArgs e)
  332. {
  333. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  334. if (equipmentData != null)
  335. {
  336. if (equipmentData.DisableAlarm)
  337. {
  338. DebugMessageShow($"获取检测结果原始数据结束", equipmentData.IpAddress, equipmentData.SerialNo);
  339. return;
  340. }
  341. await Task.Run(() =>
  342. {
  343. if (equipmentData.DetectionData != null && equipmentData.DetectionData.RawResultData != null)
  344. {
  345. DebugMessageShow($"数据接收:{e.DetectionRawData.PacketNumber}/{e.DetectionRawData.TotalPackets}", equipmentData.IpAddress, equipmentData.SerialNo);
  346. if (e.DetectionRawData.PacketNumber == 1)
  347. {
  348. equipmentData.DetectionData.RawDataReceiving = true;
  349. equipmentData.DetectionData.RawData = new MemoryStream();
  350. equipmentData.DetectionData.RawData.Write(e.DetectionRawData.Data, 0, e.DetectionRawData.Data.Length);
  351. }
  352. else if (e.DetectionRawData.PacketNumber <= e.DetectionRawData.TotalPackets)
  353. {
  354. // 添加原始数据到检测数据中
  355. equipmentData.DetectionData.RawData.Write(e.DetectionRawData.Data, 0, e.DetectionRawData.Data.Length);
  356. // 如果是最后一包数据,处理检测数据
  357. if (e.DetectionRawData.PacketNumber == e.DetectionRawData.TotalPackets)
  358. {
  359. // 生成数据文件路径
  360. (string absolutePath, string relativePath) = DatFileHandler.GetDatFilePath(equipmentData.SerialNo);
  361. // 处理检测数据逻辑
  362. var record = new RecordDto
  363. {
  364. RopeName = equipmentData.RopeName,
  365. RopeNumber = equipmentData.RopeNumber,
  366. StartPoint = equipmentData.DetectionData.StartPoint,
  367. EndPoint = equipmentData.DetectionData.EndPoint,
  368. DetectedSpeed = equipmentData.DetectionData.DetectedSpeed,
  369. DetectionLength = equipmentData.DetectionData.DetectionLength,
  370. StartTime = equipmentData.DetectionData.StartTime.TimestampToDateTime(),
  371. EndTime = equipmentData.DetectionData.EndTime.TimestampToDateTime(),
  372. SensorCount = equipmentData.DetectionData.RawResultData.SensorCount,
  373. SamplingStep = equipmentData.DetectionData.RawResultData.SamplingStep,
  374. DataFilePath = relativePath,
  375. InUseSensors = string.Join(",", equipmentData.InUseSensor)
  376. };
  377. foreach (var damage in equipmentData.DetectionData.Damages)
  378. {
  379. var alarmCount = _alarmRepository.AddAlarm(new AlarmDataModel
  380. {
  381. DamageLevel = damage.DamageLevel,
  382. DamagePosition = damage.DamagePoint,
  383. DamageValue = damage.DamageValue,
  384. RopeNumber = equipmentData.RopeNumber
  385. }, AlarmSourceType.Detection, App.Config.DamageExtent);
  386. if (alarmCount >= App.Config.AlarmValidCount)
  387. {
  388. record.Damages.Add(new DamageDto
  389. {
  390. DamageLevel = damage.DamageLevel,
  391. DamagePoint = damage.DamagePoint,
  392. DamageValue = damage.DamageValue,
  393. });
  394. record.DamageCount++;
  395. //纠正健康度 以客户端上传的损伤数据 重新计算
  396. if ((int)record.RiskLevel < (int)damage.DamageLevel)
  397. {
  398. record.RiskLevel = (RiskLevel)damage.DamageLevel;
  399. }
  400. }
  401. }
  402. equipmentData.RiskLevel = record.RiskLevel;
  403. if (record.DamageCount > 0)
  404. {
  405. int? recordId = _recordRepository.CreateRecord(record);
  406. if (recordId.HasValue)
  407. {
  408. record.Id = recordId.Value;
  409. AddRecordToPageRecords(record);
  410. if (!DatFileHandler.CreateDatFile(absolutePath, equipmentData.DetectionData.RawData))
  411. {
  412. LogHelper.Error($"创建检测数据文件失败,路径:{absolutePath}");
  413. }
  414. DebugMessageShow($"检测数据记录成功", equipmentData.IpAddress, equipmentData.SerialNo);
  415. if ((int)record.RiskLevel >= (int)App.Config.SoundRiskLevel)
  416. {
  417. Application.Current.Dispatcher.Invoke(() =>
  418. {
  419. speech.SpeakAsync($"{equipmentData.RopeName},检测到{record.DamageCount}处损伤");
  420. });
  421. }
  422. }
  423. else
  424. {
  425. LogHelper.Error("检测数据记录失败");
  426. }
  427. }
  428. else
  429. {
  430. DebugMessageShow($"检测完成,未发现损伤,本次检测不做记录。", equipmentData.IpAddress, equipmentData.SerialNo);
  431. }
  432. equipmentData.DetectionData.RawDataReceiving = false;
  433. }
  434. }
  435. }
  436. });
  437. }
  438. }
  439. /// <summary>
  440. /// 接收报警数据
  441. /// </summary>
  442. private void TcpServer_AlarmDataReceived(object sender, AlarmDataReceivedEventArgs e)
  443. {
  444. var equipmentData = App.DataCenter.Equipments.FirstOrDefault(c => c.IpAddress == e.IpAddress);
  445. if (equipmentData != null && equipmentData.IsSpeedStable && !equipmentData.DisableAlarm)
  446. {
  447. Dispatcher.InvokeAsync(() =>
  448. {
  449. e.AlarmData.RopeNumber = equipmentData.RopeNumber;
  450. var alarmCount = _alarmRepository.AddAlarm(e.AlarmData, AlarmSourceType.RealTime, App.Config.DamageExtent);
  451. if (alarmCount >= App.Config.AlarmValidCount)
  452. {
  453. equipmentData.AddAlarm(e.AlarmData);
  454. }
  455. });
  456. }
  457. }
  458. private void TcpServer_UpgradedRequestResultReceived(object sender, UpgradedResultReceivedEventArgs e)
  459. {
  460. Dispatcher.InvokeAsync(async () =>
  461. {
  462. if (e.Code == 0)
  463. {
  464. await Task.Delay(2000);
  465. string url = $"http://192.168.1.200"; // 替换为您的网页地址
  466. Tools.OpenUrl(url);
  467. }
  468. });
  469. }
  470. public void AddRecordToPageRecords(RecordDto record)
  471. {
  472. Application.Current.Dispatcher.Invoke(() =>
  473. {
  474. if (Main_Frame.Content is Page currentPage && currentPage != null)
  475. {
  476. var simpleRecord = record.ToSimpleRecordDto();
  477. if (currentPage.Title == "RealTimePage")
  478. {
  479. if (currentPage.DataContext is RealTimeViewModel realTimeView)
  480. {
  481. realTimeView.AddRecord(simpleRecord);
  482. }
  483. }
  484. }
  485. });
  486. }
  487. private void WindowX_Loaded(object sender, RoutedEventArgs e)
  488. {
  489. AdjustViewboxStretch();
  490. NavigateToPage("Home");
  491. // 在程序启动时开启一个后台线程,每隔15秒检测一次
  492. Task.Run(async () =>
  493. {
  494. bool lastIpOk = true;
  495. bool lastPortOk = true;
  496. while (true)
  497. {
  498. bool ipOk = Tools.CheckIpAddressExists(App.Config.IpAddress);
  499. bool portOk = !Tools.CheckPortInUse(App.Config.Port);
  500. // IP异常
  501. if (!ipOk)
  502. {
  503. NoticeBox.Show($"当前在用网卡的IP地址中没有发现[{App.Config.IpAddress}],请检查网络配置。",
  504. "警告", MessageBoxIcon.Warning, true, 5000);
  505. }
  506. // IP从异常恢复正常
  507. else if (!lastIpOk && ipOk)
  508. {
  509. if (!HasConnectedDevice())
  510. {
  511. NoticeBox.Show($"IP地址[{App.Config.IpAddress}]已恢复,5秒后将自动重启程序", "提示", MessageBoxIcon.Info, true, 5000);
  512. if (HasConnectedDevice())
  513. {
  514. NoticeBox.Show($"检测到有设备处于连接状态,已取消自动重启", "提示", MessageBoxIcon.Info, true, 5000);
  515. }
  516. else
  517. {
  518. await RestartApplication();
  519. }
  520. }
  521. }
  522. // 端口异常
  523. if (!portOk)
  524. {
  525. NoticeBox.Show("当前配置的端口已被占用,请更换端口或关闭占用该端口的程序。",
  526. "警告", MessageBoxIcon.Warning, true, 5000);
  527. }
  528. // 端口从异常恢复正常
  529. else if (!lastPortOk && portOk)
  530. {
  531. if (!HasConnectedDevice())
  532. {
  533. NoticeBox.Show($"端口[{App.Config.Port}]已释放,5秒后将自动重启程序", "提示", MessageBoxIcon.Info, true, 5000);
  534. if (HasConnectedDevice())
  535. {
  536. NoticeBox.Show($"检测到有设备处于连接状态,已取消自动重启", "提示", MessageBoxIcon.Info, true, 5000);
  537. }
  538. else
  539. {
  540. await RestartApplication();
  541. }
  542. }
  543. }
  544. lastIpOk = ipOk;
  545. lastPortOk = portOk;
  546. await Task.Delay(15000); // 每15秒检测一次
  547. }
  548. });
  549. }
  550. private async Task RestartApplication(int delay = 5000)
  551. {
  552. await Task.Delay(delay);
  553. Application.Current.Dispatcher.Invoke(() =>
  554. {
  555. App.RestartApplication();
  556. });
  557. }
  558. /// <summary>
  559. /// 检查是否有设备处于连接状态
  560. /// </summary>
  561. private bool HasConnectedDevice()
  562. {
  563. return App.DataCenter.Equipments.Any(e => e.IsConnect);
  564. }
  565. public void NavigatePage(Uri uri)
  566. {
  567. Main_Frame.NavigationService.Navigate(uri);
  568. }
  569. private void NavigateToPage(object pageName)
  570. {
  571. switch (pageName)
  572. {
  573. case "Home":
  574. MainView.CurrentPage = "Home";
  575. Main_Frame.NavigationService.Navigate(new Uri($"Pages/RealTime/RealTimePage.xaml", uriKind: UriKind.Relative));
  576. break;
  577. case "Record":
  578. MainView.CurrentPage = "Record";
  579. Main_Frame.NavigationService.Navigate(new Uri($"Pages/RecordPage.xaml", uriKind: UriKind.Relative));
  580. break;
  581. }
  582. }
  583. private void Menu_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
  584. {
  585. if (sender is TextBlock menuItem)
  586. {
  587. CleanNavigation(Main_Frame);
  588. NavigateToPage(menuItem?.Tag);
  589. }
  590. }
  591. private void CleanNavigation(Frame frame)
  592. {
  593. while (frame.CanGoBack)
  594. frame.RemoveBackEntry();
  595. }
  596. private void StackPanel_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
  597. {
  598. if (e.ClickCount == 2)
  599. {
  600. Left = 0;
  601. Top = 0;
  602. }
  603. }
  604. private void Setting_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
  605. {
  606. SettingDialog settingDialog = new SettingDialog();
  607. if (settingDialog.ShowDialog(true) == true)
  608. {
  609. if (settingDialog.IsAutoStart)
  610. {
  611. App.RestartApplication();
  612. }
  613. }
  614. }
  615. private void Window_Closing(object sender, CancelEventArgs e)
  616. {
  617. App.TcpServer?.Dispose();
  618. speech?.Dispose();
  619. }
  620. private void Minimize_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
  621. {
  622. WindowState = WindowState.Minimized;
  623. }
  624. private void Close_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
  625. {
  626. var result = MessageBoxX.Show(this, "退出后将无法进行实时检测,是否确认退出程序?", "警告",
  627. MessageBoxButton.YesNo,
  628. MessageBoxIcon.Warning, DefaultButton.YesOK);
  629. if (result == MessageBoxResult.Yes)
  630. {
  631. Close();
  632. }
  633. }
  634. private void SwitchToInstance_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
  635. {
  636. if (sender is Border instanceBorder && instanceBorder.Tag != null)
  637. {
  638. App.SwitchToExistingInstance(instanceBorder.Tag.ToString());
  639. }
  640. }
  641. private void AdjustViewboxStretch()
  642. {
  643. var screen = System.Windows.Forms.Screen.FromHandle(
  644. new System.Windows.Interop.WindowInteropHelper(this).Handle);
  645. double aspectRatio = (double)screen.Bounds.Width / screen.Bounds.Height;
  646. RootGrid.Height = aspectRatio <= ASPECT_RATIO_THRESHOLD ? 1440 : 1080;
  647. }
  648. }
  649. }