"Specified argument was out of the range of valid values.Parameter name: index" 向 ObservableCollection 添加新项目时<T>

"Specified argument was out of the range of valid values.Parameter name: index" when adding new item to ObservableCollection<T>

我遇到这样的异常:

'FooStorageStorage.Add(new TreeViewItem() { Header=i.ToString()})' threw an exception of type 'System.ArgumentOutOfRangeException': "Specified argument was out of the range of valid values.\r\nParameter name: index"

我在 viewModel 中有一个 属性:

private ObservableCollection<TreeViewItem> fooStorage=new ObservableCollection<TreeViewItem>();
public ObservableCollection<TreeViewItem> FooStorage
{
   get { return facetStorage; }
   set { facetStorage = value; }
}

但是,在我清除 FooStorage 并尝试添加新项目后:

private void LoadData()
{
    if (FooStorage.Count > 0)
    {
       FooStorage.Clear();
    }
    for (int k = 0; k < lengthOfColl; k++)            
    {
       FooStorage.Add(new TreeViewItem() { Header=k.ToString()});//here is exception
    }
}

我遇到了上述异常。

当我第一次调用 LoadData() 方法时,一切正常。然后如果我第二次调用 LoadData() 方法,就会得到这样的异常。

有人遇到过这样的异常吗?最有趣的是我在测试项目中无法重现这个异常。

堆栈跟踪:

System.ArgumentOutOfRangeException was unhandled HResult=-2146233086 Message=Specified argument was out of the range of valid values. Parameter name: index ParamName=index Source=PresentationCore
StackTrace: at System.Windows.Media.VisualCollection.Insert(Int32 index, Visual visual) at System.Windows.Controls.UIElementCollection.InsertInternal(Int32 index, UIElement element) at System.Windows.Controls.Panel.AddChildren(GeneratorPosition pos, Int32 itemCount) at System.Windows.Controls.Panel.OnItemsChangedInternal(Object sender, ItemsChangedEventArgs args) at System.Windows.Controls.Panel.OnItemsChanged(Object sender, ItemsChangedEventArgs args) at System.Windows.Controls.ItemContainerGenerator.OnItemAdded(Object item, Int32 index) at System.Windows.Controls.ItemContainerGenerator.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) at System.Windows.WeakEventManager.ListenerList1.DeliverEvent(Object sender, EventArgs e, Type managerType) at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args) at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) at System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args) at System.Windows.Controls.ItemCollection.OnViewCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) at System.Windows.WeakEventManager.ListenerList1.DeliverEvent(Object sender, EventArgs e, Type managerType) at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args) at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) at System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args) at System.Windows.Data.ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs args, Int32 adjustedOldIndex, Int32 adjustedNewIndex) at System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) at System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) at System.Collections.ObjectModel.ObservableCollection1.OnCollectionChanged(NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection1.InsertItem(Int32 index, T item) at System.Collections.ObjectModel.Collection1.Add(T item) at ModuleA.ViewModel.PersonControlViewModel.LoadData(IPerson person) in D:\WPF\...\ViewModel\PersonControlViewModel.cs:line 110 at Prism.Commands.DelegateCommand1.<>c__DisplayClass1_0.<.ctor>b__0(Object o) at Prism.Commands.DelegateCommandBase.<>c__DisplayClass5_0.<.ctor>b__0(Object arg) at Prism.Commands.DelegateCommandBase.d__14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Prism.Commands.DelegateCommandBase.d__12.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.b__6_0(Object state) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.DispatcherOperation.InvokeImpl() at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state) at System.Windows.Threading.DispatcherOperation.Invoke() at System.Windows.Threading.Dispatcher.ProcessQueue() at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame) at System.Windows.Application.RunDispatcher(Object ignore) at System.Windows.Application.RunInternal(Window window) at System.Windows.Application.Run(Window window) at System.Windows.Application.Run() at PrototypeBootstrapper.App.Main() in D:\WPF...\Src\PrototypeBootstrapper\obj\Debug\App.g.cs:line 0 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:

更新:

我正在将 FooStorage 中的新 TreeViewItem's 添加到位于 DataGridTextBoxColumn 的 HeaderTemplate 内的不同 TreeView。因此,当用户单击 DataGridTextBoxColumn2Header1 时,Header1TreeView 将由来自 viewModel 的 FooStorage 填充。好的。当用户单击 DataGridTextBoxColumn2Header2 时,Header2TreeView 应该由 viewModel 中的 FooStorage 填充,但是当我 Clear()Add() 新项目到 FooStorage,然后我遇到了上述异常。

只是想说将 UI 元素 TreeViewItem 传递给 ViewModel 是一种不好的做法。所以也许添加新的 TreeViewItem 然后在不同的地方使用是我的问题。

正如@Sinatr 所说:

You should not use TreeViewItem directly in ViewModel. Moreover framework elements (including TreeViewItem) can have only one parent at a time. Maybe adding new TreeViewItem which is then used in different places is your problem (cba to check sources if it's the case, simply don't do it). Rather use TreeViewItemViewModel (call it shorter, e.g. ItemViewModel).

帕特里克霍夫曼建议我禁用 UI 中的那个部分,在我禁用它之后,就没有问题了。

所以我得出结论,我遇到了使用不良做法的后果并受到了惩罚。 避免不良做法。而ObservableCollection<T>无罪!抱歉,ObservableCollection<T>.

Now I am learning about TreeView by Josh Smith.