You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 23:33:18