Catel MVVM框架中如何将标记[Model]属性的模型重置为初始状态
问题根因
- [Expose]特性由Catel.Fody在编译时织入代理属性,属性的get/set会直接透传标记了[Model]特性的实例对应属性,ViewModel层不会额外存储这些属性的副本,因此内置的
CancelAsync、ResetModel方法只会重置ViewModel自身声明的属性,不会处理透传的Model属性。 - 修改Model属性后Expose的代理属性没有同步,是因为
Part类未实现INotifyPropertyChanged接口,Catel无法捕获Model层的属性变更事件,也就无法通知界面更新代理属性的值。
可行解决方案
方案1(推荐):调整Model实现复用Catel内置逻辑
让Part类继承Catel的ModelBase,自动获得INotifyPropertyChanged实现和编辑状态管理能力,Catel会自动监听[Model]实例的属性变更,重置后会自动同步到Expose的属性。
// Part模型定义 public class Part : ModelBase { public string Number { get; set; } public string Description { get; set; } }
ViewModel中重置逻辑:
private void OnResetExecute() { // 调用Model的CancelEdit回滚到上次保存的状态 Part.CancelEdit(); // 兜底触发所有属性变更通知,确保界面同步 RaisePropertyChanged(string.Empty); }
方案2:无需修改Model的手动备份方案
如果不能修改Part类的实现,可以在ViewModel初始化时备份Model的初始值,重置时手动赋值:
public class PartEditViewModel : ViewModelBase { private Part _initialPart; [Model] [Expose("Number")] [Expose("Description")] public Part Part { get; set; } public PartEditViewModel(Part part) { Part = part; // 深拷贝初始值,避免和当前Part共用引用 _initialPart = DeepClone(part); } private void OnResetExecute() { // 还原备份的属性值 Part.Number = _initialPart.Number; Part.Description = _initialPart.Description; // 触发所有属性变更通知,同步界面 RaisePropertyChanged(string.Empty); } // 简单深拷贝实现,复杂对象可改用序列化方式实现 private Part DeepClone(Part source) { return new Part { Number = source.Number, Description = source.Description }; } }
方案3:兼容原有ResetModel调用的方案
你之前调用ResetModel未生效是因为没有触发属性变更通知,补充一行通知代码即可:
private void OnResetExecute() { ResetModel(nameof(Part), ModelCleanUpMode.CancelEdit); // 强制触发所有属性变更通知,同步Expose的属性到界面 RaisePropertyChanged(string.Empty); }
注意:如果你的Model是自定义实现没有继承Catel的
ModelBase,修改属性后必须触发PropertyChanged事件界面才会更新,调用RaisePropertyChanged(string.Empty)是最简单的兜底方案,不需要逐个处理Expose的属性。
内容的提问来源于stack exchange,提问作者pgross
相关产品推荐
相关产品推荐

