C# 向ListCollectionView添加项时引发异常

C# 向ListCollectionView添加项时引发异常,c#,.net,wpf,exception,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>());

当我运行以下测试时,我得到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; }
}

我可能没有正确使用
AddNewItem
/
CommitNew
吗?

我不确定,但我认为,您应该使用
AddNew()
方法而不是AddNewItem。您将调用
CommitNew()
,而不调用
AddNew()
,并且没有开始事务,因此引发异常

AddNewItem()摘要:
将指定的对象添加到集合。

AddNew()摘要:
启动一个add事务并返回挂起的新项目。

CommitNew()摘要:
结束添加事务并保存挂起的新项目。

因此,您应该编写下一行代码:

Test pendingItem = (Test)collection2.AddNew();
pendingItem.Name = "Bob";
pendingItem.IsTrue = false;
collection2.CommitNew();
可能的解决方案: 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"));
由于您添加了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
,该方法在不同的场景中调整索引,但在添加具有分组功能的新项时未调用该方法,我不确定为什么看起来这是出于设计(?)因此,您必须在新项目开始时手动指定占位符

我刚刚尝试过,但不幸的是,它引发了相同的异常2)我可以确认在添加项目后添加排序和组是否有效,但不幸的是,我需要能够在设置集合视图后添加新项目,而不是继续添加/删除排序和分组:)解决方案1)有效!非常感谢。您认为这是预期的行为还是一个bug?
// !!! When you've added GroupDescription this.IsGrouping becomes true!
if (this.IsGrouping)
{
    this.CommitNewForGrouping();
}
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);
     ...
}