private IChangeSet <IGrouping <TObject, TGroupKey> > Process(ChangeAwareList <IGrouping <TObject, TGroupKey> > result, IDictionary <TGroupKey, GroupContainer> allGroupings, IChangeSet <ItemWithGroupKey> changes) { //need to keep track of effected groups to calculate correct notifications var initialStateOfGroups = new Dictionary <TGroupKey, IGrouping <TObject, TGroupKey> >(); foreach (var grouping in Enumerable.GroupBy(changes.Unified(), change => change.Current.Group)) { //lookup group and if created, add to result set var currentGroup = grouping.Key; var groupContainer = GetGroup(allGroupings, currentGroup); void GetInitialState() { if (!initialStateOfGroups.ContainsKey(grouping.Key)) { initialStateOfGroups[grouping.Key] = GetGroupState(groupContainer); } } var listToModify = groupContainer.List; //iterate through the group's items and process foreach (var change in grouping) { switch (change.Reason) { case ListChangeReason.Add: { GetInitialState(); listToModify.Add(change.Current.Item); break; } case ListChangeReason.Refresh: { var previousItem = change.Current.Item; var previousGroup = change.Current.PrevousGroup.Value; var currentItem = change.Current.Item; //check whether an item changing has resulted in a different group if (!previousGroup.Equals(currentGroup)) { GetInitialState(); //add to new group listToModify.Add(currentItem); //remove from old group allGroupings.Lookup(previousGroup) .IfHasValue(g => { if (!initialStateOfGroups.ContainsKey(g.Key)) { initialStateOfGroups[g.Key] = GetGroupState(g.Key, g.List); } g.List.Remove(previousItem); }); } break; } case ListChangeReason.Replace: { GetInitialState(); var previousItem = change.Previous.Value.Item; var previousGroup = change.Previous.Value.Group; //check whether an item changing has resulted in a different group if (previousGroup.Equals(currentGroup)) { //find and replace var index = listToModify.IndexOf(previousItem); listToModify[index] = change.Current.Item; } else { //add to new group listToModify.Add(change.Current.Item); //remove from old group allGroupings.Lookup(previousGroup) .IfHasValue(g => { if (!initialStateOfGroups.ContainsKey(g.Key)) { initialStateOfGroups[g.Key] = GetGroupState(g.Key, g.List); } g.List.Remove(previousItem); }); } break; } case ListChangeReason.Remove: { GetInitialState(); listToModify.Remove(change.Current.Item); break; } case ListChangeReason.Clear: { GetInitialState(); listToModify.Clear(); break; } } } } return(CreateChangeSet(result, allGroupings, initialStateOfGroups)); }