Возникает исключение при добавлении элемента в ListCollectionView. - PullRequest
2 голосов
/ 23 марта 2012

Когда я запускаю следующий тест, я получаю 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 ]

1 голос
/ 23 марта 2012

Возможные решения:

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 для новых элементов.

0 голосов
/ 23 марта 2012

Я не уверен, но я думаю, что вы должны использовать 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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...