Skip to content

Using event raising collections

Craig Fowler edited this page Dec 2, 2016 · 3 revisions

There are presently three available implementations of event-raising collections. You are also welcome to write/contribute your own.

  • CSF.Collections.EventRaising.EventRaisingCollection<T> - implements ICollection<T>
  • CSF.Collections.EventRaising.EventRaisingList<T> - implements IList<T>
  • CSF.Collections.EventRaising.EventRaisingSet<T> - implements ISet<T>

These types may be instantiated via their public constructors. Each of these takes an instance of a collection based upon the same interface as a constructor parameter. This instance is the source collection. The source collection is your "real" collection instance that the event-raising instance will wrap and control. If the event-raising collection is modified then the source collection is modified, and vice-versa. However, only modifications which are made via the event-raising wrapper will trigger the events.

In most cases, after passing in the source collection you will no longer need to hold a reference to it. In other cases you may wish to hold a reference as a private field. The event-raising collection is the one which you will want to expose in your API (typically as its relevant collection interface).

Example

using CSF.Collections.EventRaising;
using System.Collections.Generic;

public class Parent()
{
  private IList<Child> _sourceChildren;
  private EventRaisingList<Child> _children;

  public Parent()
  {
    _sourceChildren = new List<Child>();
    _children = new EventRaisingList<Child>(_sourceChildren);

    // Set up bindings to the event-raising list's events here
  }

  public IList<Child> Children { get { return _children; } }
}

Notice that in this example the Children property is get-only. This is important when using event-raising collections; if we allowed it to be settable then we would be permitting the replacement of our event-raising collection with a completely different instance. That new instance may or may not be an event-raising collection at all and even if it is then we may or may not have subscribed to its events. For scenarios where you wish to permit this, and to preserve the event subscriptions, you should consider an event-raising collection wrapper.

Subscribing to events

There are four events available to every event-raising collection instance:

  • BeforeAdd
  • AfterAdd
  • BeforeRemove
  • AfterRemove

These trigger before and after the addition or removal of each individual item to/from the collection, respectively. The events have the signature EventHandler<BeforeModifyEventArgs<T>> and EventHandler<AfterModifyEventArgs<T>> depending upon whether the event represents a before or after action.

These event args types are very similar - they both expose the Item being added/removed and also the Collection itself. The before event args type additionally exposes a read-only boolean property IsCancelled and a method Cancel. The extra functionality available before the collection is modified allows the cancelling of the modification. Whilst this offers a powerful way to filter the addition/removal to/from a collection, please consider very carefully whether it is appropriate before making use of it.