WPF中修改传递至其他类的模型值时如何避免影响原模型?
问题场景代码
MyModel 类
public class MyModel : INotifyPropertyChanged { private MyEnum _myEnumValue; public MyEnum MyEnumValue { get => _myEnumValue; set { if (value == _myEnumValue) return; _myEnumValue = value; OnPropertyChanged(); } } // 省略INotifyPropertyChanged相关实现 }
MainViewModel 类
public class MainViewModel { private MyModel _myModelVariable; public MyModel MyModelVariable { get => _myModelVariable; set { _myModelVariable = value; OnPropertyChanged(); } } public MainViewModel() { MyModelVariable = new(); MyModelVariable.MyEnumValue = MyEnum.Enum1; } public void OptionsButton() { _windowManager.ShowDialogAsync(new EditViewModel(MyModelVariable)); } }
EditViewModel 类
public class EditViewModel : INotifyPropertyChanged { private MyModel _localModel; public EditViewModel(MyModel myModel) { _localModel = myModel; } public MyModel LocalModel { get => _localModel; set { _localModel = value; OnPropertyChanged(); } } public void OkButton() { // 通过EventAggregator将LocalModel传回MainViewModel } public void CancelButton() { CloseWindow(); } }
问题说明
基于Caliburn Micro的WPF应用中,点击主界面的选项按钮会打开EditViewModel控制的窗口,传入原始MyModel实例。前端ComboBox绑定EditViewModel的LocalModel,用户修改选中值时,MainViewModel中的原始MyModel值会同步变化。需要避免这种引用类型的同步修改,克隆/复制方案尝试后未解决,求可行方案。
可行解决方案
1. 给MyModel实现深克隆方法
在MyModel中添加克隆方法,创建全新实例并复制所有属性值:
public class MyModel : INotifyPropertyChanged { // 原有属性和INotifyPropertyChanged实现 // 实现克隆方法 public MyModel Clone() { return new MyModel { MyEnumValue = this.MyEnumValue // 后续新增值类型属性时,在此处同步复制 }; } }
修改MainViewModel的打开逻辑,传入克隆后的实例:
public void OptionsButton() { var clonedModel = MyModelVariable.Clone(); _windowManager.ShowDialogAsync(new EditViewModel(clonedModel)); }
用户点击确定时,将克隆实例的属性值同步回原始模型,或直接替换原始模型即可。
2. 手动创建副本实例
若不想实现克隆接口,传递时直接手动创建新实例并复制属性:
public void OptionsButton() { var tempModel = new MyModel { MyEnumValue = MyModelVariable.MyEnumValue }; _windowManager.ShowDialogAsync(new EditViewModel(tempModel)); }
确定操作时,将tempModel的属性值同步回原始MyModel。
3. 使用映射工具批量复制属性
如果模型属性较多,可使用AutoMapper这类本地工具(无需外部链接),先配置映射规则:
// 初始化时配置(如在AppBootstrapper中) var config = new MapperConfiguration(cfg => cfg.CreateMap<MyModel, MyModel>()); var mapper = config.CreateMapper();
然后复制实例:
var clonedModel = mapper.Map<MyModel>(MyModelVariable);
这种方式无需手动逐个复制属性,适合属性较多的场景。
4. 创建专门的编辑DTO
如果编辑界面仅需修改部分属性,可创建一个EditModelDTO,只包含需要编辑的字段,传递DTO到EditViewModel,确定时再将DTO的值映射回原始MyModel:
public class EditModelDTO { public MyEnum MyEnumValue { get; set; } }
修改MainViewModel的打开逻辑:
public void OptionsButton() { var dto = new EditModelDTO { MyEnumValue = MyModelVariable.MyEnumValue }; _windowManager.ShowDialogAsync(new EditViewModel(dto)); }
EditViewModel接收DTO并绑定前端,确定时将DTO的值传回MainViewModel,再赋值给原始MyModel。
内容的提问来源于stack exchange,提问作者MLHYLMZ
相关产品推荐
相关产品推荐

