web-dev-qa-db-ja.com

CollectionChangedイベントハンドラーのObservableCollectionからアイテムを削除します

ObservableCollectionに追加された後、一部のアイテムを拒否できるようにしたいと思っています。 ObservableCollectionをサブクラス化したり、任意の種類のビューを使用したりできないため、定義された1つのイベントハンドラー(CollectionChanged)を使用して、禁止されたアイテムに対して.Remove()を実行することに制限されているようです。イベントが発生してから処理されるまでの間にアイテムが短期間存在する場合は問題ありません。アイテムはコレクション内に保持されるべきではありません。 CollectionChangedイベントハンドラー内で.Remove()を呼び出すことは許可されていないようです。実行時に.NETはInvalidOperationExceptionをスローします。

CollectionChangedイベント中にObservableCollectionを変更できません。」

個人的には、.NETで許可されるべきだと思います。私が無限ループを作成する場合、それは私自身のひどい過ちです。

使用したいコードは次のようになります。

myCollection.CollectionChanged += (sender, args) =>
{
    if (args.Action == NotifyCollectionChangedAction.Remove)
        return;
    foreach (var itm in myCollection)
    {
        if (itm.name == "Fred")
            myCollection.Remove(itm);
    }
}

どのようなオプションがあるのか​​わかりません。ディスパッチャーを使用しても機能しないようです。別のイベントをトリガーして.Remove呼び出しを別のハンドラーに配置することが、頭に浮かぶ唯一の他のオプションです。

12
ebpa

チェックアウト Observable Collectionを使用した一般的な間違い

そうは言っても、それでもこのルートに行きたい場合は、スピンすることができます 新しいスレッド

17
Raj Ranjhan

コレクションを本当に変更したい場合は、コレクションのコピーを反復処理する必要があります。これは、foreachループのコレクションを変更しようとしているために悲しみを引き起こしているためです。

var copy = new ObservableCollection<YourType>(collection)
foreach(var item in copy)
{
    if(item.Name == "Fred")
    {
        collection.Remove(item);
    }

}

そうは言っても、私はAnuragに同意します。この種のことを、observablecollectionで行うべきではなく、CollectionChangedイベント内で行うべきではないということです。

13
tam

これをoncollectionchangedで使用して機能します(WPFおよびMVVMの例):

new System.Threading.Thread(t =>
{
  Application.Current.Dispatcher.Invoke((Action)delegate
  {
    OnHoldMessages.Add(_selectedOnHoldMessage);
    RaisePropertyChanged(propertyName: "OnHoldMessages");
  });
}).Start();
0
Mark

リストを反復処理するには、ToList()を使用します。

foreach(var item in collection.ToList())
{
    if(item.Name == "Fred")
    {
        collection.Remove(item);
    }
}
0
Gilad