【问题标题】:Remove an item from an ObservableCollection in a CollectionChanged event handler在 CollectionChanged 事件处理程序中从 ObservableCollection 中删除项目
【发布时间】:2012-03-16 19:32:03
【问题描述】:

我希望能够在将某些项目添加到 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 调用放在另一个处理程序中是唯一想到的其他选项。

【问题讨论】:

  • 您不能从 ObservableCollection 中删除项目。这就是一个重点......您只能从它正在包装的集合中删除项目。
  • 您不应该在集合更改事件处理程序中执行此操作。而是在允许更改集合之前执行过滤器。如果不适当的更改,请勿更改集合。
  • 我知道这是旧的,可​​能不是“正确”的方法;但这是我所做的,可能会帮助某人。当我试图从 OberservableCollection 中删除选定的文件时,我遇到了同样的问题。当我的 Messenger 正在处理第二个文件删除请求时,CollectionChange 事件仍在触发。因此,在我的 CollectionChanged 事件处理程序中,我必须添加 lock (this.Files) { // Code of the Event } 完成此操作后,我再次运行我的程序并选择多个文件并点击删除。这一次也不例外,因为 Remove 必须等待。

标签: c# observablecollection


【解决方案1】:

查看Common Mistakes using Observable Collection

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

【讨论】:

【解决方案2】:

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

例子

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

}

也就是说,我同意 Anurag 的观点,即您不应该使用 observablecollection 来做这种事情,当然也不应该在 CollectionChanged 事件中。

【讨论】:

    【解决方案3】:

    我曾尝试使用设置标志来请求集合添加/删除更改,然后当 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;
        }
    }
    

    【讨论】:

      【解决方案4】:

      使用ToList() 来遍历列表。

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

      【讨论】:

        【解决方案5】:

        在 oncollectionchanged 中使用它并且它可以工作(WPF 和 MVVM 示例):

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-01-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-21
          • 2021-10-29
          相关资源
          最近更新 更多