Xamarin.Forms MVVM架构下BLE设备状态变更时ListView未同步更新问题
问题根因
- 你创建
NativeDevice实例时仅在扫描阶段赋值了一次初始状态,后续BLE插件的IDevice实例状态发生变更时,没有同步到对应的NativeDevice的States属性,导致UI无法感知到状态变化。 - 未订阅BLE插件
IAdapter提供的设备状态变更事件,无法收到状态更新的回调触发同步逻辑。 - 存在小的代码缺陷:
MainViewModel构造函数重复初始化设备集合、PerformScan方法语法缺失方法括号。
解决方案
1. 扩展NativeDevice类,新增设备唯一标识字段用于匹配对应BLE设备
class NativeDevice : INotifyPropertyChanged { private string deviceNameValue = String.Empty; private DeviceState states; // 新增设备唯一标识,用于匹配BLE插件返回的IDevice public Guid DeviceId { get; } public event PropertyChangedEventHandler PropertyChanged; public NativeDevice(Guid deviceId, string name, DeviceState stated) { DeviceId = deviceId; deviceNameValue = name; states = stated; } public void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public string Name { get => deviceNameValue; set { if (value != deviceNameValue) { deviceNameValue = value; OnPropertyChanged(); } } } public DeviceState States { get => states; set { if (value != states) { states = value; OnPropertyChanged(); } } } }
2. 修改MainViewModel,订阅状态变更事件、修正代码缺陷
class MainViewModel : INotifyPropertyChanged { public ObservableCollection<IDevice> BluetoothDevices { get; set; } private ObservableCollection<NativeDevice> devicesFound; public ObservableCollection<NativeDevice> DevicesFound { get => devicesFound; set { devicesFound = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; private readonly IAdapter _bluetoothAdapter; public AsyncCommand ScanForDevices { get; } public AsyncCommand ConnectToDevices { get; } CancellationTokenSource source = new CancellationTokenSource(); public MainViewModel() { ScanForDevices = new AsyncCommand(PerformScanAsync); BluetoothDevices = new ObservableCollection<IDevice>(); // 移除重复初始化,仅在这里初始化一次 DevicesFound = new ObservableCollection<NativeDevice>(); _bluetoothAdapter = CrossBluetoothLE.Current.Adapter; // 订阅设备发现事件 _bluetoothAdapter.DeviceDiscovered += (s, a) => { BluetoothDevices.Add(a.Device); }; // 新增订阅设备状态变更事件 _bluetoothAdapter.DeviceStateChanged += (s, a) => { // 匹配到对应的NativeDevice,更新状态 var targetDevice = DevicesFound.FirstOrDefault(d => d.DeviceId == a.Device.Id); if (targetDevice != null) { targetDevice.States = a.Device.State; } }; ConnectToDevices = new AsyncCommand(ConnectAsync); } public void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } // 修正方法语法 async Task PerformScanAsync() { // 扫描前清空已有设备,避免重复添加 BluetoothDevices.Clear(); DevicesFound.Clear(); await _bluetoothAdapter.StartScanningForDevicesAsync(); foreach (var item in BluetoothDevices) { if (item.Name == "GP") { // 传入设备ID DevicesFound.Add(new NativeDevice(item.Id, item.Name, item.State)); } } await _bluetoothAdapter.StopScanningForDevicesAsync(); } async Task ConnectAsync() { foreach (var device in BluetoothDevices) { if (device.Name == "GP") { var parameters = new ConnectParameters(forceBleTransport: true); await _bluetoothAdapter.ConnectToDeviceAsync(device, parameters, source.Token); } } } }
3. 优化XAML绑定,状态展示无需双向绑定,改为默认的单向绑定即可
<Label x:DataType="bleappmodelview1:NativeDevice" Text="{Binding Name}"/> <Label x:DataType="bleappmodelview1:NativeDevice" Text="{Binding States}" TextColor="Red"/>
修改完成后,蓝牙设备状态发生任何变更时,插件都会触发DeviceStateChanged事件,回调中会自动同步到对应的NativeDevice实例,触发属性变更通知后UI就会自动更新展示最新状态。
内容的提问来源于stack exchange,提问作者Alexander Petrov
相关产品推荐
相关产品推荐

