I have something here that is really catching me off guard.
I have an ObservableCollection of T that is filled with items. I also have an event handler attached to t
Another option is to replace the Reset event with a single Remove event that has all the cleared items in its OldItems property as follows:
public class ObservableCollectionNoReset : ObservableCollection
{
protected override void ClearItems()
{
List removed = new List(this);
base.ClearItems();
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action != NotifyCollectionChangedAction.Reset)
base.OnCollectionChanged(e);
}
// Constructors omitted
...
}
Advantages:
No need to subscribe to an additional event (as required by accepted answer)
Doesn't generate an event for each object removed (some other proposed solutions result in multiple Removed events).
Subscriber only needs to check NewItems & OldItems on any event to add/remove event handlers as required.
Disadvantages:
No Reset event
Small (?) overhead creating copy of list.
???
EDIT 2012-02-23
Unfortunately, when bound to WPF list based controls, Clearing a ObservableCollectionNoReset collection with multiple elements will result in an exception "Range actions not supported". To be used with controls with this limitation, I changed the ObservableCollectionNoReset class to:
public class ObservableCollectionNoReset : ObservableCollection
{
// Some CollectionChanged listeners don't support range actions.
public Boolean RangeActionsSupported { get; set; }
protected override void ClearItems()
{
if (RangeActionsSupported)
{
List removed = new List(this);
base.ClearItems();
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
}
else
{
while (Count > 0 )
base.RemoveAt(Count - 1);
}
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action != NotifyCollectionChangedAction.Reset)
base.OnCollectionChanged(e);
}
public ObservableCollectionNoReset(Boolean rangeActionsSupported = false)
{
RangeActionsSupported = rangeActionsSupported;
}
// Additional constructors omitted.
}
This isn't as efficient when RangeActionsSupported is false (the default) because one Remove notification is generated per object in the collection