将项添加到ListCollectionView时抛出异常

时间:2012-03-23 09:30:29

标签: c# .net wpf exception

当我运行以下测试时,我得到一个ArgumentOutOfRangeException:

[TestClass]
public class ReproduceException
{
    [TestMethod]
    public void Doesnt_throw_when_adding_to_grouped_collection()
    {
        var collection = new ListCollectionView(new List<Test>());
        collection.SortDescriptions.Add(new SortDescription("IsTrue", ListSortDirection.Ascending));
        collection.GroupDescriptions.Add(new PropertyGroupDescription("Name"));
        collection.AddNewItem(new Test() { Name = "Bob", IsTrue = false });
        collection.CommitNew();

    }
}

public class Test
{
    public string Name { get; set; }
    public bool IsTrue { get; set; }
}

我得到以下异常:

System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.ObjectModel.Collection`1.RemoveAt(Int32 index)
at System.Windows.Data.ListCollectionView.CommitNewForGrouping()
at System.Windows.Data.ListCollectionView.CommitNew()

我可能没有以正确的方式使用AddNewItem / CommitNew吗?

2 个答案:

答案 0 :(得分:1)

可能的解决方案:

1)在添加新项目之前执行

 collection.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtBeginning;

2)在创建分组和排序之前,基本上尝试添加项目:

var collection = new ListCollectionView(new List<Test>());            
collection.AddNewItem(new Test() { Name = "Bob", IsTrue = false });
collection.CommitNew();

collection.SortDescriptions.Add(new SortDescription("IsTrue", 
                                          ListSortDirection.Ascending));   
collection.GroupDescriptions.Add(new PropertyGroupDescription("Name"));

分析:

在深入研究.NET Reflector后,CommitNew()方法有以下检查:

// !!! When you've added GroupDescription this.IsGrouping becomes true!
if (this.IsGrouping)
{
    this.CommitNewForGrouping();
}

由于您已添加GroupDescription,因此它将提交分组:

private void CommitNewForGrouping()
{
    int num;   

    // !!! I believe it is None by default
    switch (this.NewItemPlaceholderPosition)
    {
        case NewItemPlaceholderPosition.AtBeginning:
            num = 1;
            break;

        case NewItemPlaceholderPosition.AtEnd:
            num = this._group.Items.Count - 2;
            break;

        default:
            // !!! Since you've not added groups -1 would be assigned to num
            num = this._group.Items.Count - 1;
            break;
    }
    int index = this._newItemIndex;
    object item = this.EndAddNew(false);

    // This method will call RemoveAt(num) where num == -1 in your case
    this._group.RemoveSpecialItem(num, item, false);
    this.ProcessCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, 
             item, index));

}

internal void RemoveSpecialItem(int index, object item, bool loading)
{
     ...
     // will fail since index always -1
     base.ProtectedItems.RemoveAt(index);
     ...
}

LCV有私有方法ProcessCollectionChangedWithAdjustedIndex,它可以在不同情况下调整索引,但是在添加分组启用的新项目时不调用它,我不知道为什么这样看起来像是设计(?!)所以您已为新项目手动指定占位符AtBeginning

答案 1 :(得分:0)

我不确定,但我认为你应该使用AddNew()方法而不是AddNewItem。你打算调用CommitNew(),而不是调用AddNew(),并且没有开始事务,所以抛出了异常。

AddNewItem()摘要:Adds the specified object to the collection.

AddNew()摘要:Starts an add transaction and returns the pending new item.

CommitNew()摘要:Ends the add transaction and saves the pending new item.

所以,你应该编写下一行代码:

Test pendingItem = (Test)collection2.AddNew();
pendingItem.Name = "Bob";
pendingItem.IsTrue = false;
collection2.CommitNew();