更新 ObservableCollection 会导致“参数不正确”例外

发布于 2024-11-05 08:34:19 字数 1415 浏览 5 评论 0原文

我有一个奇怪的问题我不明白。这是在 Silverlight/WP7 中。

我正在用项目填充 ObservableCollection,稍后我想更新每个项目。

我已经设法删除代码以重现该错误。我的 XAML 只是一个列表框和一个按钮。

    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);
}

使得问题消失了。

I've got a weird issue I don't understand. This is in Silverlight/WP7.

I'm filling an ObservableCollection with items, and later I want to update each of the items.

I've managed to strip down the code to reproduce the error. My XAML is just a ListBox and a 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);
        }
    }

The first time I run the code it fills the ObservableCollection with the numbers 1, 2 and 3, and they are displayed in the ListBox.

The second time it is run all the code is executed, but then an unhandled exception with the message "The parameter is incorrect" is thrown.

The weird thing is that if I remove my line in the constructor, the one where I set up the ItemsSource, the error isn't thrown. The observable collection is updated as it should.

Also, if I comment out the "Words[index] = number" line it also works. So for some reason, when my ObservableCollection is set as the datasource to a ListBox I can't replace the item.

Can someone explain why? (Or suggest a workaround?)

My solution;
I changed my codebehind from

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

to

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

That made the problem go away.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

红尘作伴 2024-11-12 08:34:19

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

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

If you enable CLR Exceptons to break when thrown (under Debug|Exceptions) you'll see this stack trace:

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] 

For some reason the virtualizing stack panel is trying to clean up the element at index -1 (you can see this value for index in the stack frame).

The type of the ObservableCollection's contents makes no difference. You get the same error with strings ... and it happens with just two elements.

To me it looks like a bug in the VirtualizingStackPanel. You can work around it (if you don't need the virtualizing functionality) by setting the VirtualizationMode to Standard instead of Recycling on the ListBox:

<ListBox VirtualizingStackPanel.VirtualizationMode="Standard"
    ...
</ListBox>
小霸王臭丫头 2024-11-12 08:34:19

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

As an alternative, why not use databinding, rather than setting the itemSource from code behind?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文