Обновление ObservableCollection вызывает исключение «Неверный параметр» - PullRequest
4 голосов
/ 07 мая 2011

У меня странная проблема, которую я не понимаю. Это в Silverlight / WP7.

Я заполняю ObservableCollection элементами, а позже я хочу обновить каждый из элементов.

Мне удалось сократить код, чтобы воспроизвести ошибку. Мой XAML - это просто ListBox и Button.

    private ObservableCollection<int> Words = new ObservableCollection<int>();

    public MainPage()
    {
        InitializeComponent();

        listBox1.ItemsSource = Words;
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        List<int> numbers = new List<int>()
                                {
                                    1,2,3
                                };

        foreach (var number in numbers)
        {
            var index = Words.IndexOf(number);
            if (index > -1)
                Words[index] = number;
            else
                Words.Add(number);
        }
    }

При первом запуске кода он заполняет ObservableCollection числами 1, 2 и 3, и они отображаются в ListBox.

При втором запуске выполняется весь код, но затем выдается необработанное исключение с сообщением «Неверный параметр».

Странная вещь в том, что если я удалю свою строку в конструкторе, ту, где я установил ItemsSource, ошибка не будет выдана. Наблюдаемая коллекция обновляется, как и должно быть.

Кроме того, если я закомментирую строку «Words [index] = number», это тоже сработает. Поэтому по какой-то причине, когда моя коллекция ObservableCollection установлена ​​как источник данных для ListBox, я не могу заменить элемент.

Может кто-нибудь объяснить, почему? (Или предложить обходной путь?)

Мое решение; Я изменил свой код от

if (index > -1)
    Words[index] = number;

до

if (index > -1)
{
    Words.RemoveAt(index);
    Words.Add(number);
}

Это заставило проблему уйти.

Ответы [ 2 ]

3 голосов
/ 08 мая 2011

Если вы включите исключения CLR, когда они будут выброшены (в разделе «Отладка | Исключения»), вы увидите следующую трассировку стека:

mscorlib.dll!System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument argument, System.ExceptionResource resource) + 0x10 bytes 
mscorlib.dll!System.ThrowHelper.ThrowArgumentOutOfRangeException() + 0x9 bytes  
mscorlib.dll!System.Collections.Generic.List<object>.this[int].get(int index) + 0xe bytes   
mscorlib.dll!System.Collections.ObjectModel.Collection<object>.System.Collections.IList.get_Item(int index) + 0x7 bytes 
System.Windows.dll!System.Windows.Controls.ItemCollection.GetItemImpl(int index) + 0x17 bytes   
System.Windows.dll!System.Windows.Controls.ItemCollection.GetItemImplSkipMethodPack(int index) + 0x2 bytes  
System.Windows.dll!System.Windows.PresentationFrameworkCollection<object>.this[int].get(int index) + 0x2 bytes  
System.Windows.dll!System.Windows.Controls.VirtualizingStackPanel.CleanupContainers(System.Windows.Controls.ItemsControl itemsControl) + 0xa3 bytes 
System.Windows.dll!System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(System.Windows.Size constraint) + 0x56a bytes 
System.Windows.dll!System.Windows.FrameworkElement.MeasureOverride(System.IntPtr nativeTarget, float inWidth, float inHeight, out float outWidth, out float outHeight) + 0x45 bytes 
[External Code] 

По какой-то причине панель стека виртуализации пытается очистить элемент с индексом -1 (вы можете увидеть это значение для индекса в кадре стека).

Тип содержимого ObservableCollection не имеет значения. Вы получаете ту же ошибку со строками ... и это происходит только с двумя элементами.

Для меня это выглядит как ошибка в VirtualizingStackPanel. Вы можете обойти это (если вам не нужны функциональные возможности виртуализации), установив для VirtualizationMode значение Standard вместо Recycling в ListBox:

<ListBox VirtualizingStackPanel.VirtualizationMode="Standard"
    ...
</ListBox>
2 голосов
/ 07 мая 2011

В качестве альтернативы, почему бы не использовать привязку данных вместо установки itemSource из кода позади?

...