Updating ObservableCollection causes "The Parameter is incorrect" exception
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 un开发者_运维技巧handled 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.
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>
As an alternative, why not use databinding, rather than setting the itemSource from code behind?
精彩评论