refactor: 插件窗体由 static 单例状态改为实例字段(对齐 TextViewer)

将 10 个 CycleGUI 窗体/管理器从进程级 static 单例状态改为实例字段 + 实例方法,
消除本地端/Web 端共享同一可变状态的隐患(对齐 TextViewer 正例)。

每个类保留一个 private static _instance 单实例持有者;静态入口 Open()/OpenViewer()
与实例 Show() 均转发到该实例,调用方零改动、单实例“置前”行为不变。

涉及:ChargeStationManagementForm、ChargeStrategyConfigForm、CommunicationMonitorForm、
AlarmConfigManagementForm、ButtonBoxManager、DoorManager、DoorMonitor、
LoopViewer、DeliveryViewer、TrafficInterlockViewer。

构建:dotnet build StandardScene.sln --no-incremental → 0 错误,30 警告(与基线一致,无新增)。
This commit is contained in:
zhaowei.huang
2026-06-26 15:31:02 +08:00
parent a0dc1e6cd0
commit 54cda958db
10 changed files with 297 additions and 257 deletions
@@ -17,32 +17,36 @@ namespace StandardScene.ExtendDevice.ButtonBox
public class ButtonBoxManager
{
private const string DataFileName = "ButtonBoxConfig.json";
private static string DataFilePath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DataFileName);
private static readonly object SaveLock = new object();
private string DataFilePath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DataFileName);
private readonly object SaveLock = new object();
private static Panel _panel;
private static List<ButtonBoxModel> _boxes = new List<ButtonBoxModel>();
private static int _selectedBoxIdx = -1;
private static int _selectedBtnIdx = -1;
private static string _status = "";
private Panel _panel;
private List<ButtonBoxModel> _boxes = new List<ButtonBoxModel>();
private int _selectedBoxIdx = -1;
private int _selectedBtnIdx = -1;
private string _status = "";
private static string _boxIp = "";
private static string _boxPort = "502";
private static string _boxIndex = "";
private static int _typeIdx;
private static string[] _typeNames = Array.Empty<string>();
private string _boxIp = "";
private string _boxPort = "502";
private string _boxIndex = "";
private int _typeIdx;
private string[] _typeNames = Array.Empty<string>();
private static string _btnIndex = "";
private static string _triggerMission = "";
private static string _triggerMethod = "";
private static string _triggerParams = "";
private static string _triggerDelay = "0";
private static int _triggerStateIdx;
private static readonly string[] _triggerStateNames = Enum.GetNames(typeof(ButtonState));
private string _btnIndex = "";
private string _triggerMission = "";
private string _triggerMethod = "";
private string _triggerParams = "";
private string _triggerDelay = "0";
private int _triggerStateIdx;
private readonly string[] _triggerStateNames = Enum.GetNames(typeof(ButtonState));
private static ButtonBoxManager _instance;
public static void OpenViewer() => Open();
public static void Open()
public static void Open() => (_instance ??= new ButtonBoxManager()).OpenCore();
private void OpenCore()
{
if (_panel != null)
{
@@ -155,17 +159,17 @@ namespace StandardScene.ExtendDevice.ButtonBox
});
}
private static ButtonBoxModel GetSelectedBox() =>
private ButtonBoxModel GetSelectedBox() =>
_selectedBoxIdx >= 0 && _selectedBoxIdx < _boxes.Count ? _boxes[_selectedBoxIdx] : null;
private static ButtonModel GetSelectedButton()
private ButtonModel GetSelectedButton()
{
var box = GetSelectedBox();
return box != null && _selectedBtnIdx >= 0 && _selectedBtnIdx < box.Buttons.Count
? box.Buttons[_selectedBtnIdx] : null;
}
private static string[] DiscoverTypes()
private string[] DiscoverTypes()
{
try
{
@@ -184,7 +188,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
}
}
private static void LoadData()
private void LoadData()
{
try
{
@@ -201,7 +205,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
}
}
private static void SaveData()
private void SaveData()
{
var json = _boxes.ToJson();
var path = DataFilePath;
@@ -220,7 +224,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
});
}
private static void LoadBoxFields(ButtonBoxModel b)
private void LoadBoxFields(ButtonBoxModel b)
{
_boxIp = b.Ip;
_boxPort = b.Port.ToString();
@@ -229,7 +233,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
if (_typeIdx < 0) _typeIdx = 0;
}
private static void ClearBoxFields()
private void ClearBoxFields()
{
_boxIp = "";
_boxPort = "502";
@@ -237,7 +241,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
_typeIdx = 0;
}
private static void LoadButtonFields(ButtonModel b)
private void LoadButtonFields(ButtonModel b)
{
_btnIndex = b.Index.ToString();
_triggerMission = b.TriggerMission ?? "";
@@ -247,7 +251,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
_triggerStateIdx = Math.Max(0, Array.IndexOf(_triggerStateNames, b.TriggerState));
}
private static void ClearButtonFields()
private void ClearButtonFields()
{
_btnIndex = "";
_triggerMission = "";
@@ -257,7 +261,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
_triggerStateIdx = 0;
}
private static void AddBox()
private void AddBox()
{
if (!TryParseBoxInput(out var index, out var ip, out var port, out var type, false, out var err))
{ CycleUiHelper.Alert("错误", err); return; }
@@ -272,7 +276,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
_panel?.Repaint();
}
private static void SaveBox()
private void SaveBox()
{
var cur = GetSelectedBox();
if (cur == null) { CycleUiHelper.Alert("提示", "请先选择按钮盒"); return; }
@@ -287,7 +291,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
_panel?.Repaint();
}
private static void ConfirmDeleteBox()
private void ConfirmDeleteBox()
{
var cur = GetSelectedBox();
if (cur == null) { CycleUiHelper.Alert("提示", "请选择要删除的按钮盒"); return; }
@@ -304,7 +308,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
});
}
private static void AddButton()
private void AddButton()
{
var box = GetSelectedBox();
if (box == null) { CycleUiHelper.Alert("提示", "请先选择按钮盒"); return; }
@@ -327,7 +331,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
_panel?.Repaint();
}
private static void SaveButton()
private void SaveButton()
{
var box = GetSelectedBox();
var btn = GetSelectedButton();
@@ -347,7 +351,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
_panel?.Repaint();
}
private static void ConfirmDeleteButton()
private void ConfirmDeleteButton()
{
var box = GetSelectedBox();
var btn = GetSelectedButton();
@@ -363,7 +367,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
});
}
private static bool TryParseBoxInput(out int index, out string ip, out int port, out string type, bool requireSelection, out string err)
private bool TryParseBoxInput(out int index, out string ip, out int port, out string type, bool requireSelection, out string err)
{
index = 0; ip = ""; port = 502; type = ""; err = "";
ip = string.IsNullOrWhiteSpace(_boxIp) ? "192.168.1.100" : _boxIp.Trim();
@@ -379,7 +383,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
return true;
}
private static bool TryParseButtonInput(out int index, out ushort delay, out string err)
private bool TryParseButtonInput(out int index, out ushort delay, out string err)
{
index = 0; delay = 0; err = "";
var box = GetSelectedBox();
@@ -393,7 +397,7 @@ namespace StandardScene.ExtendDevice.ButtonBox
return true;
}
private static bool IsValidIp(string ip)
private bool IsValidIp(string ip)
{
if (string.IsNullOrWhiteSpace(ip)) return false;
var pattern = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
@@ -18,29 +18,33 @@ namespace StandardScene.ExtendDevice.Door
public class DoorManager
{
private const string DataFileName = "DoorConfig.json";
private static string DataFilePath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DataFileName);
private static readonly object SaveLock = new object();
private string DataFilePath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DataFileName);
private readonly object SaveLock = new object();
private static Panel _panel;
private static List<DoorControllerModel> _controllers = new List<DoorControllerModel>();
private static int _selectedCtrlIdx = -1;
private static int _selectedDoorIdx = -1;
private static string _status = "";
private Panel _panel;
private List<DoorControllerModel> _controllers = new List<DoorControllerModel>();
private int _selectedCtrlIdx = -1;
private int _selectedDoorIdx = -1;
private string _status = "";
private static string _ctrlIp = "";
private static string _ctrlPort = "502";
private static string _ctrlIndex = "";
private static int _typeIdx;
private static string[] _typeNames = Array.Empty<string>();
private string _ctrlIp = "";
private string _ctrlPort = "502";
private string _ctrlIndex = "";
private int _typeIdx;
private string[] _typeNames = Array.Empty<string>();
private static string _doorIndex = "";
private static string _doorCtrlAddr = "";
private static string _doorOpenAddr = "";
private static bool _doorNoControl;
private string _doorIndex = "";
private string _doorCtrlAddr = "";
private string _doorOpenAddr = "";
private bool _doorNoControl;
public static void OpenViewer() => Open();
public static void Open()
public static void Open() => (_instance ??= new DoorManager()).OpenCore();
private static DoorManager _instance;
private void OpenCore()
{
if (_panel != null)
{
@@ -148,17 +152,17 @@ namespace StandardScene.ExtendDevice.Door
});
}
private static DoorControllerModel GetSelectedController() =>
private DoorControllerModel GetSelectedController() =>
_selectedCtrlIdx >= 0 && _selectedCtrlIdx < _controllers.Count ? _controllers[_selectedCtrlIdx] : null;
private static DoorModel GetSelectedDoor()
private DoorModel GetSelectedDoor()
{
var ctrl = GetSelectedController();
return ctrl != null && _selectedDoorIdx >= 0 && _selectedDoorIdx < ctrl.Doors.Count
? ctrl.Doors[_selectedDoorIdx] : null;
}
private static string[] DiscoverTypes()
private string[] DiscoverTypes()
{
try
{
@@ -179,7 +183,7 @@ namespace StandardScene.ExtendDevice.Door
}
}
private static void LoadData()
private void LoadData()
{
try
{
@@ -196,7 +200,7 @@ namespace StandardScene.ExtendDevice.Door
}
}
private static void SaveData()
private void SaveData()
{
var json = _controllers.ToJson();
var path = DataFilePath;
@@ -215,7 +219,7 @@ namespace StandardScene.ExtendDevice.Door
});
}
private static void LoadControllerFields(DoorControllerModel c)
private void LoadControllerFields(DoorControllerModel c)
{
_ctrlIp = c.Ip;
_ctrlPort = c.Port.ToString();
@@ -224,7 +228,7 @@ namespace StandardScene.ExtendDevice.Door
if (_typeIdx < 0) _typeIdx = 0;
}
private static void ClearControllerFields()
private void ClearControllerFields()
{
_ctrlIp = "";
_ctrlPort = "502";
@@ -232,7 +236,7 @@ namespace StandardScene.ExtendDevice.Door
_typeIdx = 0;
}
private static void LoadDoorFields(DoorModel d)
private void LoadDoorFields(DoorModel d)
{
_doorIndex = d.Index.ToString();
_doorCtrlAddr = d.ControlAddress.ToString();
@@ -240,7 +244,7 @@ namespace StandardScene.ExtendDevice.Door
_doorNoControl = d.NoControl;
}
private static void ClearDoorFields()
private void ClearDoorFields()
{
_doorIndex = "";
_doorCtrlAddr = "";
@@ -248,7 +252,7 @@ namespace StandardScene.ExtendDevice.Door
_doorNoControl = false;
}
private static void AddController()
private void AddController()
{
if (!TryParseControllerInput(out var index, out var ip, out var port, out var type, false, out var err))
{
@@ -266,7 +270,7 @@ namespace StandardScene.ExtendDevice.Door
_panel?.Repaint();
}
private static void SaveController()
private void SaveController()
{
var cur = GetSelectedController();
if (cur == null) { CycleUiHelper.Alert("提示", "请先选择要保存的门控制器"); return; }
@@ -288,7 +292,7 @@ namespace StandardScene.ExtendDevice.Door
_panel?.Repaint();
}
private static void ConfirmDeleteController()
private void ConfirmDeleteController()
{
var cur = GetSelectedController();
if (cur == null) { CycleUiHelper.Alert("提示", "请选择要删除的门控制器"); return; }
@@ -305,7 +309,7 @@ namespace StandardScene.ExtendDevice.Door
});
}
private static void AddDoor()
private void AddDoor()
{
var ctrl = GetSelectedController();
if (ctrl == null) { CycleUiHelper.Alert("提示", "请先选择门控制器"); return; }
@@ -330,7 +334,7 @@ namespace StandardScene.ExtendDevice.Door
_panel?.Repaint();
}
private static void SaveDoor()
private void SaveDoor()
{
var ctrl = GetSelectedController();
var door = GetSelectedDoor();
@@ -352,7 +356,7 @@ namespace StandardScene.ExtendDevice.Door
_panel?.Repaint();
}
private static void ConfirmDeleteDoor()
private void ConfirmDeleteDoor()
{
var ctrl = GetSelectedController();
var door = GetSelectedDoor();
@@ -368,7 +372,7 @@ namespace StandardScene.ExtendDevice.Door
});
}
private static bool TryParseControllerInput(out int index, out string ip, out int port, out string type, bool requireSelection, out string err)
private bool TryParseControllerInput(out int index, out string ip, out int port, out string type, bool requireSelection, out string err)
{
index = 0; ip = ""; port = 502; type = ""; err = "";
ip = string.IsNullOrWhiteSpace(_ctrlIp) ? "192.168.1.100" : _ctrlIp.Trim();
@@ -384,7 +388,7 @@ namespace StandardScene.ExtendDevice.Door
return true;
}
private static bool TryParseDoorInput(out int index, out ushort cAddr, out ushort oAddr, bool requireSelection, out string err)
private bool TryParseDoorInput(out int index, out ushort cAddr, out ushort oAddr, bool requireSelection, out string err)
{
index = 0; cAddr = 0; oAddr = 0; err = "";
var ctrl = GetSelectedController();
@@ -401,7 +405,7 @@ namespace StandardScene.ExtendDevice.Door
return true;
}
private static bool IsValidIp(string ip)
private bool IsValidIp(string ip)
{
if (string.IsNullOrWhiteSpace(ip)) return false;
var pattern = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
@@ -20,13 +20,17 @@ namespace StandardScene.ExtendDevice.Door
{
private const string TableId = "door-monitor-list";
private static readonly Color SelectedRowColor = Color.FromArgb(230, 240, 255);
private readonly Color SelectedRowColor = Color.FromArgb(230, 240, 255);
private static Panel _panel;
private static (int ControllerIndex, int DoorIndex)? _selectedDoor;
private Panel _panel;
private (int ControllerIndex, int DoorIndex)? _selectedDoor;
/// <summary>打开(或置前)门控监控面板。</summary>
public static void Open()
public static void Open() => (_instance ??= new DoorMonitor()).OpenCore();
private static DoorMonitor _instance;
private void OpenCore()
{
if (_panel != null)
{
@@ -105,21 +109,21 @@ namespace StandardScene.ExtendDevice.Door
});
}
private static void LabelCell(PanelBuilder.Row row, DoorMission.DoorMonitorSnapshotItem door, string text)
private void LabelCell(PanelBuilder.Row row, DoorMission.DoorMonitorSnapshotItem door, string text)
{
if (row.Label(text))
_selectedDoor = (door.ControllerIndex, door.DoorIndex);
}
private static DoorMission GetMission() =>
private DoorMission GetMission() =>
SimpleProject.proj?.Missions?.OfType<DoorMission>().FirstOrDefault();
private static bool IsRowSelected(DoorMission.DoorMonitorSnapshotItem door) =>
private bool IsRowSelected(DoorMission.DoorMonitorSnapshotItem door) =>
_selectedDoor.HasValue
&& _selectedDoor.Value.ControllerIndex == door.ControllerIndex
&& _selectedDoor.Value.DoorIndex == door.DoorIndex;
private static string GetDoorInfoText(IReadOnlyList<DoorMission.DoorMonitorSnapshotItem> snapshot)
private string GetDoorInfoText(IReadOnlyList<DoorMission.DoorMonitorSnapshotItem> snapshot)
{
if (!_selectedDoor.HasValue)
return "请选择要控制的门";
@@ -133,7 +137,7 @@ namespace StandardScene.ExtendDevice.Door
return $"控制器编码: {door.ControllerIndex}, 门编码: {door.DoorIndex}";
}
private static bool CanCloseSelected(DoorMission mission)
private bool CanCloseSelected(DoorMission mission)
{
if (!_selectedDoor.HasValue || mission == null)
return true;
@@ -142,18 +146,18 @@ namespace StandardScene.ExtendDevice.Door
return cars.Count == 0;
}
private static string FormatState(DoorState state) =>
private string FormatState(DoorState state) =>
state == DoorState.Open ? "打开" : state == DoorState.Closed ? "关闭" : "未知";
private static string FormatManualRemain(DoorMission.DoorMonitorSnapshotItem door) =>
private string FormatManualRemain(DoorMission.DoorMonitorSnapshotItem door) =>
door.Source == DoorMission.ControlSource.Manual && door.ManualRemainingSeconds.HasValue
? Math.Ceiling(door.ManualRemainingSeconds.Value).ToString()
: "-";
private static string FormatCars(DoorMission.DoorMonitorSnapshotItem door) =>
private string FormatCars(DoorMission.DoorMonitorSnapshotItem door) =>
door.CarsInArea.Count > 0 ? string.Join(", ", door.CarsInArea) : "无";
private static void OpenSelectedDoor()
private void OpenSelectedDoor()
{
if (!_selectedDoor.HasValue)
{
@@ -180,7 +184,7 @@ namespace StandardScene.ExtendDevice.Door
}
}
private static void CloseSelectedDoor()
private void CloseSelectedDoor()
{
if (!_selectedDoor.HasValue)
{
@@ -213,7 +217,7 @@ namespace StandardScene.ExtendDevice.Door
}
}
private static void ClearSelectedCars()
private void ClearSelectedCars()
{
if (!_selectedDoor.HasValue)
{