Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove an item from an ObservableCollection in a CollectionChanged event handler

I'm hoping to be able to reject some items after they have been added to an ObservableCollection. I am not able to subclass the ObservableCollection or use any sort of view, so I seem to be limited to using the one event handler defined (CollectionChanged) to perform a .Remove() on the prohibited items. It's fine if the items exist for the short period between the event being raised and then handled; the items should just not persist in the collection. Calling .Remove() within the CollectionChanged event handler doesn't appear to be allowed. At runtime .NET throws an InvalidOperationException:

"Cannot change ObservableCollection during a CollectionChanged event."

Personally I think .NET should allow me to. If I create an infinite loop, it's my own darn fault.

The code I would like to use would look like:

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

I'm not sure what options I have. Using a dispatcher doesn't seem to work. Triggering another event and placing the .Remove call in another handler is the only other option that comes to mind.

like image 214
ebpa Avatar asked Mar 16 '12 19:03

ebpa


2 Answers

Check out Common Mistakes using Observable Collection.

Having said that, if you still want to go this route - you can spin a new Thread

like image 179
Raj Ranjhan Avatar answered Sep 19 '22 17:09

Raj Ranjhan


I had tried using setting a flag to request collection add/remove changes and then when the System.Windows.Interop.ComponentDispatcher.ThreadIdle called my handler, doing my add or remove. That works. However, using a try-finally in the collection changed handler to unwire and then rewire that same collection changed event handler also bypassed the re-entrance issue:

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;
    }
}
like image 37
TonyM Avatar answered Sep 22 '22 17:09

TonyM