C# WPF CollectionView错误:';收集被修改;枚举操作可能无法执行;
我正在重写C# WPF CollectionView错误:';收集被修改;枚举操作可能无法执行;,c#,.net,wpf,observablecollection,collectionview,C#,.net,Wpf,Observablecollection,Collectionview,我正在重写System.Windows.Data.CollectionView的行为。有一种方法可以从数据库中清除并重新填充CollectionView.SourceCollection(在我的例子中,这是一种observeCollection)。引发异常: 引发异常:mscorlib.dll中的“System.InvalidOperationException” 附加信息:集合已修改;枚举操作 可能不会执行 它正好在第二次命中此行时抛出sourceobservecollection.Add(i
System.Windows.Data.CollectionView
的行为。有一种方法可以从数据库中清除并重新填充CollectionView.SourceCollection
(在我的例子中,这是一种observeCollection
)。引发异常:
引发异常:mscorlib.dll中的“System.InvalidOperationException”
附加信息:集合已修改;枚举操作
可能不会执行
它正好在第二次命中此行时抛出sourceobservecollection.Add(item)代码>
(注释行描述了我修复问题的失败尝试):
然而,我仍然不知道如何避开这个问题,甚至不知道到底出了什么问题。任何帮助都将不胜感激
当前.Net Framework版本:4.5当您迭代集合并尝试修改它时,会发生此异常。通常,当您在集合上迭代时,它会返回一个IEnumerable,您可以假定它是一个按顺序向前移动的指针。假设您更改了集合,然后迭代器变得无效,框架抛出无效操作异常
例如(伪代码)
在上面的代码中,肯定会抛出异常
为了处理这种情况,您必须迭代集合,并希望执行一些修改操作,同时使用索引
例如(伪代码)
for(int i=0;i
事实证明,问题实际上出在ObservableCollection
本身,因为它不是线程安全的。它似乎是在UI线程中读取的,而它仍在修改中,问题中描述的与线程相关的解决方法不起作用,因为无论如何都会引发CollectionChanged
事件。用线程安全版本替换类型observateCollection
解决了问题。这可能是因为结果
仍在填充中(在方法refreshSourceFunction
中),并且您开始迭代它(foreach
)?我想到了这一点,但如果是这样的话,在第2次、第3次或第4次尝试中,应通过.ToList()
解决此问题。即使没有.ToList()
,结果也从未被修改过@kennyzxDispatcher.BeginInvoke(()=>/{////////////////////////////////////////////////////
我正在迭代的IEnumerable(result
)从未被修改过。结果来自SourceCollection,是吗?如果是这样的话,可以使用result.ToList()在循环中也是如此。恐怕不是;它来自数据库。嗯。我明白你的意思。在这个场景中,我们可以做的是委托声明。指向它的方法。Dispatcher.BeginInvoke(()=>/{///////////源ObservableCollection.Add(item);//},也试试这个让我们看看
//...
public ObservableCollection<object> SourceObservableCollection { get { return (ObservableCollection<object>)SourceCollection; } }
//<Part of Attempt7>
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
base.OnCollectionChanged(args);
isCollectionChanging = false;
}
private bool isCollectionChanging = false;
//</Part of Attempt7>
//<Part of Attempt9>
private static readonly object _lock = new object();
//</Part of Attempt9>
//<*async syntax is part of Attempt10*/>
public async void RefreshSource()
{
SourceObservableCollection.Clear();
// refreshSourceFunction retrieves data from Database
IEnumerable result = refreshSourceFunction(/*parameters*/);
////Attempt1:
foreach (object item in result)
{
SourceObservableCollection.Add(item);
}
////Attempt2:
//foreach (object item in result.OfType<object>().ToList())
//{
// SourceObservableCollection.Add(item);
//}
////Attempt3:
//List<object> lstResult = result.OfType<object>().ToList();
//foreach (object item in lstResult)
// SourceObservableCollection.Add(item);
////Attempt4:
//List<object> lstResult2 = result.OfType<object>().ToList();
//for (int x = 0; x < lstResult2.Count; x++)
//{
// SourceObservableCollection.Add(lstResult2[x]);
//}
////Attempt5:
//IEnumerator enumerator = result.GetEnumerator();
//while (enumerator.MoveNext())
//{
// SourceObservableCollection.Add(enumerator.Current);
//}
////Attempt6:
//IEnumerator enumerator2 = result.GetEnumerator();
//while (enumerator2.MoveNext())
//{
// Dispatcher.Invoke(() =>
// {
// SourceObservableCollection.Add(enumerator2.Current);
// });
//}
////Attempt7:
//foreach (object item in result)
//{
// isCollectionChanging = true;
// Dispatcher.Invoke(() =>
// {
// SourceObservableCollection.Add(item);
// }, System.Windows.Threading.DispatcherPriority.Background);
// while (isCollectionChanging) ;
//}
////Attempt8:
//foreach (object item in result)
//{
// SourceObservableCollection.Add(item);
// Refresh();
//}
////Attempt9:
//foreach (object item in result)
//{
// lock (_lock)
// {
// SourceObservableCollection.Add(item);
// }
//}
////Attempt10:
//await Dispatcher.InvokeAsync(() => SourceObservableCollection.Clear());
//IEnumerable result2 = await Task.Run(() => refreshSourceFunction(/*parameters*/));
//foreach (object item in result2)
//{
// await Dispatcher.InvokeAsync(() => SourceObservableCollection.Add(item));
//}
}
//...
/// <summary>
/// for a collection implementing IEnumerable this offers
/// optimistic indexer, i.e. this[int index] { get; }
/// and cached Count/IsEmpty properties and IndexOf method,
/// assuming that after an initial request to read item[N],
/// the following indices will be a sequence for index N+1, N+2 etc.
/// </summary>
/// <remarks>
/// This class is NOT safe for multi-threaded use.
/// if the source collection implements IList or ICollection, the corresponding
/// properties/methods will be used instead of the cached versions
/// </remarks>
internal class IndexedEnumerable : IEnumerable, IWeakEventListener
{
//...
Foreach(var item in collection)
{
modify collection here; (Do some add , remove or clear operation)
}
for(int i=0; i< collection.count(); i++)
{
// do anything here
}