跳到主要内容

全栈审计 — GUI 视图层审计报告

  • 范围: Darra_Pnet_GUI/Views/ 六视图 — DeviceView / SlotView / IoView / DiagView / XmlPreviewView / DataTestView (含各自 Designer.cs)
  • 口径: 只读审计, 不修代码; 每项结论 + 证据 (文件:行) + 分级
  • 分级定义: 高 = 用户可见 bug / 布局破坏; 中 = 死代码·口径分裂·维护债; 低 = 注释陈旧·风格不一致·健壮性小坑
  • 审计时间: 2026-08-14

结论速览

级别数量摘要
0六视图无用户可见的功能性 bug
5XmlPreview 重叠单元格 / SlotView 基类不一致 / IoView 整页隐藏残留 / DiagView 空标注死行 / 诊断注入陈旧注释跨文件残留
12陈旧注释 (Far 口径/行数断言)、写死字段、对齐声明不一致、灰字三色、掩码风格分裂等

正向结论 (逐项核对通过的部分见各节末尾 ✓)。


1. 对齐/布局

1.1 页根去边距 — 六页全部统一 ✓

六视图根 TablePanel 全部 Padding(0) + 视图自身 Margin(0) (2026-08-13 去边距裁定), 无一例外:

  • DeviceView: DeviceView.Designer.cs:732,735,757
  • SlotView: SlotView.Designer.cs:328,342
  • IoView: IoView.Designer.cs:335,338,353
  • DiagView: DiagView.Designer.cs:695,698,726
  • XmlPreviewView: XmlPreviewView.Designer.cs:86,89,199
  • DataTestView: DataTestView.Designer.cs:200,203,220

1.2 行高规范基本统一 (工具条 38 / 分区标题 28 / 数据行 32 / 页脚 36)

DiagView 38/28/32... (DiagView.Designer.cs:700-711)、XmlPreviewView 38/28 (XmlPreviewView.Designer.cs:91-93)、IoView 28/页脚 36 (IoView.Designer.cs:340-342)、SlotView 页脚 36 (SlotView.Designer.cs:330-331)、DeviceView 28/32 (DeviceView.Designer.cs:737-747)。

[低-1] DeviceView 末行 26F 空行残留 + 行数注释失实 (DeviceView.Designer.cs:747)

  • 行定义 11 行: 3 标题行 (28) + 7 数据行 (32) + 末行 26F; 全部控件 SetRow 最大 = 9, 第 10 行 (26F) 无任何控件挂载 — 空行残留, 且 26F 不在 28/32 规范内。
  • 文件头注释 (DeviceView.Designer.cs:28) 写 "数据行 8 行 Absolute 32 统一", 实际只有 7 行 32F + 1 行 26F 空行 — 注释与代码对不上。

[低-2] 标签列宽三页三套, 无统一设计令牌

  • DeviceView 88/200/88/200 (DeviceView.Designer.cs:694-698)、DiagView 100/200/100/200 (DiagView.Designer.cs:656-660)、IoView 40/160/52/160 (IoView.Designer.cs:322-326) — 同是"标签|输入|标签|输入"表单, 标签列宽 88 / 100 / 40+52 三种口径, 视觉节奏不完全一致 (可接受, 但无共享常量)。

1.3 HAlignment — 页面内一致, 声明风格不一致

  • DeviceView 全部标签显式 HAlignment=Near (15 处, DeviceView.Designer.cs:166-661) ✓
  • DiagView/IoView/XmlPreviewView 名称标签未显式声明 HAlignment (靠 LabelControl 默认 Near, 视觉同为左贴) — 声明风格不一致 (低, 见 5.1)。
  • DiagView 值标签 HAlignment=Far (DiagView.cs:149) — 数值右对齐是 2026-08-14 西门子式裁定的有意行为, 但只在运行时构造函数设置 (Designer 预览为左对齐), 且只对齐该页; DeviceView 发送周期/缩减比 SpinEdit 与 DataTestView 字节格仍为 Near — 数值对齐口径跨页不一致 [低-3]。
  • 未发现"发送周期右贴类"标签残留 (DeviceView 标签已全部 Near)。

1.4 XmlPreviewView 文件名行重叠单元格 [中-1]

