using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; using StandardScene.Utils; namespace StandardScene.ExtendDevice.Door { public partial class DoorManager : Form { private static DoorManager _instance = null; private static readonly object _lock = new object(); private const string DataFileName = "DoorConfig.json"; private string _dataFilePath; private List _doorControllers = new List(); private DoorControllerModel _currentController = null; private DoorModel _currentDoor = null; private int _controllerHoverIndex = -1; private int _doorHoverIndex = -1; /// /// 获取单例实例 /// public static DoorManager Instance { get { if (_instance == null || _instance.IsDisposed) { lock (_lock) { if (_instance == null || _instance.IsDisposed) { _instance = new DoorManager(); } } } return _instance; } } /// /// 私有构造函数,确保单例模式 /// private DoorManager() { InitializeComponent(); // 设置数据文件路径 _dataFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DataFileName); } private void DoorManager_Load(object sender, EventArgs e) { // 设置ListView的视觉样式 SetupListViewStyles(); // 初始化类型下拉框 InitializeTypeComboBox(); LoadData(); RefreshControllerList(); } /// /// 初始化类型下拉框,显示 DoorTypeAttribute.Name /// private void InitializeTypeComboBox() { comboBoxType.Items.Clear(); try { // 获取当前命名空间下所有继承自BasicDoorController且带有DoorTypeAttribute特性的类 // 在插件/宿主环境下 GetExecutingAssembly 可能不是 StandardScene.dll // 跨程序集发现:门控制器具体类型可能位于卫星插件 dll(StandardScene.Devices.Door)。 var controllerTypes = SimpleLite.Utils.UiTypeDiscovery.AllTypes() .Where(t => t.IsClass && !t.IsAbstract && t.Namespace == typeof(BasicDoorController).Namespace && t.IsSubclassOf(typeof(BasicDoorController)) && t.IsDefined(typeof(DoorTypeAttribute), false)) .ToList(); var typeNames = new List(); foreach (var type in controllerTypes) { var attr = type.GetCustomAttribute(); if (attr != null && !string.IsNullOrWhiteSpace(attr.Name)) { typeNames.Add(attr.Name); } } // 按名称排序 typeNames.Sort(); foreach (var typeName in typeNames) { comboBoxType.Items.Add(typeName); } // 如果没有找到任何类型,添加默认选项 if (comboBoxType.Items.Count == 0) { comboBoxType.Items.Add("ModbusDoorController"); } } catch (Exception ex) { MessageBox.Show($"初始化类型下拉框失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); comboBoxType.Items.Add("ModbusDoorController"); } } /// /// 设置ListView的视觉样式 /// private void SetupListViewStyles() { SetupListView(doorControllerListView, ControllerListView_DrawItem, ControllerListView_DrawSubItem, ControllerListView_DrawColumnHeader, ControllerListView_MouseMove, ControllerListView_MouseLeave); SetupListView(doorListView, DoorListView_DrawItem, DoorListView_DrawSubItem, DoorListView_DrawColumnHeader, DoorListView_MouseMove, DoorListView_MouseLeave); } private void SetupListView(ListView listView, DrawListViewItemEventHandler itemHandler, DrawListViewSubItemEventHandler subItemHandler, DrawListViewColumnHeaderEventHandler headerHandler, MouseEventHandler mouseMoveHandler, EventHandler mouseLeaveHandler) { listView.OwnerDraw = true; listView.BackColor = Color.White; listView.DrawItem += itemHandler; listView.DrawSubItem += subItemHandler; listView.DrawColumnHeader += headerHandler; listView.MouseMove += mouseMoveHandler; listView.MouseLeave += mouseLeaveHandler; // 启用双缓冲 typeof(Control)?.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic)? .SetValue(listView, true, null); } private static readonly Color RowEvenColor = Color.FromArgb(250, 250, 252); private static readonly Color RowOddColor = Color.White; private static readonly Color RowHighlightColor = Color.FromArgb(230, 240, 255); private static readonly Color TextRegularColor = Color.FromArgb(68, 68, 68); private static readonly Color TextHighlightColor = Color.FromArgb(51, 51, 51); private void ControllerListView_MouseMove(object sender, MouseEventArgs e) { UpdateHoverIndex(doorControllerListView, e, true); } private void ControllerListView_MouseLeave(object sender, EventArgs e) { ResetHoverIndex(doorControllerListView, true); } private void DoorListView_MouseMove(object sender, MouseEventArgs e) { UpdateHoverIndex(doorListView, e, false); } private void DoorListView_MouseLeave(object sender, EventArgs e) { ResetHoverIndex(doorListView, false); } private void UpdateHoverIndex(ListView listView, MouseEventArgs e, bool isControllerList) { var hoveredItem = listView.GetItemAt(e.X, e.Y); int newIndex = hoveredItem?.Index ?? -1; if (isControllerList) { if (_controllerHoverIndex != newIndex) { _controllerHoverIndex = newIndex; listView.Invalidate(); } } else { if (_doorHoverIndex != newIndex) { _doorHoverIndex = newIndex; listView.Invalidate(); } } } private void ResetHoverIndex(ListView listView, bool isControllerList) { if (isControllerList) { if (_controllerHoverIndex != -1) { _controllerHoverIndex = -1; listView.Invalidate(); } } else { if (_doorHoverIndex != -1) { _doorHoverIndex = -1; listView.Invalidate(); } } } private void ControllerListView_DrawItem(object sender, DrawListViewItemEventArgs e) { var isHighlighted = e.Item.Selected || e.ItemIndex == _controllerHoverIndex || (e.State & ListViewItemStates.Focused) != 0; var backColor = isHighlighted ? RowHighlightColor : (e.ItemIndex % 2 == 0 ? RowEvenColor : RowOddColor); using (var brush = new SolidBrush(backColor)) { e.Graphics.FillRectangle(brush, e.Bounds); } var textColor = isHighlighted ? TextHighlightColor : TextRegularColor; TextRenderer.DrawText(e.Graphics, e.Item.Text, e.Item.Font, e.Bounds, textColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis); e.DrawFocusRectangle(); } private void ControllerListView_DrawSubItem(object sender, DrawListViewSubItemEventArgs e) { var isHighlighted = e.Item.Selected || e.ItemIndex == _controllerHoverIndex || (e.ItemState & ListViewItemStates.Focused) != 0; var backColor = isHighlighted ? RowHighlightColor : (e.ItemIndex % 2 == 0 ? RowEvenColor : RowOddColor); using (var brush = new SolidBrush(backColor)) { e.Graphics.FillRectangle(brush, e.Bounds); } var textColor = isHighlighted ? TextHighlightColor : TextRegularColor; TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.SubItem.Font, e.Bounds, textColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis); } private void ControllerListView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) { e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(245, 247, 250)), e.Bounds); e.Graphics.DrawLine(new Pen(Color.FromArgb(220, 220, 220)), e.Bounds.Left, e.Bounds.Bottom - 1, e.Bounds.Right, e.Bounds.Bottom - 1); TextRenderer.DrawText(e.Graphics, e.Header.Text, new Font("微软雅黑", 10.5F, FontStyle.Bold), e.Bounds, Color.FromArgb(68, 68, 68), TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.HorizontalCenter); } private void DoorListView_DrawItem(object sender, DrawListViewItemEventArgs e) { var isHighlighted = e.Item.Selected || e.ItemIndex == _doorHoverIndex || (e.State & ListViewItemStates.Focused) != 0; var backColor = isHighlighted ? RowHighlightColor : (e.ItemIndex % 2 == 0 ? RowEvenColor : RowOddColor); using (var brush = new SolidBrush(backColor)) { e.Graphics.FillRectangle(brush, e.Bounds); } var textColor = isHighlighted ? TextHighlightColor : TextRegularColor; TextRenderer.DrawText(e.Graphics, e.Item.Text, e.Item.Font, e.Bounds, textColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis); e.DrawFocusRectangle(); } private void DoorListView_DrawSubItem(object sender, DrawListViewSubItemEventArgs e) { var isHighlighted = e.Item.Selected || e.ItemIndex == _doorHoverIndex || (e.ItemState & ListViewItemStates.Focused) != 0; var backColor = isHighlighted ? RowHighlightColor : (e.ItemIndex % 2 == 0 ? RowEvenColor : RowOddColor); using (var brush = new SolidBrush(backColor)) { e.Graphics.FillRectangle(brush, e.Bounds); } var textColor = isHighlighted ? TextHighlightColor : TextRegularColor; TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.SubItem.Font, e.Bounds, textColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis); } private void DoorListView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) { e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(245, 247, 250)), e.Bounds); e.Graphics.DrawLine(new Pen(Color.FromArgb(220, 220, 220)), e.Bounds.Left, e.Bounds.Bottom - 1, e.Bounds.Right, e.Bounds.Bottom - 1); TextRenderer.DrawText(e.Graphics, e.Header.Text, new Font("微软雅黑", 10.5F, FontStyle.Bold), e.Bounds, Color.FromArgb(68, 68, 68), TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.HorizontalCenter); } /// /// 刷新门控制器列表 /// private void RefreshControllerList() { doorControllerListView.Items.Clear(); foreach (var controller in _doorControllers) { var item = new ListViewItem(controller.Index.ToString()); item.SubItems.Add(controller.Ip); item.SubItems.Add(controller.Port.ToString()); item.SubItems.Add(controller.Type); item.Tag = controller; item.UseItemStyleForSubItems = false; doorControllerListView.Items.Add(item); } } /// /// 刷新门列表 /// private void RefreshDoorList() { doorListView.Items.Clear(); if (_currentController != null) { foreach (var door in _currentController.Doors) { var item = new ListViewItem(door.Index.ToString()); item.SubItems.Add(door.ControlAddress.ToString()); item.SubItems.Add(door.OpenStatusAddress.ToString()); item.Tag = door; item.UseItemStyleForSubItems = false; doorListView.Items.Add(item); } } } /// /// 门控制器列表选择改变 /// private void doorControllerListView_SelectedIndexChanged(object sender, EventArgs e) { if (doorControllerListView.SelectedItems.Count > 0) { _currentController = doorControllerListView.SelectedItems[0].Tag as DoorControllerModel; if (_currentController != null) { // 填充门控制器编辑区域 textBoxIp.Text = _currentController.Ip; textBoxPort.Text = _currentController.Port.ToString(); textBoxControllerIndex.Text = _currentController.Index.ToString(); // 设置类型下拉框 if (comboBoxType.Items.Contains(_currentController.Type)) { comboBoxType.SelectedItem = _currentController.Type; } else { comboBoxType.SelectedIndex = comboBoxType.Items.Count > 0 ? 0 : -1; } // 刷新门列表 RefreshDoorList(); } } else { _currentController = null; ClearControllerFields(); doorListView.Items.Clear(); } } /// /// 门列表选择改变 /// private void doorListView_SelectedIndexChanged(object sender, EventArgs e) { if (doorListView.SelectedItems.Count > 0) { _currentDoor = doorListView.SelectedItems[0].Tag as DoorModel; if (_currentDoor != null) { // 填充门编辑区域 textBoxDoorIndex.Text = _currentDoor.Index.ToString(); textBoxControlAddress.Text = _currentDoor.ControlAddress.ToString(); textBoxOpenStatusAddress.Text = _currentDoor.OpenStatusAddress.ToString(); checkBoxNoControl.Checked = _currentDoor.NoControl; } } else { _currentDoor = null; ClearDoorFields(); } } /// /// 添加门控制器 /// private void btnAddController_Click(object sender, EventArgs e) { try { string ip = textBoxIp.Text.Trim(); string portText = textBoxPort.Text.Trim(); string indexText = textBoxControllerIndex.Text.Trim(); string type = comboBoxType.SelectedItem?.ToString() ?? string.Empty; int newIndex; if (!string.IsNullOrWhiteSpace(indexText)) { if (!int.TryParse(indexText, out newIndex)) { MessageBox.Show("编码必须是数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } else { newIndex = _doorControllers.Count > 0 ? _doorControllers.Max(c => c.Index) + 1 : 1; } string newIp; if (!string.IsNullOrWhiteSpace(ip)) { if (!IsValidIpAddress(ip)) { MessageBox.Show("无效的IP地址,例如:192.168.1.100", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } newIp = ip; } else { newIp = "192.168.1.100"; } int newPort; if (!string.IsNullOrWhiteSpace(portText)) { if (!int.TryParse(portText, out newPort)) { MessageBox.Show("端口必须是数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } else { newPort = 502; } string newType; if (!string.IsNullOrWhiteSpace(type)) { newType = type; } else { newType = comboBoxType.Items.Count > 0 ? comboBoxType.Items[0].ToString() : "ModbusDoorController"; } // 检查编码是否重复 if (_doorControllers.Any(c => c.Index == newIndex)) { MessageBox.Show($"编码 {newIndex} 已存在,请使用其他编码", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // 检查IP地址是否重复 if (_doorControllers.Any(c => c.Ip == newIp)) { MessageBox.Show($"IP地址 {newIp} 已存在,请使用其他IP地址", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } var newController = new DoorControllerModel { Index = newIndex, Ip = newIp, Port = newPort, Type = newType }; _doorControllers.Add(newController); RefreshControllerList(); SaveData(); // 选中新添加的门控制器 foreach (ListViewItem item in doorControllerListView.Items) { if (item.Tag == newController) { item.Selected = true; item.EnsureVisible(); break; } } } catch (Exception ex) { MessageBox.Show($"添加门控制器失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// 删除门控制器 /// private void btnDeleteController_Click(object sender, EventArgs e) { if (_currentController == null) { MessageBox.Show("请选择要删除的门控制器", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } var result = MessageBox.Show($"删除编码为 {_currentController.Index} 的门控制器?", "确认删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { _doorControllers.Remove(_currentController); _currentController = null; ClearControllerFields(); RefreshControllerList(); doorListView.Items.Clear(); SaveData(); } } /// /// 保存门控制器 /// private void btnSaveController_Click(object sender, EventArgs e) { if (_currentController == null) { MessageBox.Show("请选择要保存的门控制器", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } try { string newIp = textBoxIp.Text.Trim(); if (!IsValidIpAddress(newIp)) { MessageBox.Show("无效的IP地址,例如:192.168.1.100", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (!int.TryParse(textBoxPort.Text, out int port)) { MessageBox.Show("端口必须是数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } _currentController.Port = port; if (!int.TryParse(textBoxControllerIndex.Text, out int index)) { MessageBox.Show("编码必须是数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // 检查编码是否重复(排除当前项) if (_doorControllers.Any(c => c.Index == index && c != _currentController)) { MessageBox.Show($"编码 {index} 已存在,请使用其他编码", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // 检查IP地址是否重复(排除当前项) if (_doorControllers.Any(c => c.Ip == newIp && c != _currentController)) { MessageBox.Show($"IP地址 {newIp} 已存在,请使用其他IP地址", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } _currentController.Index = index; _currentController.Type = comboBoxType.SelectedItem?.ToString() ?? string.Empty; _currentController.Ip = newIp; RefreshControllerList(); SaveData(); MessageBox.Show("保存成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) { MessageBox.Show($"保存失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// 添加门 /// private void btnAddDoor_Click(object sender, EventArgs e) { if (_currentController == null) { MessageBox.Show("请先选择门控制器", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } try { string indexText = textBoxDoorIndex.Text.Trim(); string controlAddressText = textBoxControlAddress.Text.Trim(); string openStatusAddressText = textBoxOpenStatusAddress.Text.Trim(); int newIndex; if (!string.IsNullOrWhiteSpace(indexText)) { if (!int.TryParse(indexText, out newIndex)) { MessageBox.Show("门编码必须是数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } else { newIndex = _currentController.Doors.Count > 0 ? _currentController.Doors.Max(d => d.Index) + 1 : 1; } // 检查门编码是否重复 if (_currentController.Doors.Any(d => d.Index == newIndex)) { MessageBox.Show($"门编码 {newIndex} 已存在,请使用其他编码", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } ushort controlAddress = 0; if (!string.IsNullOrWhiteSpace(controlAddressText)) { if (!ushort.TryParse(controlAddressText, out controlAddress)) { MessageBox.Show("控制地址必须是0-65535之间的数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } ushort openStatusAddress = 0; if (!string.IsNullOrWhiteSpace(openStatusAddressText)) { if (!ushort.TryParse(openStatusAddressText, out openStatusAddress)) { MessageBox.Show("开到位地址必须是0-65535之间的数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } var newDoor = new DoorModel { Index = newIndex, ControlAddress = controlAddress, OpenStatusAddress = openStatusAddress, NoControl = checkBoxNoControl.Checked }; _currentController.Doors.Add(newDoor); RefreshDoorList(); SaveData(); // 选中新添加的门 foreach (ListViewItem item in doorListView.Items) { if (item.Tag == newDoor) { item.Selected = true; item.EnsureVisible(); break; } } } catch (Exception ex) { MessageBox.Show($"添加门失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// 删除门 /// private void btnDeleteDoor_Click(object sender, EventArgs e) { if (_currentController == null) { MessageBox.Show("请先选择门控制器", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } if (_currentDoor == null) { MessageBox.Show("请选择要删除的门", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } var result = MessageBox.Show($"删除编码为 {_currentDoor.Index} 的门?", "确认删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { _currentController.Doors.Remove(_currentDoor); _currentDoor = null; ClearDoorFields(); RefreshDoorList(); SaveData(); } } /// /// 保存门 /// private void btnSaveDoor_Click(object sender, EventArgs e) { if (_currentController == null) { MessageBox.Show("请先选择门控制器", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } if (_currentDoor == null) { MessageBox.Show("请选择要保存的门", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } try { if (!int.TryParse(textBoxDoorIndex.Text, out int index)) { MessageBox.Show("门编码必须是数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // 检查门编码是否重复(排除当前门) if (_currentController.Doors.Any(d => d.Index == index && d != _currentDoor)) { MessageBox.Show($"门编码 {index} 已存在,请使用其他编码", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (!ushort.TryParse(textBoxControlAddress.Text, out ushort controlAddress)) { MessageBox.Show("控制地址必须是0-65535之间的数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (!ushort.TryParse(textBoxOpenStatusAddress.Text, out ushort openStatusAddress)) { MessageBox.Show("开到位地址必须是0-65535之间的数字", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } _currentDoor.Index = index; _currentDoor.ControlAddress = controlAddress; _currentDoor.OpenStatusAddress = openStatusAddress; _currentDoor.NoControl = checkBoxNoControl.Checked; RefreshDoorList(); SaveData(); MessageBox.Show("保存成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) { MessageBox.Show($"保存失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// 清空门控制器字段 /// private void ClearControllerFields() { textBoxIp.Text = string.Empty; textBoxPort.Text = string.Empty; textBoxControllerIndex.Text = string.Empty; comboBoxType.SelectedIndex = -1; } /// /// 清空门字段 /// private void ClearDoorFields() { textBoxDoorIndex.Text = string.Empty; textBoxControlAddress.Text = string.Empty; textBoxOpenStatusAddress.Text = string.Empty; checkBoxNoControl.Checked = false; } /// /// 加载数据 /// private void LoadData() { try { if (File.Exists(_dataFilePath)) { var jsonContent = File.ReadAllText(_dataFilePath, Encoding.UTF8); if (!string.IsNullOrWhiteSpace(jsonContent)) { _doorControllers = jsonContent.JsonTo>(); if (_doorControllers == null) { _doorControllers = new List(); } } else { _doorControllers = new List(); } } else { _doorControllers = new List(); } } catch (Exception ex) { MessageBox.Show($"加载数据失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); _doorControllers = new List(); } } /// /// 保存数据 /// private void SaveData() { try { var jsonContent = _doorControllers.ToJson(); File.WriteAllText(_dataFilePath, jsonContent, Encoding.UTF8); } catch (Exception ex) { MessageBox.Show($"保存数据失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// 验证IP地址格式 /// private bool IsValidIpAddress(string ipAddress) { if (string.IsNullOrWhiteSpace(ipAddress)) { return false; } string 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]?)$"; if (Regex.IsMatch(ipAddress, pattern)) { IPAddress address; return IPAddress.TryParse(ipAddress, out address) && address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork; } return false; } /// /// 窗体关闭事件 /// private void DoorManager_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) { // 关闭前保存数据 SaveData(); e.Cancel = true; this.Visible = false; } } /// /// 打开管理界面(静态方法) /// public static void OpenViewer() { try { var manager = Instance; if (manager.Visible) { if (manager.WindowState == FormWindowState.Minimized) { manager.WindowState = FormWindowState.Normal; } manager.Activate(); manager.BringToFront(); } else { manager.Show(); manager.Activate(); } } catch (Exception ex) { MessageBox.Show($"打开门控制器管理界面失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } }