ObservableCollection 深度克隆

时间:2021-04-20 16:58:10

标签: wpf observablecollection deep-copy

我已经实现了 ObservableCollection 的深度克隆,以便通过取消按钮将可编辑 Datagrid 中的项目重置为其原始状态。

为此,我有两个集合 - 一个 ObservableCollection 将 Datagrid 绑定到它,并克隆 List 以在需要时将 ObservableCollection 重新初始化为它的原始状态。

我的代码只在我第一次点击取消按钮时起作用,之后我克隆的 List 也发生了变化。

提供的代码是一个例子(我的有点长),但它和我的 100% 相同:

实现 ICloneable 的模型:

public class EmployeeModel : ICloneable
{
   public object Clone()
   {
       return MemberwiseClone();
   }
    
   public string NAME
   {
      get { return _name; }
      set
         {
            if (_name != value)
            {
               CHANGE = true;
                _name = value;
             }
          }
     }
     private string _name;

     public string SURNAME
     {
        get { return _surname; }
        set
         {
            if (_surname != value)
            {
               CHANGE = true;
                _surname = value;
             }
          }
     }
     private string _surname; 

     ///<summary>Property for tracking changes in model</summary>
     public bool CHANGE { get; set; }
}

视图模型:

public ViewModel() : Base //Implements InotifyPropertyChanged
{
   public ViewModel()
   {
      Task.Run(()=> GetData());
   }

   public ObservableCollection<EmployeeModel> Employees
   {
       get { return _employees; }
       set { _employees = value; OnPropertyChanged();}
   }
   private ObservableCollection<EmployeeModel> _employees;

   public List<EmployeeModel> Copy_employees
   {
        get { return _copy_employees; }
        set { _copy_employees = value; OnPropertyChanged();}
   }
   private List<EmployeeModel> _copy_employees;

   //Fetch data from DB
   private async Task Get_data()
   {
       //Returns new ObservableCollection of type Employee
       Employees = await _procedures.Get_employees();

       if (Employees != null) //Now make a deep copy of Collection
       {
            Copy_employees = new List<EmployeeModel>();
            Copy_employees = Employees.Select(s => (EmployeeModel)s.Clone()).ToList();
       }
    }

   //My Command for canceling changes (reseting DataGrid)
   //CanExecute happens, when model is changed - tracking via CHANGE property of EmployeeModel
   public void Cancel_Execute(object parameter)
   {
        Employees.Clear(); //Tried with re-initializing too, but same result
        
        foreach (var item in Copy_employees)// Reset binded ObservableCollection with old items
        {
             Employees.Add(item);
        }
         
        //Check if copied List really hasn't got any changes                    
        foreach (EmployeeModel item in Copy_employees)
        {
           Console.WriteLine("Changes are " + item.CHANGES.ToString());
        }

     }
 }

取消命令的输出:

1.) 我第一次点击取消按钮:

// Changes are False

下次:

// Changes are True

所以,正如我从控制台看到的那样,当 ObservableCollection 更新时,我复制的 List 也会更新,即使它没有绑定到 DataGrid。 它只更新我更改的属性,因此 List 反映了 ObservableCollection 项。

如何保留 List<Employee> 的原始项目,并随时将它们复制到绑定的 ObservableCollection 中?

1 个答案:

答案 0 :(得分:1)

当您返回值时,您不会返回它们,而是将支持项引用写入可编辑集合。 因此,您在两个集合中拥有相同的实例。 在最简单的情况下,当您返回它们时,您还需要进行克隆。

public void Cancel_Execute(对象参数) { 员工.清除(); //也尝试过重新初始化,但结果相同

    foreach (var item in Copy_employees)// Reset binded ObservableCollection with old items
    {
         Employees.Add((EmployeeModel)item.Clone());
    }
     
    //Check if copied List really hasn't got any changes                    
    foreach (EmployeeModel item in Copy_employees)
    {
       Console.WriteLine("Changes are " + item.CHANGES.ToString());
    }

 }

与问题无关,但我仍然建议您使用稍微对用户友好的界面进行克隆:

public interface ICloneable<T> : ICloneable
{
    new T Clone();
}