XmlPreviewView.Designer.cs:146-171:

  • _fileNameCaptionLabel SetColumn(0) + SetColumnSpan(4) → 占满 row1 全部 0-3 列 (Size 1481×27, Location 18,54);
  • _fileNameLabel SetColumn(1) 同在 row1 (Size 1094×27, Location 228,54) — 两个控件重叠在同一单元格区域 (列 1), 靠 z 序 (fileNameLabel 后 Add 在上层) 才不遮字。

违反 TablePanel 单元格唯一占用契约 (System TableLayoutPanel 同构布局会抛 ArgumentException; DevExpress TablePanel 较宽松所以能跑)。视觉目前可用 (caption 文本 "文件名" 只占左侧, value 浮在右侧), 但 z 序一翻转/加背景即遮字, 属脆弱布局。正确做法: caption 只占列 0 (取消 Span) 或两 Label 并入一个单元格内 FlowLayoutPanel。


2. 皮肤

2.1 淡绿 (232,245,233) 三处完全一致 ✓

  • SlotView: SlotView.cs:91
  • IoView: IoView.cs:66
  • DataTestView: DataTestView.cs:99 + DataTestView.Designer.cs:157 (_byteEditor 编辑器同色)

注 [低-4]: DeviceView 可编辑 TextEdit/SpinEdit 未标淡绿 (表单输入框自带可编辑外观), 与三处"单元格可编辑淡绿"口径不冲突但未在文档统一说明 — 建议在 DeviceView 头注释补一句"表单输入框不加淡绿"的口径记录。

2.2 深灰 (70,70,70) 黑底残留 = 0 ✓;白字正文 = 0 ✓

  • 全 Views 目录 grep FromArgb(70,...) / Color.White 文本前景色: 0 命中 (唯一命中是 XmlPreviewView.Designer.cs:175 _previewEdit.BackColor = Color.White — 预览区白底, 属正文底非黑底白字)。
  • 只读单元格回退默认外观 (去深灰底) 在 SlotView SlotView.cs:184 / IoView IoView.cs:216 注释与代码一致落实。

2.3 SlotView 基类与其他五页不一致 [中-2]

SlotView.cs:62public partial class SlotView : UserControl (System.Windows.Forms.UserControl); 其余五页均为 DevExpress.XtraEditors.XtraUserControl (DeviceView.cs:64 / IoView.cs:46 / DiagView.cs:78 / XmlPreviewView.cs:38 / DataTestView.cs:87)。

后果: SlotView 自身背景/缩进不吃 WXI 皮肤 (子控件 TreeList/SimpleButton 仍各自带肤), 页底色可能与其他 tab 页不一致; 且 SlotView.cs:90 注释 "WXI 浅色皮肤下与默认白底区隔" 的前提在 UserControl 上不成立。建议改继承 XtraUserControl。

2.4 UseSkinIndents 注释与代码不符 [低-5]

DeviceView/DataTestView/XmlPreviewView/IoView 四处 Designer 头注释均写 "UseSkinIndents=false" (DeviceView.Designer.cs:21 / DataTestView.Designer.cs:15 / XmlPreviewView.Designer.cs:16 / IoView.Designer.cs:11), 但全 Views 无任何代码设置该属性 (全仓仅 MainForm.Designer.cs:642tablePanelMain.UseSkinIndents = true)。XtraUserControl.UseSkinIndents 默认 true — 注释声明的关闭从未执行 (当前靠各处 Padding(0)/Margin(0) 硬抵消, 视觉结果对, 但注释与运行状态不符)。

2.5 灰字三色口径未统一 [低-6]

  • 分区标题 + 快照标注: (96,96,96) — DeviceView.Designer.cs:131,148,524, DiagView.Designer.cs:169,181,199,217
  • 只读派生单元格 (偏移/输入/输出合计) + 占位提示: Color.GraySlotView.cs:191, IoView.cs:207, DataTestView.cs:182
  • 文件名值标签: Color.DimGrayXmlPreviewView.Designer.cs:159

视觉接近但三种灰并存, 无共享常量 (建议统一为单一"次要文字色"令牌, 三处语义其实相同)。

