C#/.NET MAUI中如何将匿名事件处理器重构为可注销委托
.NET MAUI接入Plugin.BLE扫描设备重复条目问题解决方案
你遇到的扫描结果条目随按钮点击次数递增的问题,根因就是每次触发扫描逻辑时,都给全局复用的同一个adapter实例重复绑定了DeviceDiscovered事件处理函数。同一个设备被发现时,所有历史绑定过的处理逻辑会依次执行,自然会出现重复条目,和你测试用的Pixel 5模拟器本身没有直接关系。
具名事件处理函数实现方法
你不需要纠结事件自带的两个参数,这是C#事件的标准签名约定:
- 第一个参数通常命名为
sender,是触发当前事件的源对象实例,这里就是对应的蓝牙适配器,绝大多数场景下用不到,保留参数声明即可 - 第二个参数通常命名为
e,是事件携带的业务参数,这里包含扫描到的蓝牙设备信息,和你之前Lambda表达式里的a用法完全一致
具体实现步骤
- 在你的MVVM ViewModel类中,编写独立的具名事件处理方法,和按钮命令方法放在同级:
// 蓝牙设备发现事件处理函数 private void OnBleDeviceDiscovered(object sender, DeviceEventArgs e) { if (!string.IsNullOrEmpty(e.Device.Name)) { // 这里替换为你原来Lambda内部写的业务逻辑 // 比如将有效设备加入绑定到UI的扫描结果集合,更新UI记得切换到主线程 } }
如果你使用的Plugin.BLE版本编译提示参数类型不匹配,把第二个参数的
DeviceEventArgs替换为DeviceDiscoveredEventArgs即可,内部e.Device的用法完全不变。
- 修改扫描启动逻辑,绑定事件前先做一次兜底注销,避免历史绑定残留:
// 按钮触发扫描时执行的逻辑 // 先兜底注销,就算之前没有绑定过事件,执行这句也不会抛异常 adapter.DeviceDiscovered -= OnBleDeviceDiscovered; // 绑定具名事件处理函数 adapter.DeviceDiscovered += OnBleDeviceDiscovered; // 启动扫描 await adapter.StartScanningForDevicesAsync();
- 在所有扫描终止的分支(定时器超时、用户手动点击停止)的公共停止逻辑中,执行完停止扫描操作后主动注销事件:
// 停止扫描公共逻辑,所有终止扫描的场景都调用这段代码 await adapter.StopScanningForDevicesAsync(); // 注销事件处理函数,避免后续扫描触发重复逻辑 adapter.DeviceDiscovered -= OnBleDeviceDiscovered;
额外优化建议
安卓模拟器的蓝牙栈本身存在模拟缺陷,就算事件没有重复绑定,也可能出现同一个设备多次上报广播的情况,你可以在添加设备到结果集合时,以设备的唯一标识e.Device.Id(即MAC地址)做去重判断,从业务层彻底避免重复条目问题。
内容的提问来源于stack exchange,提问作者gfmoore
相关产品推荐
相关产品推荐

