NewLife/XCoder

定时2秒刷新设备清单
JiuHuan authored at 2026-10-08 09:49:45
dfc6bae
Tree
1 Parent(s) 0ad0733
Summary: 2 changed files with 56 additions and 6 deletions.
Modified +48 -6
Modified +8 -0
Modified +48 -6
diff --git a/A2Lib/CAN/CanSelect.cs b/A2Lib/CAN/CanSelect.cs
index b063405..576081f 100644
--- a/A2Lib/CAN/CanSelect.cs
+++ b/A2Lib/CAN/CanSelect.cs
@@ -1,4 +1,4 @@
-using ALib.WinForm;
+using ALib.WinForm;
 using NewLife.Log;
 using System;
 using System.Collections.Generic;
@@ -20,6 +20,7 @@ namespace ALib.CAN
         #region 属性
 
         private ICanPort _Port = null;
+        private System.Windows.Forms.Timer _timer = null;
 
         /// <summary>当前打开或外部注入的 CAN 口,未打开时为 null</summary>
         [Browsable(false)]
@@ -52,6 +53,9 @@ namespace ALib.CAN
                 _needClose = false;
                 _opened = true;
 
+                // 已注入端口,停止定时枚举,避免干扰正在运行的接收线程
+                _timer?.Stop();
+
                 if (cbCan != null) cbCan.Text = value.Name;
                 if (cbBaudrate != null) cbBaudrate.Text = value.Baudrate.ToString();
 
@@ -148,7 +152,7 @@ namespace ALib.CAN
             if (_Port == null)
             {
                 InitBaudrate();
-                InitCanPort();
+                AutoRefreshDevices();
             }
             else
             {
@@ -167,20 +171,52 @@ namespace ALib.CAN
             if (FindForm() is Form frm) frm.FormClosed += Form_FormClosed;
         }
 
+        /// <summary>
+        /// 定时枚举 CAN 设备。已打开端口或外部注入端口时不枚举,
+        /// 避免驱动在设备已打开的情况下再次枚举而干扰正在运行的接收线程。
+        /// </summary>
+        private void AutoRefreshDevices()
+        {
+            _timer = new System.Windows.Forms.Timer { Interval = 2000 };
+            _timer.Tick += (s, e) =>
+            {
+                // 已打开或已注入端口,无需再枚举
+                if (_opened || _Port != null) return;
+                if (!AllowSelect) return;
+                // 用户正在展开下拉框时不要刷新,避免打断选择
+                if (cbCan.DroppedDown) return;
+
+                InitCanPort();
+            };
+            _timer.Start();
+        }
+
         private void Form_FormClosed(object sender, FormClosedEventArgs e) => ClosePort();
 
-        /// <summary>枚举 CAN 设备,填充设备下拉框</summary>
+        /// <summary>枚举 CAN 设备,填充设备下拉框。设备拔掉后同步移除列表项</summary>
         private void InitCanPort()
         {
             var devices = ICanPort.EnumDevices();
-            if (devices.Count == 0)
+
+            var keys = devices.Keys.ToList();
+            var last = cbCan.Text;
+
+            // 每次重新绑定前先断开,避免 DataSource 复用旧集合导致条目残留
+            cbCan.DataSource = null;
+            cbCan.Items.Clear();
+
+            cbCan.Tag = devices;
+            cbCan.DataSource = keys;
+
+            if (keys.Count == 0)
             {
                 WriteLog("未发现 CAN 设备");
                 return;
             }
 
-            cbCan.DataSource = devices.Keys.ToList();
-            cbCan.Tag = devices;
+            // 保持用户原先选中的设备;已拔掉则回退到首项
+            var idx = keys.IndexOf(last);
+            cbCan.SelectedIndex = idx >= 0 ? idx : 0;
         }
 
         /// <summary>初始化波特率下拉框,默认 250K</summary>
@@ -262,6 +298,9 @@ namespace ALib.CAN
                 _opened = true;
             }
 
+            // 已打开,停止定时枚举
+            _timer?.Stop();
+
             if (btCanOpen != null) btCanOpen.Text = "关闭";
             if (LockOnOpen)
             {
@@ -297,6 +336,9 @@ namespace ALib.CAN
             if (cbBaudrate != null) cbBaudrate.Enabled = AllowSelect;
             if (cbCan != null) cbCan.Enabled = AllowSelect;
 
+            // 关闭后恢复定时枚举
+            if (_Port == null && AllowSelect) _timer?.Start();
+
             PortClosed?.Invoke(this, EventArgs.Empty);
         }
 
Modified +8 -0
diff --git a/A2Lib/CAN/CanSelect.Designer.cs b/A2Lib/CAN/CanSelect.Designer.cs
index 344a51e..7e88515 100644
--- a/A2Lib/CAN/CanSelect.Designer.cs
+++ b/A2Lib/CAN/CanSelect.Designer.cs
@@ -18,6 +18,14 @@ namespace ALib.CAN
                 // 先关硬件再走基类(UserControl 销毁不一定触发 FormClosed)
                 ClosePort();
 
+                // 停止并释放定时枚举
+                if (_timer != null)
+                {
+                    _timer.Stop();
+                    _timer.Dispose();
+                    _timer = null;
+                }
+
                 if (components != null) components.Dispose();
             }
             base.Dispose(disposing);