2.6 红色文本 = 0 ✓ (仅一处语法着色待观察)

  • 全 Views 无 Color.Red/正文红字; DiagView 变化高亮用 ForestGreen (DiagView.cs:381) ✓。
  • XmlPreviewView.cs:56 XmlAttributeColor = (0xE0,0x3B,0x3B) 红 — XML 属性名语法着色 (VS XML 编辑器标准配色, 白底), 属语法高亮非正文, 判合规; 但若未来切暗色皮肤需复核对比度 [观察]。

3. 输入格式

3.1 IP 四段掩码三处完全一致 ✓

_ipAddressEdit / _subnetMaskEdit / _gatewayEdit 同款官方 RegEx 掩码 + BeepOnError + UseMaskAsDisplayFormat (DeviceView.Designer.cs:301-304, 363-366, 425-428), 与 f1/r2 编辑口径一致。

3.2 hex 归一 (u1 口径) ✓

  • VendorID/DeviceID: 掩码 (0[xX])?[0-9a-fA-F]{0,4} (DeviceView.Designer.cs:649,682) + 失焦归一 0x 小写前缀+大写+4 位补零 (DeviceView.cs:356-385) + 提交兜底 (DeviceView.cs:228-229) — 与 GSDML 校验口径一致 ✓。
  • 槽位/子模块标识号: 模块 8 位补零 / 子模块 1-8 位不补零, 归一逻辑与 GSDML XSD 一致 (SlotView.cs:1111-1140) ✓。

3.3 [低-7] 同类 hex ID 字段掩码风格分裂 (DeviceView vs ModuleEditDialog)

  • DeviceView: 严格前缀式 (0[xX])?[0-9a-fA-F]{0,4} — 0x 只能在最前;
  • SlotView ModuleEditDialog: 字符类式 [0-9a-fA-FxX]{0,10} (SlotView.cs:950) — x/X 允许出现在任意位置 (如 "12x3" 掩码放行, 失焦才被归一拒绝回滚)。

同为"十六进制 ID 输入", 掩码策略两套; 建议统一为 DeviceView 前缀式。

3.4 SpinEdit 口径一致 ✓

发送周期 1..1000 ms (DeviceView.Designer.cs:502-507)、缩减比 1..512 (DeviceView.Designer.cs:572-577)、条目/子模块长度 1..1440 或 0..1440 (SlotView.cs:939-947,1198-1200, SlotView.Designer.cs:232-241, IoView.Designer.cs:232-241) — 与 ValidationService 契约一致, 各页同口径 ✓。

3.5 [低-8] ParseHex16 / 校验Hex输入 用 Replace("0x") 非前缀判断

DeviceView.cs:452,709text.Replace("0x", "", OrdinalIgnoreCase) 会替换字符串任意位置的 "0x" (理论例 "A0x" → "A" 通过 TryParse); 当前掩码只允许前缀 0x 所以实际打不出, 但程序化赋值 (RefreshView 直接 set Text) 不经过掩码, 建议与 归一HexStartsWith 口径统一。


4. 锁定语义 (运行态只读 + 可查看)

4.1 三配置页均实现 设置配置只读 且 MainForm 遍历调用 ✓

  • MainForm 设置配置锁定_deviceView/_slotView/_ioView.设置配置只读(locked) (MainForm.cs:924-926), 应用配置按钮随锁态禁用 (MainForm.cs:929)。
  • DeviceView 14 控件全禁 (DeviceView.cs:101-117) / SlotView 关单元格编辑+四按钮禁用 (SlotView.cs:102-109) / IoView 关网格编辑+两按钮禁用, 保留槽位/子模块下拉导航 (IoView.cs:116-121)。
  • DataTestView 按 2026-08-13/14 裁定豁免锁定 (运行时测试工具, 输出区运行中可编辑), 改由"服务已启动 + 已保存配置"双条件门控显隐 (DataTestView.cs:242-265), MainForm 经 设置已保存配置 驱动 (MainForm.cs:369,378,2064) — 接线完整无 orphan ✓。
  • DiagView 同豁免 (观测页, DiagView.cs:38-39 注释与实现一致)。

4.2 [低-9] "可查看"粒度三页不一致 (各页有注释但未统一口径)

  • DeviceView: 连网卡下拉 (TreeListLookUpEdit) 一并 Enabled=false — 运行中无法展开下拉查看六列明细;
  • IoView: 下拉保留可用 (仅导航);
  • SlotView: 树完全保留 (展开/滚动/选择)。

