全栈审计 — GUI 视图层审计报告
- 范围:
Darra_Pnet_GUI/Views/六视图 — DeviceView / SlotView / IoView / DiagView / XmlPreviewView / DataTestView (含各自 Designer.cs) - 口径: 只读审计, 不修代码; 每项结论 + 证据 (文件:行) + 分级
- 分级定义: 高 = 用户可见 bug / 布局破坏; 中 = 死代码·口径分裂·维护债; 低 = 注释陈旧·风格不一致·健壮性小坑
- 审计时间: 2026-08-14
结论速览
| 级别 | 数量 | 摘要 |
|---|---|---|
| 高 | 0 | 六视图无用户可见的功能性 bug |
| 中 | 5 | XmlPreview 重叠单元格 / 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:
_fileNameCaptionLabelSetColumn(0)+SetColumnSpan(4)→ 占满 row1 全部 0-3 列 (Size 1481×27, Location 18,54);_fileNameLabelSetColumn(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/ IoViewIoView.cs:216注释与代码一致落实。
2.3 SlotView 基类与其他五页不一致 [中-2]
SlotView.cs:62 — public 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:642 设 tablePanelMain.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.Gray—SlotView.cs:191,IoView.cs:207,DataTestView.cs:182 - 文件名值标签:
Color.DimGray—XmlPreviewView.Designer.cs:159
视觉接近但三种灰并存, 无共享常量 (建议统一为单一"次要文字色"令牌, 三处语义其实相同)。
2.6 红色文本 = 0 ✓ (仅一处语法着色待观察)
- 全 Views 无
Color.Red/正文红字; DiagView 变化高亮用ForestGreen(DiagView.cs:381) ✓。 XmlPreviewView.cs:56XmlAttributeColor = (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,709 — text.Replace("0x", "", OrdinalIgnoreCase) 会替换字符串任意位置的 "0x" (理论例 "A0x" → "A" 通过 TryParse); 当前掩码只允许前缀 0x 所以实际打不出, 但程序化赋值 (RefreshView 直接 set Text) 不经过掩码, 建议与 归一Hex 的 StartsWith 口径统一。
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:1690RebuildViews 仍new IoView(_project);MainForm.cs:1051-1052MountViewsOnTabs 仍把 IoView 挂到tabPageIo;MainForm.cs:926设置配置锁定仍调_ioView.设置配置只读;MainForm.cs:1697IoView.内容变更 仍接 SetDirty;MainForm.cs:1708ApplyViews 仍调_ioView.Apply();MainForm.Designer.cs:884-889TabPages.AddRange 已不含 tabPageIo (页头不显示), 注释 (:907-910) 明确"隐藏宿主, 永不选中"。
后果:
- IO 编辑模型双轨并存: 可见树 (SlotView) 类型列已隐藏、GSDML 恒 OctetString; 隐藏网格 (IoView) 仍有"类型 (仅标记)"列 +
ShowIoItemDialog带类型下拉 (IoView.cs:377-379) — 与 2026-08-14 删类型裁定背离的死模型; - 每次保存/导出都跑一次隐藏页的 Apply (
_project.RecalculateLengths(), 无害但多余); - 语言切换重建、锁态遍历均携带死页。
建议 (待用户裁定): 彻底移除 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,682hex 掩码 — 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)。