I have a form where users can modify a collection of objects using a DataGrid. When the form is opened I create a deep copy of the original collection and if the Cancel butt
Why not keep a copy of the original, and bind to the actual collection. If you bind to the actual collection, then there is no reconciliation. When cancel is pressed, simply replace the actual collection with the copy of the original. It is basically an inversion of what you are trying to do...but it should be a lot easier to manage.
I just worked out the following algorithm for a project I'm working on and I think it complies with your requirements. It follows this steps:
This method maintains the new order and reuses the original references but requires that your objects have an unique identifier. I'm using a Guid for that.
var originalPersons = m_originalList.ToList();
m_originalList.Clear();
foreach (var modifiedPerson in m_modifiedList)
{
var originalPerson = originalPersons.FirstOrDefault(c => c.ID == modifiedPerson.ID);
if (originalPerson == null)
m_originalList.Add(modifiedPerson);
else
{
m_originalList.Add(originalPerson);
originalPerson.Document = modifiedPerson.Document;
originalPerson.Name = modifiedPerson.Name;
...
}
}
Good luck.
The way I've dealt with this depends on the collections of objects having a unique ID. I also pass in the repository to deal with this as well, but for brevity I left it out. It's similiar to the following:
public static void MergeFields(IEnumerable<TYPE1> persistedValues, IEnumerable<TYPE1> newValues)
{
var leftIds = persistedValues.Select(x => x.Id).ToArray();
var rightIds = newValues.Select(x => x.Id).ToArray();
var toUpdate = rightIds.Intersect(leftIds).ToArray();
var toAdd = rightIds.Except(leftIds).ToArray();
var toDelete = leftIds.Except(rightIds).ToArray();
foreach(var id in toUpdate){
var leftScope = persistedValues.Single(x => x.ID == id);
var rightScope = newValues.Single(x => x.ID == id);
// Map appropriate values from rightScope over to leftScope
}
foreach(var id in toAdd) {
var rightScope = newValues.Single(x => x.ID == id);
// Add rightScope to the repository
}
foreach(var id in toDelete) {
var leftScope = persistedValues.Single(x => x.ID == id);
// Remove leftScope from the repository
}
// persist the repository
}