.NET MAUI MVVM模式下如何跨ContentPage读写全局共享数据对象
最优实现方案:单例共享可观察状态
首先直接排除SQLite/本地存储方案:这类方案只适合持久化需要长期留存的历史数据,高频实时的蓝牙传感器数据走磁盘IO有不必要的性能开销和延迟,完全没必要。
你现在遇到的问题本质是跨ViewModel的状态共享,最简单、性能最好、最符合MVVM规范的实现是用单例注册的内存共享对象,配合正确实现的属性变更通知,不需要额外的消息转发组件。
第一步:修正你的数据模型实现
你当前的BluetoothData类虽然继承了ObservableObject,但所有属性都是普通自动属性,赋值时不会触发PropertyChanged事件,就算对象共享了UI也不会自动更新。如果你用的是CommunityToolkit.Mvvm(MAUI默认推荐的MVVM工具包),直接用源生成器实现属性通知即可:
namespace TSDZ2Monitor.Models; public partial class BluetoothData : ObservableObject { // 心率原始数据 [ObservableProperty] private int _hrm; [ObservableProperty] private double _hrr; // 速度原始数据 [ObservableProperty] private int _spdWheelRevolutions; [ObservableProperty] private double _spdWheelEventTime; // 踏频原始数据 [ObservableProperty] private int _cadCrankRevolutions; [ObservableProperty] private double _cadCrankEventTime; }
第二步:注册共享对象为单例
在MauiProgram.cs的应用构建配置中,把BluetoothData注册为单例,保证整个应用生命周期内所有注入的地方拿到的都是同一个实例:
// 其他服务注册... builder.Services.AddSingleton<BluetoothData>();
第三步:两个ViewModel分别注入共享实例
不管是负责蓝牙采集的BluetoothViewModel,还是负责展示的DisplayViewModel,都通过构造函数注入这个共享实例:
// BluetoothViewModel 中 public partial class BluetoothViewModel : ObservableObject { private readonly BluetoothData _sharedBleData; // DI容器会自动传入全局唯一的BluetoothData实例 public BluetoothViewModel(BluetoothData sharedBleData) { _sharedBleData = sharedBleData; } // 蓝牙模块回调收到新传感器数据时,直接给共享对象的属性赋值 private void OnSensorDataUpdated(int hrmValue, double hrrValue /*其他传感器参数*/) { _sharedBleData.HRM = hrmValue; _sharedBleData.HRR = hrrValue; // 速度、踏频数据按相同方式赋值 } }
// DisplayViewModel 中 public partial class DisplayViewModel : ObservableObject { // 直接暴露共享数据对象给Page做绑定即可 public BluetoothData SharedBleData { get; } public DisplayViewModel(BluetoothData sharedBleData) { SharedBleData = sharedBleData; } }
最后在DisplayPage的XAML里,直接把控件绑定到SharedBleData对应的属性即可,所有属性更新会通过INotifyPropertyChanged接口自动通知UI刷新,全程是内存直接操作,没有额外开销,完全适配蓝牙数据的高频更新场景。
其他备选方案的差异和适用场景
- MessagingCenter/WeakReferenceMessenger:这类消息总线方案和标准.NET事件的核心差异是采用弱引用机制,不需要显式注销事件订阅,不容易引发内存泄漏;而标准.NET事件是强引用,如果订阅者不手动解绑事件,发布者会一直持有订阅者的引用,导致GC无法回收订阅者对象,容易出现内存泄漏。
消息总线适合松耦合的、跨多层级的一次性通知场景,比如蓝牙连接状态变化、全局操作提示这类不需要持续持有状态的逻辑。如果用来做高频传感器数据同步,每次更新都要打包发送消息、接收方再拆包赋值,代码冗余且性能不如直接共享单例状态,不是最优选择。 - 标准.NET事件:如果两个ViewModel层级很近(比如父子VM关系)可以用,但跨页面的场景下事件订阅解绑很容易遗漏,内存泄漏风险高,也不适合你这个跨页面共享状态的场景。
内容的提问来源于stack exchange,提问作者gfmoore
相关产品推荐
相关产品推荐

