using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; namespace StandardScene.Charge { /// /// 通讯监控窗体 /// public partial class CommunicationMonitorForm : Form { private readonly CommunicationMessageService messageService; private bool isFormLoaded = false; private bool isFormMessageStop = false; private const int MaxDisplayRows = 100; private const int UiBatchSize = 20; private const int StatsRefreshMs = 500; private readonly Queue pendingMessages = new Queue(); private readonly object pendingMessagesLock = new object(); private readonly Timer uiFlushTimer; private readonly Timer statsRefreshTimer; private bool pendingStatsRefresh = false; private int lastDisplayCountForStats = 0; public CommunicationMonitorForm() { InitializeComponent(); messageService = CommunicationMessageService.Instance; uiFlushTimer = new Timer { Interval = 500 }; uiFlushTimer.Tick += UiFlushTimer_Tick; statsRefreshTimer = new Timer { Interval = StatsRefreshMs }; statsRefreshTimer.Tick += StatsRefreshTimer_Tick; // 订阅窗体关闭事件 this.FormClosing += CommunicationMonitorForm_FormClosing; } private void CommunicationMonitorForm_Load(object sender, EventArgs e) { try { InitializeForm(); LoadMessages(); // 标记窗体已加载完成 isFormLoaded = true; uiFlushTimer.Start(); statsRefreshTimer.Start(); // 在窗体加载完成后再订阅报文添加事件(避免在初始化期间触发) messageService.MessageAdded += OnMessageAdded; } catch (Exception ex) { MessageBox.Show($"窗体加载失败: {ex.Message}\r\n{ex.StackTrace}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void InitializeForm() { this.Text = "通讯监控"; this.Size = new Size(1400, 800); this.StartPosition = FormStartPosition.CenterScreen; this.MinimumSize = new Size(1200, 600); // 初始化IP筛选下拉框 RefreshIpFilter(); } /// /// 刷新IP筛选下拉框 /// private void RefreshIpFilter() { try { if (cmbIpFilter == null || messageService == null) return; var selectedIp = cmbIpFilter.SelectedItem?.ToString(); cmbIpFilter.Items.Clear(); cmbIpFilter.Items.Add("全部"); var ipAddresses = messageService.GetUniqueIpAddresses(); if (ipAddresses != null) { foreach (var ip in ipAddresses) { if (!string.IsNullOrEmpty(ip)) { cmbIpFilter.Items.Add(ip); } } } // 恢复选中项 if (!string.IsNullOrEmpty(selectedIp) && cmbIpFilter.Items.Contains(selectedIp)) { cmbIpFilter.SelectedItem = selectedIp; } else if (cmbIpFilter.Items.Count > 0) { cmbIpFilter.SelectedIndex = 0; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"刷新IP筛选失败: {ex.Message}"); } } /// /// 加载报文列表 /// private void LoadMessages() { var layoutSuspended = false; try { if (dgvMessages == null|| isFormMessageStop) return; var selectedIp = cmbIpFilter?.SelectedItem?.ToString(); var messages = string.IsNullOrEmpty(selectedIp) || selectedIp == "全部" ? messageService.GetAllMessages() : messageService.GetMessagesByIp(selectedIp); dgvMessages.SuspendLayout(); layoutSuspended = true; dgvMessages.Rows.Clear(); foreach (var msg in messages) { AddMessageRow(msg, false); } UpdateStatistics(messages.Count); pendingStatsRefresh = false; } catch (Exception ex) { MessageBox.Show($"加载报文失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { if (layoutSuspended && dgvMessages != null) { dgvMessages.ResumeLayout(); } } } /// /// 定时批量刷新UI,避免每条报文都抢占UI线程 /// private void UiFlushTimer_Tick(object sender, EventArgs e) { if (!isFormLoaded || isFormMessageStop) return; List batch = null; lock (pendingMessagesLock) { if (pendingMessages.Count == 0) return; int count = Math.Min(UiBatchSize, pendingMessages.Count); batch = new List(count); for (int i = 0; i < count; i++) { batch.Add(pendingMessages.Dequeue()); } } if (batch == null || batch.Count == 0) return; dgvMessages.SuspendLayout(); try { var selectedIp = cmbIpFilter?.SelectedItem?.ToString(); bool displayChanged = false; foreach (var message in batch) { EnsureIpInFilter(message.IpAddress); if (string.IsNullOrEmpty(selectedIp) || selectedIp == "全部" || selectedIp == message.IpAddress) { AddMessageRow(message, true); displayChanged = true; } } if (displayChanged) { RequestStatisticsRefresh(dgvMessages.Rows.Count); } } finally { dgvMessages.ResumeLayout(); } } /// /// 统计信息低频刷新(500ms) /// private void StatsRefreshTimer_Tick(object sender, EventArgs e) { if (!isFormLoaded || isFormMessageStop || !pendingStatsRefresh) return; pendingStatsRefresh = false; UpdateStatistics(lastDisplayCountForStats); } private void RequestStatisticsRefresh(int displayCount) { lastDisplayCountForStats = displayCount; pendingStatsRefresh = true; } private void EnsureIpInFilter(string ipAddress) { if (cmbIpFilter == null || string.IsNullOrWhiteSpace(ipAddress)) return; if (!cmbIpFilter.Items.Contains(ipAddress)) { cmbIpFilter.Items.Add(ipAddress); } } /// /// 向表格新增一条报文行(支持头部插入) /// private void AddMessageRow(CommunicationMessage msg, bool insertAtTop = true) { if (msg == null || dgvMessages == null) return; DataGridViewRow row; if (insertAtTop) { dgvMessages.Rows.Insert(0, msg.Timestamp.ToString("HH:mm:ss.fff"), msg.Direction == MessageDirection.Send ? "发送" : "接收", msg.IpAddress, msg.Port, msg.Length, msg.RawData, msg.StationId ?? "-", msg.Type); row = dgvMessages.Rows[0]; } else { var index = dgvMessages.Rows.Add( msg.Timestamp.ToString("HH:mm:ss.fff"), msg.Direction == MessageDirection.Send ? "发送" : "接收", msg.IpAddress, msg.Port, msg.Length, msg.RawData, msg.StationId ?? "-", msg.Type); row = dgvMessages.Rows[index]; } if (msg.Direction == MessageDirection.Send) { row.DefaultCellStyle.BackColor = Color.FromArgb(232, 245, 233); row.DefaultCellStyle.ForeColor = Color.FromArgb(46, 125, 50); } else { row.DefaultCellStyle.BackColor = Color.FromArgb(227, 242, 253); row.DefaultCellStyle.ForeColor = Color.FromArgb(13, 71, 161); } while (dgvMessages.Rows.Count > MaxDisplayRows) { dgvMessages.Rows.RemoveAt(dgvMessages.Rows.Count - 1); } } /// /// 更新统计信息 /// private void UpdateStatistics(int displayCount) { try { if (lblStatistics == null || messageService == null) return; var allMessages = messageService.GetAllMessages(); if (allMessages == null) return; var sendCount = allMessages.Count(m => m.Direction == MessageDirection.Send); var receiveCount = allMessages.Count(m => m.Direction == MessageDirection.Receive); lblStatistics.Text = $"显示: {displayCount} | 总数: {allMessages.Count} | 发送: {sendCount} | 接收: {receiveCount}"; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"更新统计信息失败: {ex.Message}"); if (lblStatistics != null) { lblStatistics.Text = "统计信息加载失败"; } } } /// /// 新报文添加事件处理(线程安全) /// private void OnMessageAdded(object sender, CommunicationMessage message) { // 如果窗体还未加载完成,忽略此事件 if (!isFormLoaded || isFormMessageStop) return; try { if (message == null) { return; } lock (pendingMessagesLock) { pendingMessages.Enqueue(message); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"处理新报文失败: {ex.Message}"); } } /// /// 解析报文数据 /// private void ParseMessage(CommunicationMessage message) { if (message == null || txtParsedData == null) return; try { var parsed = new System.Text.StringBuilder(); parsed.AppendLine("=== 报文解析 ==="); parsed.AppendLine($"时间: {message.Timestamp:yyyy-MM-dd HH:mm:ss.fff}"); parsed.AppendLine($"方向: {(message.Direction == MessageDirection.Send ? "发送" : "接收")}"); parsed.AppendLine($"地址: {message.IpAddress}:{message.Port}"); parsed.AppendLine($"站点: {message.StationId ?? "未关联"}"); parsed.AppendLine($"长度: {message.Length} 字节"); parsed.AppendLine(); parsed.AppendLine("=== 原始数据 (HEX) ==="); parsed.AppendLine(message.RawData); // parsed.AppendLine(FormatHexString(message.RawData)); parsed.AppendLine(); parsed.AppendLine("=== 数据解析 ==="); // TODO: 根据实际协议进行解析 parsed.AppendLine(); if (message.Direction== MessageDirection.Send) { var sendDate = messageService.ParseSendRawData(message.RawData, message.Type); parsed.AppendLine("示例解析:"); parsed.AppendLine($"充电指令:{sendDate.ChargeCommand}"); parsed.AppendLine($"发送电压:{sendDate.SetVoltage}"); parsed.AppendLine($"发送电流:{sendDate.SetCurrent}"); parsed.AppendLine($"车辆ID:{sendDate.CurrentVehicleId}"); parsed.AppendLine($"车辆电量:{sendDate.BatteryLevel}"); parsed.AppendLine($"车辆电压:{sendDate.CarVoltage}"); parsed.AppendLine($"车辆电流:{sendDate.CarCurrent}"); } else { var recDate = messageService.ParseReceiveRawData(message.RawData, message.Type); string mechanismStatus = (int)recDate.MechanismStatus == 1 ? "伸出" : (int)recDate.MechanismStatus == 2 ? "缩回" : (int)recDate.MechanismStatus == 3 ? "运动中" : recDate.MechanismStatus.ToString(); parsed.AppendLine("示例解析:"); parsed.AppendLine($"机构状态:{mechanismStatus}"); parsed.AppendLine($"实时电压:{recDate.RealTimeVoltage}"); parsed.AppendLine($"实时电流:{recDate.RealTimeCurrent}"); parsed.AppendLine($"充电量: {recDate.BatteryAH}"); parsed.AppendLine($"是否报警:{recDate.HasAlarm}"); parsed.AppendLine($"充电状态:{recDate.Status.ToString()}"); } txtParsedData.Text = parsed.ToString(); } catch (Exception ex) { txtParsedData.Text = $"解析失败: {ex.Message}"; } } /// /// 格式化十六进制字符串 /// private string FormatHexString(string hexData) { if (string.IsNullOrEmpty(hexData)) return string.Empty; var formatted = new System.Text.StringBuilder(); for (int i = 0; i < hexData.Length; i += 2) { if (i > 0 && i % 32 == 0) formatted.AppendLine(); else if (i > 0) formatted.Append(" "); if (i + 1 < hexData.Length) formatted.Append(hexData.Substring(i, 2)); else formatted.Append(hexData[i]); } return formatted.ToString(); } // ==================== 事件处理 ==================== private void cmbIpFilter_SelectedIndexChanged(object sender, EventArgs e) { try { LoadMessages(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"筛选改变失败: {ex.Message}"); } } private void dgvMessages_SelectionChanged(object sender, EventArgs e) { try { if (dgvMessages.SelectedRows.Count > 0) { var row = dgvMessages.SelectedRows[0]; var rawData = row.Cells[5].Value?.ToString(); var ipAddress = row.Cells[2].Value?.ToString(); var port = int.Parse(row.Cells[3].Value?.ToString() ?? "0"); var timeStr = row.Cells[0].Value?.ToString(); var directionStr = row.Cells[1].Value?.ToString(); var stationId = row.Cells[6].Value?.ToString(); var type = row.Cells[7].Value?.ToString(); // 构造消息对象用于解析 var message = new CommunicationMessage { RawData = rawData, IpAddress = ipAddress, Port = port, Direction = directionStr == "发送" ? MessageDirection.Send : MessageDirection.Receive, StationId = stationId == "-" ? null : stationId, Length = rawData.Split(' ')?.Length ?? 0, Type=type, }; if (DateTime.TryParse(timeStr, out DateTime timestamp)) { message.Timestamp = timestamp; } ParseMessage(message); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"选择报文失败: {ex.Message}"); } } private void btnRefresh_Click(object sender, EventArgs e) { try { RefreshIpFilter(); LoadMessages(); RequestStatisticsRefresh(dgvMessages?.Rows.Count ?? 0); } catch (Exception ex) { MessageBox.Show($"刷新失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void btnClear_Click(object sender, EventArgs e) { try { var result = MessageBox.Show( "确定要清空所有报文记录吗?", "确认清空", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { messageService.Clear(); RefreshIpFilter(); LoadMessages(); if (txtParsedData != null) { txtParsedData.Clear(); } dgvMessages.Rows.Clear(); RequestStatisticsRefresh(0); } } catch (Exception ex) { MessageBox.Show($"清空报文失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void btnClose_Click(object sender, EventArgs e) { this.Close(); } private void CommunicationMonitorForm_FormClosing(object sender, FormClosingEventArgs e) { // 取消订阅事件 messageService.MessageAdded -= OnMessageAdded; uiFlushTimer.Stop(); uiFlushTimer.Dispose(); statsRefreshTimer.Stop(); statsRefreshTimer.Dispose(); } private void button1_Click(object sender, EventArgs e) { isFormMessageStop = !isFormMessageStop; if (sender is Button pauseButton) { pauseButton.Text = isFormMessageStop ? "继续" : "暂停"; } } } }