System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
UIスレッド上にないObservableCollectionを追加または削除しています。
コレクションに追加するメソッドEnqueueReportと、コレクションから削除するDequeueReportという名前があります。
手順の流れは次のとおりです。
私はC#ライブラリにはあまり関わっていません。誰かがこれについて私を案内してくれませんか?
監視可能なコレクションの単純なスレッドフレンドリーバージョンを作成できます。次のように:
public class MTObservableCollection<T> : ObservableCollection<T>
{
public override event NotifyCollectionChangedEventHandler CollectionChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged;
if (CollectionChanged != null)
foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList())
{
DispatcherObject dispObj = nh.Target as DispatcherObject;
if (dispObj != null)
{
Dispatcher dispatcher = dispObj.Dispatcher;
if (dispatcher != null && !dispatcher.CheckAccess())
{
dispatcher.BeginInvoke(
(Action)(() => nh.Invoke(this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
DispatcherPriority.DataBind);
continue;
}
}
nh.Invoke(this, e);
}
}
}
これで、大規模な検索と置換を実行し、すべてのObservableCollection
をMTObservableCollection
に変更します。
.net framwork 4.5以降では、ネイティブコレクション同期を使用できます。
BindingOperations.EnableCollectionSynchronization(YourCollection, YourLockObject);
YourLockObject
は、任意のオブジェクトのインスタンスです。 new Object();
。コレクションごとに1つ使用します。
これにより、特別なクラスなどの必要がなくなります。ただ有効にしてお楽しみください;)
[edit] MarkとEdのコメントに明記されているように(明確化に感謝します!)、これはしない更新時にコレクションをロックすると、コレクションとビューのバインディングが同期され、コレクションがスレッドセーフになりますnot。 [/ edit]
PS:BindingOperations
は名前空間System.Windows.Data
にあります。
ここに投稿されたフランクのソリューションは、1つのスレッドが追加している場合に機能しますが、ObservableCollection自体(およびそれに基づくList)はスレッドセーフではありません。複数のスレッドがコレクションに書き込んでいる場合、追跡が困難なバグが発生する可能性があります。私は、ReaderWriteLockSlimを使用して本当にスレッドセーフになるObservableCollectionのバージョンを作成しました。
残念ながら、StackOverflowの文字制限に達したため、ここではPastebinにあります。 これは、複数のリーダー/ライターで100%機能するはずです。通常のObservableCollectionと同様に、(コールバックを受信したスレッド上の)コレクションからのコールバックでコレクションを変更することは無効です。
ObservableConcurrentCollectionクラスを使用できます。これらは、Parallel Extensions ExtrasライブラリでMicrosoftが提供するパッケージに含まれています。
コミュニティによってNugetで事前にビルドできます: https://www.nuget.org/packages/ParallelExtensionsExtras/
または、こちらからマイクロソフトから入手してください。