ObservableCollection 深度克隆

ObservableCollection deep cloning

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

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

我的代码仅在我第一次点击取消按钮时有效,之后我克隆的列表也发生了变化。

提供的代码是示例(我的有点长),但它与我的 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

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

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

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

public void Cancel_Execute(对象参数) { Employees.Clear(); //也尝试重新初始化,但结果相同

    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();
}