ArgumentOutOfRangeException when replacing items in an ObservableCollection<T>

感情迁移 提交于 2020-01-03 21:14:52

问题


I'm working on a Refresh() extension method for ObservableCollection which adds, removes or replaces items based on a matching key (this means when bound to a DataGrid the grid doesn't re-scroll and items don't change their position unless they were removed).

Problem is when I replace items in the ObservableCollection the last item throws an ArgumentOutOfRangeException, what am I missing here?

public static void Refresh<TItem, TKey>(this ObservableCollection<TItem> target, IEnumerable<TItem> source, Func<TItem, TKey> keySelector)
{
    var sourceDictionary = source.ToDictionary(keySelector);
    var targetDictionary = target.ToDictionary(keySelector);

    var newItems = sourceDictionary.Keys.Except(targetDictionary.Keys).Select(k => sourceDictionary[k]).ToList();
    var removedItems = targetDictionary.Keys.Except(sourceDictionary.Keys).Select(k => targetDictionary[k]).ToList();
    var updatedItems = (from eachKey in targetDictionary.Keys.Intersect(sourceDictionary.Keys)
                        select new
                        {
                            Old = targetDictionary[eachKey],
                            New = sourceDictionary[eachKey]
                        }).ToList();

    foreach (var updatedItem in updatedItems)
    {
        int index = target.IndexOf(updatedItem.Old);
        target[index] = updatedItem.New; // ArgumentOutOfRangeException is thrown here
    }

    foreach (var removedItem in removedItems)
    {
        target.Remove(removedItem);
    }

    foreach (var newItem in newItems)
    {
        target.Add(newItem);
    }
}

回答1:


You've got Old and New the wrong way round. This:

var updatedItems = (from eachKey in targetDictionary.Keys
                                              .Intersect(sourceDictionary.Keys)
                    select new
                    {
                        Old = targetDictionary[eachKey],
                        New = sourceDictionary[eachKey]
                    }).ToList();

should be this:

var updatedItems = (from eachKey in targetDictionary.Keys
                                              .Intersect(sourceDictionary.Keys)
                    select new
                    {
                        New = targetDictionary[eachKey],
                        Old = sourceDictionary[eachKey]
                    }).ToList();

Currently you're looking for the index of the new value, which will be -1...



来源:https://stackoverflow.com/questions/1659692/argumentoutofrangeexception-when-replacing-items-in-an-observablecollectiont

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!