.NET Maui:从蓝牙事件自动更新Blazor UI,无需手动调用更新方法
解决.NET Maui Blazor蓝牙事件UI自动更新问题
核心原因
Android蓝牙广播接收器的事件在后台线程触发,而Blazor组件的状态变更需要在UI线程执行;同时Blazor的自动状态检测仅在组件生命周期方法或UI事件回调中生效,后台线程的状态变更无法自动触发UI更新。
解决方案
方案1:让蓝牙服务在UI线程触发事件
修改BluetoothService,将事件回调切换到UI线程执行,组件中无需手动调用InvokeAsync和StateHasChanged:
// 修改BluetoothService中的事件处理逻辑 private void BluetoothReceiver_DeviceFound(object? sender, Platforms.Android.CustomCode.EventArgs.DeviceFoundEventArgs e) { if (e.Device?.Name is string name) { // 切换到UI线程执行回调 MainThread.BeginInvokeOnMainThread(async () => { await deviceFound(name); }); } } private void BluetoothReceiver_DiscoveryFinished(object? sender, EventArgs e) { IsDiscovering = false; // 切换到UI线程执行回调 MainThread.BeginInvokeOnMainThread(async () => { await discoveryFinished(); }); }
然后简化Razor页面的回调方法:
private Task OnDeviceDiscovered(string deviceName) { devices.Add(deviceName); return Task.CompletedTask; } private Task OnDiscoveryFinished() { isDiscovering = false; return Task.CompletedTask; }
方案2:封装Blazor组件基类自动处理状态变更
创建一个基类组件,封装状态更新逻辑,让页面继承该基类以减少重复代码:
public class BaseComponent : ComponentBase { protected async Task UpdateState(Action action) { await InvokeAsync(() => { action(); StateHasChanged(); }); } }
Razor页面继承基类并使用封装方法:
@inherits BaseComponent @inject IBluetoothService bluetoothService; <!-- 页面内容保持不变 --> @code { private bool isDiscovering = false; private ObservableCollection<string> devices = new(); private async Task StartDiscovery() { isDiscovering = true; await bluetoothService.StartDiscovery(OnDeviceDiscovered, OnDiscoveryFinished); } private async Task OnDeviceDiscovered(string deviceName) { await UpdateState(() => devices.Add(deviceName)); } private async Task OnDiscoveryFinished() { await UpdateState(() => isDiscovering = false); } private void StopDiscovery() { isDiscovering = false; } }
方案3:使用IComponentContext触发状态变更(.NET 7+)
在组件中注入IComponentContext,利用其自动处理UI线程调度和状态变更:
@inject IBluetoothService bluetoothService; @inject IComponentContext ComponentContext; <!-- 页面内容保持不变 --> @code { private bool isDiscovering = false; private ObservableCollection<string> devices = new(); private async Task StartDiscovery() { isDiscovering = true; await bluetoothService.StartDiscovery(OnDeviceDiscovered, OnDiscoveryFinished); } private async Task OnDeviceDiscovered(string deviceName) { await ComponentContext.InvokeAsync(() => { devices.Add(deviceName); }); } private async Task OnDiscoveryFinished() { await ComponentContext.InvokeAsync(() => { isDiscovering = false; }); } private void StopDiscovery() { isDiscovering = false; } }
额外优化提示
- 当前
BluetoothService仅申请了权限,需补充调用bluetoothAdapter.StartDiscovery()启动扫描 - Blazor对
ObservableCollection的自动更新支持有限,结合UI线程触发变更更可靠
内容的提问来源于stack exchange,提问作者Pieterjan
相关产品推荐
相关产品推荐

