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; }
}
}
}