【问题标题】:Updating ObservableCollection causes "The Parameter is incorrect" exception更新 ObservableCollection 导致“参数不正确”异常
【发布时间】:2025-12-19 02:50:11
【问题描述】:

我有一个奇怪的问题,我不明白。这是在 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);
        }
    }

我第一次运行代码时,它会用数字 1、2 和 3 填充 ObservableCollection,它们会显示在 ListBox 中。

第二次运行时,所有代码都被执行,但随后抛出了一个未处理的异常,并显示“参数不正确”的消息。

奇怪的是,如果我在构造函数中删除我的行,即我设置 ItemsSource 的行,则不会引发错误。可观察的集合已按应有的方式更新。

另外,如果我注释掉“Words[index] = number”行,它也可以工作。因此,由于某种原因,当我的 ObservableCollection 被设置为 ListBox 的数据源时,我无法替换该项目。

有人能解释为什么吗? (或提出解决方法?)

我的解决方案; 我从

更改了我的代码隐藏
if (index > -1)
    Words[index] = number;

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

这让问题消失了。

【问题讨论】:

    标签: silverlight exception xaml windows-phone-7 observablecollection


    【解决方案1】:

    如果您启用 CLR 异常以在抛出时中断(在 Debug|Exceptions 下),您将看到以下堆栈跟踪:

    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 中的 bug。您可以通过在 ListBox 上将 VirtualizationMode 设置为 Standard 而不是 Recycling 来解决它(如果您不需要虚拟化功能):

    <ListBox VirtualizingStackPanel.VirtualizationMode="Standard"
        ...
    </ListBox>
    

    【讨论】:

    • 感谢调试。我最终得到了另一个解决方案,因为当我将 VirtualizationMode 设置为 Standard 时,ListBox 最终为空。
    • 奇怪 - 它对我有用...您可能希望在解决方案中使用 Words.Insert(index, number) 而不是 Add。
    【解决方案2】:

    作为替代方案,为什么不使用数据绑定,而不是从后面的代码中设置 itemSource?

    【讨论】:

      最近更新 更多