WPF MVVM Caliburn Micro:数据保存后自动刷新DataGrid实现
解决Caliburn.MVVM项目中保存数据后自动刷新DataGrid的问题
嘿,我之前用Caliburn.Micro重构过类似的WinForms转WPF的项目,刚好碰到过这个保存后刷新DataGrid的问题,给你几个实用的解决方案:
1. 用ObservableCollection绑定DataGrid(基础核心)
首先,你的ViewModel里用来绑定DataGrid的集合必须用ObservableCollection
结合Caliburn.Micro的PropertyChangedBase(ViewModel建议继承这个,或者Screen),代码可以这么写:
using Caliburn.Micro; using System.Collections.ObjectModel; public class MainViewModel : PropertyChangedBase { private readonly IGameRepository _gameRepository; // 假设你有数据仓储类 private ObservableCollection<GameModel> _games; public ObservableCollection<GameModel> Games { get => _games; set => Set(ref _games, value); // Caliburn的Set方法自动触发PropertyChanged事件 } public MainViewModel(IGameRepository gameRepository) { _gameRepository = gameRepository; LoadGames(); // 初始化加载数据 } private async void LoadGames() { var games = await _gameRepository.GetAllAsync(); Games = new ObservableCollection<GameModel>(games); } }
2. 保存后直接更新集合(最简单的同步方式)
当你完成数据库保存操作后,只需要重新从数据库拉取最新数据,然后替换掉ViewModel里的Games集合即可——因为我们用了Set方法,它会自动触发UI更新。
示例保存方法:
public async Task SaveGame(GameModel gameToSave) { // 执行数据库保存逻辑 await _gameRepository.SaveOrUpdateAsync(gameToSave); // 重新加载最新数据并更新集合 var latestGames = await _gameRepository.GetAllAsync(); Games = new ObservableCollection<GameModel>(latestGames); }
3. 确保GameModel实现属性变更通知(针对单条数据修改)
如果你的场景是修改DataGrid里的某一行数据(比如直接在DataGrid里编辑GameName),想要实时刷新该行的显示,那你的GameModel也需要实现INotifyPropertyChanged。最方便的是直接继承Caliburn.Micro的PropertyChangedBase:
using Caliburn.Micro; public class GameModel : PropertyChangedBase { private int _gameID; public int GameID { get => _gameID; set => Set(ref _gameID, value); } private string _gameName; public string GameName { get => _gameName; set => Set(ref _gameName, value); } private string _gameCategory; public string GameCategory { get => _gameCategory; set => Set(ref _gameCategory, value); } private string _gameCompany; public string GameCompany { get => _gameCompany; set => Set(ref _gameCompany, value); } private decimal _gamePrice; public decimal GamePrice { get => _gamePrice; set => Set(ref _gamePrice, value); } }
4. 用EventAggregator实现跨ViewModel刷新(解耦场景)
如果你的保存操作是在另一个ViewModel里(比如弹出的编辑窗口),不想直接引用主ViewModel,那可以用Caliburn.Micro自带的EventAggregator来解耦:
第一步:定义事件类
public class GameSavedEvent { // 可以按需添加属性,比如区分是新增还是修改 public bool IsNewGame { get; set; } }
第二步:在保存ViewModel里发布事件
using Caliburn.Micro; public class EditGameViewModel : Screen { private readonly IEventAggregator _eventAggregator; private readonly IGameRepository _gameRepository; public GameModel CurrentGame { get; set; } public EditGameViewModel(IEventAggregator eventAggregator, IGameRepository gameRepository) { _eventAggregator = eventAggregator; _gameRepository = gameRepository; } public async Task Save() { await _gameRepository.SaveOrUpdateAsync(CurrentGame); // 发布保存完成事件到UI线程 await _eventAggregator.PublishOnUIThreadAsync(new GameSavedEvent { IsNewGame = CurrentGame.GameID == 0 }); // 关闭窗口 await TryCloseAsync(true); } }
第三步:在主ViewModel里订阅事件并刷新
using Caliburn.Micro; using System; public class MainViewModel : PropertyChangedBase, IHandle<GameSavedEvent> { private readonly IEventAggregator _eventAggregator; private readonly IGameRepository _gameRepository; private IDisposable _eventSubscription; public ObservableCollection<GameModel> Games { get; set; } public MainViewModel(IEventAggregator eventAggregator, IGameRepository gameRepository) { _eventAggregator = eventAggregator; _gameRepository = gameRepository; // 订阅事件(指定UI线程处理) _eventSubscription = _eventAggregator.SubscribeOnUIThread(this); LoadGames(); } private async void LoadGames() { var games = await _gameRepository.GetAllAsync(); Games = new ObservableCollection<GameModel>(games); } // 处理保存完成事件的方法,Caliburn会自动匹配 public async Task HandleAsync(GameSavedEvent message) { // 重新加载数据刷新DataGrid var latestGames = await _gameRepository.GetAllAsync(); Games = new ObservableCollection<GameModel>(latestGames); } // 记得在ViewModel销毁时取消订阅,避免内存泄漏 protected override void OnDeactivate(bool close) { _eventSubscription?.Dispose(); base.OnDeactivate(close); } }
这些方案里,前两种是最常用的,简单直接;如果涉及多ViewModel交互,用EventAggregator会更优雅。根据你的实际场景选就行~
内容的提问来源于stack exchange,提问作者Infii




