从CollectionChanged事件处理程序中的ObservableCollection中删除项

时间:2012-03-16 19:32:03

标签: c# observablecollection

我希望能够在将一些项目添加到ObservableCollection后拒绝它们。我无法继承ObservableCollection或使用任何类型的视图,因此我似乎仅限于使用定义的一个事件处理程序(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调用放在另一个处理程序中是另一个想到的选项。

5 个答案:

答案 0 :(得分:17)

查看Common Mistakes using Observable Collection

话虽如此,如果你仍想走这条路 - 你可以旋转new Thread

答案 1 :(得分:12)

如果你真的想要修改一个集合,你将要遍历集合的副本。因为你试图修改foreach循环中的集合,这会让你感到悲伤。

例如

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

}

说,我同意Anurag你不应该用observablecollection做这种事情,当然不是在CollectionChanged事件中。

答案 2 :(得分:1)

我曾尝试使用设置标志来请求集合添加/删除更改,然后当 System.Windows.Interop.ComponentDispatcher.ThreadIdle 调用我的处理程序时,执行添加或删除操作。这样可行。但是,在集合更改处理程序中使用 try-finally 取消连接然后重新连接相同的集合更改事件处理程序也绕过了重入问题:

private void MyDataGrid_CollectionChanged( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e )
{
    try
    {
        dgRows.CollectionChanged -= MyDataGrid_CollectionChanged;
        
        switch( e.Action )
        {
            case NotifyCollectionChangedAction.Add:
                if( SomeTestIsTrue() )
                dgRows.Add( new vmRowObject() );
                break;
        }
    }
    finally
    {
        dgRows.CollectionChanged += MyDataGrid_CollectionChanged;
    }
}

答案 3 :(得分:0)

使用ToList()来迭代列表。

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

答案 4 :(得分:0)

在oncollection更改中使用了它,并且可以正常工作(WPF和MVVM示例):

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