如何在其他ViewModel中访问共享的ObservableCollection?
最佳解决方案
1. 全局单例数据服务(推荐)
创建独立的数据服务类,持有唯一的ObservableCollection<Patient>实例,所有ViewModel通过依赖注入访问同一集合,确保操作的是数据源本身。
步骤1:创建数据服务
public class PatientDataService { public ObservableCollection<Patient> PatientInfo { get; } = new ObservableCollection<Patient>(); // 加载数据的方法 public void PopulatePatientData() { try { string query = "select * from " + App.userDetails.DbTable; SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(query, conn); using (sqlDataAdapter) { System.Data.DataTable dt = new System.Data.DataTable(); sqlDataAdapter.Fill(dt); PatientInfo.Clear(); foreach (System.Data.DataRow row in dt.Rows) PatientInfo.Add(new Patient(Convert.ToInt32(row[0]), row[1].ToString(), row[2].ToString(), row[3].ToString(), row[4].ToString(), row[5].ToString(), row[6].ToString(), row[7].ToString(), row[8].ToString())); } } catch (Exception) { } } }
步骤2:注册服务(在MauiProgram.cs中)
builder.Services.AddSingleton<PatientDataService>();
步骤3:修改ViewModel依赖注入
public partial class BaseViewModel : ObservableObject { protected readonly PatientDataService _dataService; public ObservableCollection<Patient> PatientInfo => _dataService.PatientInfo; public BaseViewModel(PatientDataService dataService) { _dataService = dataService; } } // DashboardViewModel中初始化数据 public partial class DashboardViewModel : BaseViewModel { public DashboardViewModel(PatientDataService dataService) : base(dataService) { _dataService.PopulatePatientData(); } } // EditingViewModel中操作共享集合 [QueryProperty(nameof(Patient), nameof(Patient))] public partial class EditingViewModel : BaseViewModel { [ObservableProperty] private Patient patient; public EditingViewModel(PatientDataService dataService) : base(dataService) { } [RelayCommand] private async Task Delete() { try { // 数据库删除逻辑不变 string query = "DELETE from " + App.userDetails.DbTable + " WHERE id = @patientId"; sqlConnection = new SqlConnection(conn); SqlCommand sqlCommand = new SqlCommand(query, sqlConnection); SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand); using (sqlDataAdapter) { sqlConnection.Open(); sqlCommand.Parameters.AddWithValue("@patientId", Patient.Id); sqlCommand.ExecuteScalar(); } // 操作共享的集合 var targetPatient = PatientInfo.SingleOrDefault(x => x.Id == Patient.Id); if (targetPatient != null) PatientInfo.Remove(targetPatient); } catch (Exception ex) { await Shell.Current.DisplayAlert("Aplicaçao", ex.ToString(), "Sair"); } finally { sqlConnection.Close(); } } }
2. 使用MVVM Toolkit Messenger传递更新通知
通过消息传递解耦ViewModel,EditingViewModel发送删除通知,DashboardViewModel接收并更新自身的集合。
步骤1:定义消息类
public class PatientDeletedMessage { public int PatientId { get; set; } }
步骤2:EditingViewModel发送消息
[RelayCommand] private async Task Delete() { try { // 数据库删除逻辑不变... // 发送删除消息 WeakReferenceMessenger.Default.Send(new PatientDeletedMessage { PatientId = Patient.Id }); } catch (Exception ex) { await Shell.Current.DisplayAlert("Aplicaçao", ex.ToString(), "Sair"); } finally { sqlConnection.Close(); } }
步骤3:DashboardViewModel注册消息处理
public partial class DashboardViewModel : BaseViewModel { public DashboardViewModel(IMessenger messenger) { // 注册消息监听 messenger.Register<PatientDeletedMessage>(this, (recipient, message) => { var patientToRemove = PatientInfo.SingleOrDefault(x => x.Id == message.PatientId); if (patientToRemove != null) PatientInfo.Remove(patientToRemove); }); } }
步骤4:注册Messenger服务(MauiProgram.cs)
builder.Services.AddSingleton<IMessenger>(WeakReferenceMessenger.Default);
3. 直接传递集合引用(简单但耦合度高)
跳转至EditingPage时,将DashboardViewModel的PatientInfo集合作为参数传递,让EditingViewModel直接操作该引用。
步骤1:修改EditingViewModel接收集合
[QueryProperty(nameof(Patient), nameof(Patient))] public partial class EditingViewModel : ObservableObject { private ObservableCollection<Patient> _sharedPatientInfo; [ObservableProperty] private Patient patient; // 通过QueryProperty接收集合 [QueryProperty(nameof(SharedPatientInfo), nameof(SharedPatientInfo))] public ObservableCollection<Patient> SharedPatientInfo { get => _sharedPatientInfo; set => SetProperty(ref _sharedPatientInfo, value); } [RelayCommand] private async Task Delete() { try { // 数据库删除逻辑不变... // 操作传递过来的共享集合 var targetPatient = SharedPatientInfo.SingleOrDefault(x => x.Id == Patient.Id); if (targetPatient != null) SharedPatientInfo.Remove(targetPatient); } catch (Exception ex) { await Shell.Current.DisplayAlert("Aplicaçao", ex.ToString(), "Sair"); } finally { sqlConnection.Close(); } } }
步骤2:跳转时传递集合参数
// DashboardViewModel中的跳转命令 [RelayCommand] private async Task NavigateToEdit() { if (SelectedPatient != null) { await Shell.Current.GoToAsync(nameof(EditingPage), new Dictionary<string, object> { { nameof(Patient), SelectedPatient }, { nameof(EditingViewModel.SharedPatientInfo), PatientInfo } }); } }
方案选型建议
- 全局数据服务:最适合需要多ViewModel共享同一数据源的场景,逻辑清晰,维护成本低,优先推荐。
- Messenger消息传递:解耦性强,适合跨模块、跨ViewModel的通知场景,避免直接依赖。
- 直接传递引用:实现简单,但ViewModel之间耦合度高,适合小型项目或临时需求。
内容的提问来源于stack exchange,提问作者Joao Lima
相关产品推荐
相关产品推荐

