Files
zhaowei.huang a0dc1e6cd0 refactor: 插件 UI 从 WinForms 迁移到 CycleGUI,并修复代码质量问题
将 StandardScene 各插件的配置/监控窗体从 WinForms 迁移到 CycleGUI(删除 .Designer.cs/.resx,重写为 PanelBuilder 立即模式 UI,新增 CycleUiHelper 统一对话框)。

同时修复代码审核中的问题:
- 后台文件写入加锁 + try/catch(ButtonBoxManager / DoorManager,对齐 LoopViewer.SaveTasks 模式)
- CoderFieldsMetadata.cs 启用 #nullable enable,消除 CS8632 警告
- DummyCar 移除已废弃的 rightClickAction()/SetPosition()
- CarRemoteHelper.OpenVehicleWebPage 的 Process.Start 加 try/catch
- 重命名名不副实的 Mstsc()(现为打开网页)
- 统一弃元命名为 _
- TrafficInterlockViewer 改用稳定 Id(GUID)做选择/编辑,替代行索引
- csproj 改用 $(CGUILibDir) 解析 CycleGUI,绝对路径收敛到 Directory.Build.props

构建:dotnet build StandardScene.sln → 0 错误,30 警告(均为历史遗留)。
注:static 单例状态重构(审核第 8 项)暂未处理,留待单独任务。
2026-06-26 15:00:53 +08:00

92 lines
3.6 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using CycleGUI;
namespace StandardScene.Utils
{
/// <summary>
/// CycleGUI 通用 UI 小工具:把多个界面都会用到的轻量对话框收敛到一处,避免各处各写一套(不造重复轮子)。
/// <para>注意:同一 <c>Panel.Define</c> 内所有控件的 label 文本必须唯一(含 <c>pb.Table</c> 列头),
/// 否则 ImGui 会抛 <c>Duplicated id</c>。编辑区 label 建议加 ASCII 序号前缀(如 <c>1. IP</c>),
/// 且勿与表格列头同名。</para>
/// </summary>
public static class CycleUiHelper
{
/// <summary>
/// 非阻塞二次确认对话框:用户点「确认」后,在<b>当前(渲染)线程</b>同步执行 <paramref name="onConfirm"/>。
/// 若 <paramref name="onConfirm"/> 含文件 IO / 锁等耗时操作,调用方应自行用 <c>Task.Run</c> 包裹,
/// 避免阻塞渲染线程导致界面卡死。
/// </summary>
public static void ConfirmThen(string message, System.Action onConfirm)
{
// 不用 ModalCycleGUI 原生「模态弹窗 + 标题栏关闭X」存在 BeginPopupModal/EndPopup 配对 bug
//X 关闭时 BeginPopupModal 返回 false 仍调用 EndPopup → ImGui 断言 "Calling End() too many times!" 崩溃)。
// 改为置顶非模态:用 Begin/End 路径,X 关闭干净,效果等同点「取消」。
var dlg = GUI.DeclarePanel()
.ShowTitle("确认")
.TopMost(true)
.InitSize(380, 150)
.InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f);
dlg.Define(pb =>
{
if (pb.Closing())
{
dlg.Exit();
return;
}
pb.Label(message);
pb.Separator();
if (pb.Button("确认", distinct: "cycleui-confirm-ok"))
{
dlg.Exit();
onConfirm();
}
pb.SameLine(8);
if (pb.Button("取消", distinct: "cycleui-confirm-cancel"))
dlg.Exit();
});
}
/// <summary>非阻塞文件选择对话框,替代 WinForms <c>OpenFileDialog</c>。</summary>
public static void PickOpenFile(string label, string filter, System.Action<string> onPicked)
{
var dlg = GUI.DeclarePanel()
.ShowTitle("选择文件")
.TopMost(true)
.InitSize(420, 120)
.InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f);
dlg.Define(pb =>
{
if (pb.Closing()) { dlg.Exit(); return; }
if (pb.OpenFile(label, filter, out var path))
{
dlg.Exit();
onPicked?.Invoke(path);
}
});
}
/// <summary>非阻塞提示对话框。</summary>
public static void Alert(string title, string message)
{
var dlg = GUI.DeclarePanel()
.ShowTitle(title)
.TopMost(true)
.InitSize(380, 150)
.InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f);
dlg.Define(pb =>
{
if (pb.Closing())
{
dlg.Exit();
return;
}
pb.Label(message);
pb.Separator();
if (pb.Button("确定", distinct: "cycleui-alert-ok"))
dlg.Exit();
});
}
}
}