using Newtonsoft.Json; using StandardScene.InterLock; // 数据类型采用 TrafficInterlockMission 中的 TrafficArea using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Linq; using System.Windows.Forms; namespace LoopViewerApp { public partial class TrafficInterlockViewer : Form { /// -1 表示新增模式;>=0 表示正在编辑对应索引 private int _editingIndex = -1; /// 选中行变化时是否允许加载到编辑区(避免在保存/取消时重复刷新) private bool _allowLoadFromSelection = true; public TrafficInterlockViewer() { InitializeComponent(); if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) return; try { RenderListView(); ClearPanelInputs(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"TrafficInterlockViewer init error: {ex}"); } } #region 表格绘制(只读展示) private void lstTasks_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) { try { // 与 LoopViewer 一致:深蓝表头 + 白色加粗字体 using (var backBrush = new SolidBrush(Color.FromArgb(63, 81, 181))) using (var textBrush = new SolidBrush(Color.White)) using (var font = new Font("微软雅黑", 9, FontStyle.Bold)) { e.Graphics.FillRectangle(backBrush, e.Bounds); var sf = new StringFormat { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Near }; var rect = e.Bounds; rect.Inflate(-8, 0); e.Graphics.DrawString(e.Header.Text, font, textBrush, rect, sf); using (var pen = new Pen(Color.FromArgb(200, 200, 200))) e.Graphics.DrawLine(pen, e.Bounds.Left, e.Bounds.Bottom - 1, e.Bounds.Right, e.Bounds.Bottom - 1); } } catch { e.DrawBackground(); e.DrawText(); } } private void lstTasks_DrawItem(object sender, DrawListViewItemEventArgs e) { // 由 DrawSubItem 统一绘制 } private void lstTasks_DrawSubItem(object sender, DrawListViewSubItemEventArgs e) { try { bool selected = e.Item.Selected; Rectangle bounds = e.Bounds; // 与 LoopViewer 一致:选中行蓝色强调,交替行背景,深灰文字 Color selectedBack = Color.FromArgb(0, 120, 215); Color selectedFore = Color.White; Color evenBack = Color.White; Color oddBack = Color.FromArgb(250, 251, 253); Color normalFore = Color.FromArgb(33, 33, 33); if (selected) { using (var selBrush = new SolidBrush(selectedBack)) e.Graphics.FillRectangle(selBrush, bounds); } else { using (var back = new SolidBrush(e.ItemIndex % 2 == 0 ? evenBack : oddBack)) e.Graphics.FillRectangle(back, bounds); } string text = e.SubItem?.Text ?? string.Empty; Color fore = selected ? selectedFore : normalFore; var textRect = bounds; textRect.Inflate(-6, 0); using (var font = new Font("微软雅黑", 9)) TextRenderer.DrawText(e.Graphics, text, font, textRect, fore, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); } catch { e.DrawBackground(); e.DrawText(); } } #endregion #region 列表渲染与保存 private void RenderListView() { try { if (lstTasks == null) return; _allowLoadFromSelection = false; lstTasks.BeginUpdate(); lstTasks.Items.Clear(); foreach (var a in TrafficInterlockMission.TrafficAreaList) { var stationStr = a.SiteList != null && a.SiteList.Count > 0 ? string.Join(", ", a.SiteList) : ""; var lvi = new ListViewItem(new[] { a.AreaName ?? "", stationStr, a.ControllerName ?? "", a.IsOccupy ? "是" : "否", a.IsEnable ? "是" : "否" }); lstTasks.Items.Add(lvi); } lstTasks.EndUpdate(); _allowLoadFromSelection = true; } catch (Exception ex) { _allowLoadFromSelection = true; System.Diagnostics.Debug.WriteLine($"RenderListView failed: {ex}"); } } private void SaveToConfig() { try { string configPath = Path.Combine(Application.StartupPath, "Config", "traffic.json"); string dir = Path.GetDirectoryName(configPath); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir); File.WriteAllText(configPath, JsonConvert.SerializeObject(TrafficInterlockMission.TrafficAreaList, Formatting.Indented)); } catch (Exception ex) { MessageBox.Show("保存失败:" + ex.Message); } } #endregion #region 点击表格行 → 编辑区展示该行数据 private void lstTasks_SelectedIndexChanged(object sender, EventArgs e) { if (!_allowLoadFromSelection || lstTasks == null || lstTasks.SelectedIndices.Count == 0) return; int idx = lstTasks.SelectedIndices[0]; if (idx < 0 || idx >= TrafficInterlockMission.TrafficAreaList.Count) return; _editingIndex = idx; LoadAreaToPanel(TrafficInterlockMission.TrafficAreaList[idx]); } #endregion #region 编辑区:加载 / 清空 private void LoadAreaToPanel(TrafficArea a) { if (a == null) return; try { if (lblEditingHint != null) lblEditingHint.Text = $"编辑:{a.AreaName}"; if (txtAreaName != null) txtAreaName.Text = a.AreaName ?? ""; if (txtStationIds != null) txtStationIds.Text = a.SiteList != null && a.SiteList.Count > 0 ? string.Join(", ", a.SiteList) : ""; if (txtControlRight != null) txtControlRight.Text = a.ControllerName ?? ""; if (chkIsOccupied != null) chkIsOccupied.Checked = a.IsOccupy; if (chkIsEnabled != null) chkIsEnabled.Checked = a.IsEnable; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"LoadAreaToPanel error: {ex}"); } } private void ClearPanelInputs() { try { _editingIndex = -1; if (lblEditingHint != null) lblEditingHint.Text = "新增区域"; if (txtAreaName != null) txtAreaName.Text = ""; if (txtStationIds != null) txtStationIds.Text = ""; if (txtControlRight != null) txtControlRight.Text = ""; if (chkIsOccupied != null) chkIsOccupied.Checked = false; if (chkIsEnabled != null) chkIsEnabled.Checked = true; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"ClearPanelInputs error: {ex}"); } } #endregion #region 解析站点集合字符串 "1,2,3" -> List private static List ParseStationIds(string text) { var list = new List(); if (string.IsNullOrWhiteSpace(text)) return list; foreach (var part in text.Split(new[] { ',', ';', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries)) { if (int.TryParse(part.Trim(), out int id)) list.Add(id); } return list; } #endregion #region 按钮:保存 / 刷新 / 新增 / 删除 private void btnSave_Click(object sender, EventArgs e) { try { string areaName = txtAreaName?.Text?.Trim() ?? ""; if (string.IsNullOrEmpty(areaName)) { MessageBox.Show("请输入区域名称。"); return; } var stationIds = ParseStationIds(txtStationIds?.Text ?? ""); string controlRight = txtControlRight?.Text?.Trim() ?? ""; bool isOccupied = chkIsOccupied?.Checked ?? false; bool isEnabled = chkIsEnabled?.Checked ?? true; if (_editingIndex >= 0 && _editingIndex < TrafficInterlockMission.TrafficAreaList.Count) { lock (TrafficInterlockMission.TrafficAreaList) { var existing = TrafficInterlockMission.TrafficAreaList[_editingIndex]; existing.AreaName = areaName; existing.SiteList = stationIds; existing.ControllerName = controlRight; existing.IsOccupy = isOccupied; existing.IsEnable = isEnabled; } } else { lock (TrafficInterlockMission.TrafficAreaList) { TrafficInterlockMission.TrafficAreaList.Add(new TrafficArea { AreaName = areaName, SiteList = stationIds, ControllerName = controlRight, IsOccupy = isOccupied, IsEnable = isEnabled }); } } SaveToConfig(); RenderListView(); ClearPanelInputs(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"btnSave_Click error: {ex}"); MessageBox.Show("操作失败:" + ex.Message); } } private void btnRefresh_Click(object sender, EventArgs e) { try { RenderListView(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"btnRefresh_Click error: {ex}"); } } private void btnNew_Click(object sender, EventArgs e) { if (lstTasks != null) lstTasks.SelectedIndices.Clear(); ClearPanelInputs(); // 进入新增模式:填写下方编辑区后点击“保存”即可新增一条数据 } private void btnDelete_Click(object sender, EventArgs e) { try { if (lstTasks == null || lstTasks.SelectedIndices.Count == 0) { MessageBox.Show("请先在上方列表中选择要删除的区域。"); return; } var dialogResult = MessageBox.Show( "确定要删除选中的区域吗?", "确认删除", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (dialogResult != DialogResult.Yes) return; var indices = lstTasks.SelectedIndices.Cast() .OrderByDescending(i => i) .ToList(); lock (TrafficInterlockMission.TrafficAreaList) { foreach (var idx in indices) { if (idx >= 0 && idx < TrafficInterlockMission.TrafficAreaList.Count) { TrafficInterlockMission.TrafficAreaList.RemoveAt(idx); } } } SaveToConfig(); RenderListView(); ClearPanelInputs(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"btnDelete_Click error: {ex}"); MessageBox.Show("删除失败:" + ex.Message); } } #endregion } }