tags:

views:

76

answers:

4

I have a collection

private ObservableCollection<Contact> _contacts;

In the constructor of my class I create it

_contacts = new ObservableCollection<Contact>();

I have methods to add and remove items from my collection. I want to track changes to the entities in my collection which implement the IPropertyChanged interface so I subscribe to their PropertyChanged event.

public void AddContact(Contact contact)
{
    ((INotifyPropertyChanged)contact).PropertyChanged += new PropertyChangedEventHandler(Contact_PropertyChanged);
    _contacts.Add(contact);
}

public void AddContact(int index, Contact contact)
{
    ((INotifyPropertyChanged)contact).PropertyChanged += new PropertyChangedEventHandler(Contact_PropertyChanged);
    _contacts.Insert(index, contact);
}

When I remove an entity from the collection, I unsubscribe from the PropertyChanged event. I am told this is to allow the entity to be garbage collected and not create memory issues.

public void RemoveContact(Contact contact)
{
    ((INotifyPropertyChanged)contact).PropertyChanged -= Contact_PropertyChanged;
    _contacts.Remove(contact);
}

So, I hope this is all good. Now, I need to clear the collection in one of my methods. My first thought would be to call _contacts.Clear(). Then I got to wondering if this releases those event subscriptions? Would I need to create my own clear method? Something like this:

public void ClearContacts()
{
    foreach(Contact contact in _contacts)
    {
        this.RemoveContact(contact);
    }
}

I am hoping one of the .NET C# experts here could clear this up for me or tell me what I am doing wrong.

+2  A: 

Clear() does not remove event handlers. (Note also, that calling Clear() does not trip a CollectionChanged event as Add() and Remove() do.)

Scott J
RE: Clear() not tipping a PropertyChanged.Are you sure about that? Looking at the code for ObservableCollection<T> with Reflector shows that it is calling OnPropertyChanged for both "Count" and "Item[]", same as in Add/Remove, inside the ClearItems() method, which Clear() calls.
Michael Morton
D'oh! I meant CollectionChanged event. Sorry.
Scott J
A: 

Clear() will not release those event subscriptions.

It would probably be best to your own Clear method that iterates over the collection removing the event handlers and then calls Clear() on the collection.

The reason to do this, instead of calling Remove() for each item is that, internally, Remove() iterates over the collection in order to find the index of the item you are removing and performance could suffer if there are a large number of items in the collection.

Michael Morton
+1  A: 

You could have a handler for the CollectionChanged event of the ObservableCollection, this will work well for unhooking the item event handlers when they are removed and that does get fired when you do a Clear, but the problem is the e.OldItems collection will be null upon the Clear().

So to agree with @Michael, to do what you want you will have to implement your own Clear method, maybe as an extension method:

public static class Extensions
{
    public static void ClearEx(this ObservableCollection<object> collection)
    {
        //custom clear logic...   
    }
}

in your clear function you could iterate over the items and clear the event handlers before calling the regular Clear() function.

slugster
A: 

Here's the code from Reflector:

protected override void ClearItems()
{
    this.CheckReentrancy();
    base.ClearItems();
    this.OnPropertyChanged("Count");
    this.OnPropertyChanged("Item[]");
    this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

It checks to make sure that one of the event handlers hasn't called it in a loop, calls the base Collection's Clear function, notifies the subscribers that properties have changed, and finally notifies subscribers that the collection has changed.

At no point does it clear either of the event handlers.

Gabe