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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 00:34:57