C#开发中ListBox重复显示BLE设备的问题如何修复
问题:BLE设备搜索时ListBox大量显示同名设备
我运行代码点击“搜索”按钮后,程序能检测到附近的BLE设备,但ListBox里总是出现大量同名的设备条目,请问该怎么修复?
相关代码
public Form1() { items = new List<string>(); InitializeComponent(); txtStatus.Text = "Press 'Search' to begin"; var watcher = new BluetoothLEAdvertisementWatcher(); watcher.ScanningMode = BluetoothLEScanningMode.Active; watcher.Received += OnAdvertisementReceived; watcher.Start(); } private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs) { items.Add(eventArgs.Advertisement.LocalName); }
现象说明
ListBox中重复出现多个相同名称的设备条目,同一个物理设备被多次添加到列表中。
解决方案:基于设备唯一标识去重
这问题其实挺常见的——BLE设备会周期性广播广告包,你现在的代码是每次收到广播就往列表里加,自然会出现大量重复。核心解决思路是用每个BLE设备的唯一硬件标识来过滤,而不是只依赖设备名称(毕竟不仅同一设备会多次广播,还可能存在同名的不同设备)。
下面给你两种实用的修复方案:
方案1:用字典存储实现自动去重
每个BLE设备都有独一无二的蓝牙硬件地址(BluetoothAddress),我们可以用Dictionary<ulong, string>来存储,键是蓝牙地址,值是设备名称,字典天然会保证键的唯一性:
// 替换原来的List<string>,用字典存设备地址和对应名称 private Dictionary<ulong, string> deviceDict = new Dictionary<ulong, string>(); public Form1() { InitializeComponent(); txtStatus.Text = "Press 'Search' to begin"; var watcher = new BluetoothLEAdvertisementWatcher(); watcher.ScanningMode = BluetoothLEScanningMode.Active; watcher.Received += OnAdvertisementReceived; watcher.Start(); } private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs) { // 获取设备唯一蓝牙地址 ulong deviceAddress = eventArgs.BluetoothAddress; // 处理设备名称为空的情况,用地址兜底显示 string deviceName = string.IsNullOrEmpty(eventArgs.Advertisement.LocalName) ? $"未命名设备 ({deviceAddress:X})" : eventArgs.Advertisement.LocalName; // 只添加字典中没有的新设备 if (!deviceDict.ContainsKey(deviceAddress)) { deviceDict.Add(deviceAddress, deviceName); // 注意:UI操作必须回到主线程,否则会触发跨线程异常! Invoke((Action)(() => { listBoxDevices.Items.Add(deviceName); })); } }
方案2:用List配合HashSet做去重判断
如果你更习惯用List来存储设备名称,可以额外维护一个HashSet<ulong>来记录已经扫描过的设备地址,避免重复添加:
private List<string> deviceNames = new List<string>(); // 用HashSet存储已扫描的设备地址,判断效率更高 private HashSet<ulong> scannedAddresses = new HashSet<ulong>(); private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs) { ulong deviceAddress = eventArgs.BluetoothAddress; string deviceName = string.IsNullOrEmpty(eventArgs.Advertisement.LocalName) ? $"未命名设备 ({deviceAddress:X})" : eventArgs.Advertisement.LocalName; // 检查地址是否已存在,不存在才添加 if (!scannedAddresses.Contains(deviceAddress)) { scannedAddresses.Add(deviceAddress); deviceNames.Add(deviceName); // 同样要切回主线程更新UI Invoke((Action)(() => { listBoxDevices.Items.Add(deviceName); })); } }
重要提醒
- 跨线程UI操作:
OnAdvertisementReceived事件是在后台线程触发的,直接操作WinForm的控件会抛出异常,所以一定要用Invoke把UI更新逻辑切回主线程。 - 空名称处理:有些BLE设备不会在广播中携带设备名称,所以要做兜底处理,避免列表中出现空条目。
内容的提问来源于stack exchange,提问作者Yann Kang
相关产品推荐
相关产品推荐

