using System; using System.Collections; using System.Collections.Generic; using Chernobyl.Event; namespace Chernobyl.Collections.Generic.Event { /// /// An type that makes creating new /// types easier. /// public abstract class EventEnumerable : IEventEnumerable { /// /// An event that is raised right after items are added to this list. /// public event EventHandler ItemsAdded { add { ItemsNeeded = true; ItemsAddedHandler += value; } remove { ItemsAddedHandler -= value; if (ItemsAddedHandler == null) ItemsNeeded = false; } } /// /// An event that is raised right after items are removed from this list. /// public event EventHandler ItemsRemoved { add { ItemsNeeded = true; ItemsRemovedHandler += value; } remove { ItemsRemovedHandler -= value; if (ItemsRemovedHandler == null) ItemsNeeded = false; } } /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be /// used to iterate through the collection. /// IEnumerator IEnumerable.GetEnumerator() { ItemsNeeded = true; return EnumerableDecorated.GetEnumerator(); } /// /// Invoked when the items in this instance need to be ready for /// iteration or events. This method is invoked when /// is changed to true. /// protected virtual void ReadyItems() { } /// /// Invoked when the items in this instance no longer need to be ready /// for iteration or events. This method is invoked when /// is changed to false. /// protected virtual void UnreadyItems() { } /// /// Set to true when items in this type are needed, such as when the /// someone signs up to the or /// events or when someone /// iterates over this instance. Set to false when the items are no /// longer needed. If overriding, make sure to invoke the base class /// method in the override. /// protected bool ItemsNeeded { get { return _itemsNeeded; } set { if (_itemsNeeded != value) { _itemsNeeded = value; if (_itemsNeeded) ReadyItems(); else UnreadyItems(); } } } /// /// The backing property to . /// protected EventHandler ItemsAddedHandler { get; private set; } /// /// The backing property to . /// protected EventHandler ItemsRemovedHandler { get; private set; } /// /// The being decorated or extended /// with event capabilities. /// protected abstract IEnumerable EnumerableDecorated { get; } /// /// The backing field to . /// bool _itemsNeeded; } /// /// An type that makes creating new /// types easier. /// /// The type that is to be held within this /// . public abstract class EventEnumerable : EventEnumerable, IEventEnumerable { /// /// Initializes a new instance of the /// class. /// protected EventEnumerable() { // We need to make sure the base class' events are raised. Note that // we do not go through ItemsAdded/ItemsRemoved for this, since that // would cause ItemsNeeded to be set to true prematurely. ItemsAddedHandler += InvokeBaseItemsAdded; ItemsRemovedHandler += InvokeBaseItemsRemoved; } /// /// An event that is raised right after items are added to this list. /// public new event EventHandler> ItemsAdded { add { ItemsNeeded = true; ItemsAddedHandler += value; } remove { ItemsAddedHandler -= value; // Check if we no longer have outside subscribers // (InvokeBaseItemsAdded will always be subscribed). We no // longer need items if subscribers no longer listen. if (ItemsAddedHandler.GetInvocationList().Length == 1) ItemsNeeded = false; } } /// /// An event that is raised right after items are removed from this list. /// public new event EventHandler> ItemsRemoved { add { ItemsNeeded = true; ItemsRemovedHandler += value; } remove { ItemsRemovedHandler -= value; // Check if we no longer have outside subscribers // (InvokeBaseItemsRemoved will always be subscribed). We no // longer need items if subscribers no longer listen. if (ItemsRemovedHandler.GetInvocationList().Length == 1) ItemsNeeded = false; } } /// /// An instance that represents an empty . /// public static readonly IEventEnumerable Empty = new StaticEventEnumerable(); /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can /// be used to iterate through the collection. /// public IEnumerator GetEnumerator() { ItemsNeeded = true; return GenericEnumerableDecorated.GetEnumerator(); } /// /// Raises the of the base /// class after checking if it is null. /// /// The sender of the event. /// The event's arguments. protected void InvokeBaseItemsAdded(object sender, ItemsEventArgs e) { if (base.ItemsAddedHandler != null) base.ItemsAddedHandler(sender, e); } /// /// Raises the of the base /// class after checking if it is null. /// /// The sender of the event. /// The event's arguments. protected void InvokeBaseItemsRemoved(object sender, ItemsEventArgs e) { if (base.ItemsRemovedHandler != null) base.ItemsRemovedHandler(sender, e); } /// /// The backing property to . /// protected new EventHandler> ItemsAddedHandler { get; set; } /// /// The backing property to . /// protected new EventHandler> ItemsRemovedHandler { get; set; } /// /// The being decorated or extended /// with event capabilities. /// protected abstract IEnumerable GenericEnumerableDecorated { get; } /// /// The being decorated or extended /// with event capabilities. /// protected override IEnumerable EnumerableDecorated { get { return GenericEnumerableDecorated; } } } }