"运行中也要能看" (2026-08-13 裁定) 在设备页只落到"值仍可见", 下拉明细看不了 — 与 IO 页/槽位页粒度不同。若裁定"下拉明细也属可看", DeviceView 需改为 Properties.AllowDropDownWhenReadOnly = true + 编辑禁写。


5. 文案 (R78) / 陈旧注释

5.1 R78 教程式废话 0 命中 ✓

全 Views grep 请输入|请单击|请选择|点击此处|欢迎使用|感谢您|操作成功|小贴士|提示: 您 — 仅注释引用 (DeviceView.cs:46, IoView.cs:19), 无 UI 文案命中 ✓。标签名词化、按钮动作动词、错误走 MessageBox 陈述事实 + 格式示例, 符合 R78。

5.2 红色正文 0 ✓ (见 2.6)

5.3 [低-10] DeviceView.Designer 头注释保留已废弃的 Far 右贴口径

DeviceView.Designer.cs:35 — "标签 AutoSizeMode=None + HAlignment=Far 右对齐贴输入 + VAlignment=Center" 与同文件第 22-25 行 (2026-08-14 裁定 Near 左贴) 及全部实际代码 (Near) 自相矛盾 — 旧口径注释残留, 直接误导后续设计器编辑。

5.4 [中-3] 诊断注入"已删除"后跨文件陈旧注释残留

2026-08-13 裁定注入整块删除 (DiagView 已无注入代码, DiagView.cs:31-33 正确注明), 但:

  • MainForm.cs:168 "计数器 + 设备诊断注入, 不依赖工程对象"
  • MainForm.cs:286 "驱动诊断计数器 + 设备诊断注入 (GET /api/diag + POST /api/diag..."
  • MainForm.cs:1064 "驱动诊断计数器 + 设备诊断注入, 常驻挂载"
  • MainForm.Designer.cs:920-921 "DiagView 常驻挂载...POST /api/diag 注入设备自定义诊断"
  • MainForm.Designer.cs:1167 "tabPageDiag; // 诊断: 驱动诊断计数器 + 设备诊断注入 (GET/POST /api/diag)"
  • Localization.cs:125 "设备诊断注入" 字典条目 (死键, 无消费方)

均描述已删除的功能 — 若 POST /api/diag 服务端也随裁定删除, 这些注释会误导后续维护。属 DiagView 视图域的直接跨文件残留 (GUI 全仓 grep, 非 Views 目录内)。

5.5 [中-4] DiagView 快照标注"停止态提示"注释与代码相反

  • DiagView.cs:28-29 "按钮条小标注只说明快照来源 (如 '服务已停止 (显示最后快照)')";
  • DiagView.cs:242 "小标注只说明快照来源";
  • DiagView.Designer.cs:17-18 "_snapshotNote (快照小标注: 服务停止/从站未启动时显示 '服务已停止 (显示最后快照)' 等灰字...)";

但 2026-08-14 裁定"快照来源小标注不要写出来"后, 代码在线/离线两条路径全部 SetSnapshotNote("") (DiagView.cs:258,269) — 标注永远为空。注释描述的停止态提示行为已不存在。


6. 孤儿/死代码

6.1 [中-4 续] DiagView 按钮条整行 + _snapshotNote = 死 UI

DiagView.Designer.cs:700 row0 Absolute 38F_buttonBar 只装一个永远为空的 _snapshotNote (DiagView.cs:303-309 dirty-check 后仍恒 ""); 手动刷新按钮 2026-08-14 已删, 快照文案同轮裁定不显示 → 38px 工具条行现在无任何内容 (纯占版面)。建议: 删 _buttonBar 行 (行高 38→0) 或在该行放真信息 (如刷新频率说明), 并同步删除 SetSnapshotNote 方法与陈旧注释。

6.2 [低-11] DiagView _hasSnapshot 只写不读死字段

DiagView.cs:100 声明 + :363 写 true, 全仓无任何读取 — 注释 "停止态标注 '最后快照/暂无快照' 分界" 的功能随 2026-08-14 简化退场, 字段未删。

6.3 [中-5] IoView 整页作为"隐藏宿主"残留 — 槽位/IO 合一未收尾

SlotView 2026-08-14 已吞并 IO 三层树, 但旧 IoView 全链路仍活着:

  • MainForm.cs:1690 RebuildViews 仍 new IoView(_project);
  • MainForm.cs:1051-1052 MountViewsOnTabs 仍把 IoView 挂到 tabPageIo;
  • MainForm.cs:926 设置配置锁定仍调 _ioView.设置配置只读;
  • MainForm.cs:1697 IoView.内容变更 仍接 SetDirty;
  • MainForm.cs:1708 ApplyViews 仍调 _ioView.Apply();
  • MainForm.Designer.cs:884-889 TabPages.AddRange 已不含 tabPageIo (页头不显示), 注释 (:907-910) 明确"隐藏宿主, 永不选中"。

后果:

  1. IO 编辑模型双轨并存: 可见树 (SlotView) 类型列已隐藏、GSDML 恒 OctetString; 隐藏网格 (IoView) 仍有"类型 (仅标记)"列 + ShowIoItemDialog 带类型下拉 (IoView.cs:377-379) — 与 2026-08-14 删类型裁定背离的死模型;
  2. 每次保存/导出都跑一次隐藏页的 Apply (_project.RecalculateLengths(), 无害但多余);
  3. 语言切换重建、锁态遍历均携带死页。

建议 (待用户裁定): 彻底移除 IoView 两文件 + tabPageIo + MainForm 五处接线, 或把 IoView 文件归档 _trash (参照已归档的 AlarmView Views\_trash_报警页\, MainForm.Designer.cs:916-917 先例)。

6.4 已删除功能的代码孤儿 = 0 ✓

全仓 grep _injectGroup / subInputLengthEditor / subOutputLengthEditor / CustomDrawFooter / layoutControl* / _summaryLabel / _statusLineLabel / _toolbar — 仅剩注释性说明 (SlotView.Designer.cs:39, IoView.Designer.cs:20-32, XmlPreviewView.Designer.cs:12,26 等), 无任何代码引用残留 — 删除干净, 无 _injectGroup 类孤儿。

6.5 [低-12] DataTestView 轮询路径 BeginInvoke 用法与同文件 SafeBeginInvoke 分裂 + 空 catch

DataTestView.cs:367 BeginInvoke(...)catch (Exception) {} (注释"下次轮询自动重试, 无需处理"), 而同文件 IO 拉取/推送路径 (:495,507,1114,1160) 与 DiagView (DiagView.cs:407-422) 均用 SafeBeginInvoke 统一 marshal — 同一竞态防护两种写法并存, 且空 catch 违反"失败路径不空吞"日志口径 (虽是 benign 关窗竞态, 建议换 SafeBeginInvoke 收敛)。另 DataTestView.cs:439 日志.日志输出.警告 命名空间全限定写法与同文件其余 日志输出.警告 不一致 (cosmetic)。


附: 与本次 wave 其他 agent 的交叉面 (仅标注, 不重复审计)

  • DiagView.cs:149 值标签 Far 右对齐 — 若 f1 (sendclock-ip-editor) 涉及数值对齐口径, 需确认 DeviceView SpinEdit 是否要跟进右对齐;
  • DeviceView.Designer.cs:649,682 hex 掩码 — u1 (hex-input-format) 若改掩码策略, 需同步 SlotView.cs:950 字符类掩码 (见 3.3);
  • 锁定粒度 (4.2) — ux1 (running-state-lock) 若统一"运行中可查看"口径, 涉及 DeviceView 网卡下拉 AllowDropDownWhenReadOnly;
  • 淡绿底色三处 (SlotView.cs:91/IoView.cs:66/DataTestView.cs:99) — r3 (skin-readable-editable-green) 若收敛为共享常量 (如 ThemeColors), 可顺带解决 2.5 灰字三色。

审计方法与守则

  • 全六视图 12 文件逐行 Read + 全仓 grep 交叉验证 (颜色/对齐/掩码/死字段/事件接线);
  • 只读审计: 未 Edit/Write 任何代码文件, 未执行任何 git 操作, 仅新建本报告;
  • MainForm 侧证据 (接线/陈旧注释) 为视图层审计的必要交叉引用, 未审计 MainForm 本体 (归主线程/s 系列 agent)。