How can I fire event before item is added to collection in C#?
I would like to do some processing before an item is added to a BindingList. I see there is an ListChanged event but this is fired after the item is added. The AddingNew event is only fired when the AddNew method (not the Add method) is called. Has anyone done something like this before?
UPDATE:
I have created the following classes and when the Add method is called on the IList, my new Add method gets triggered. So, do I have the casting problem that I've read in other places? If I removed the ISpecialCollection interface from the collection, my Add method doesn't get called. Can someone explain why it's acting differently? Do I hav开发者_运维知识库e the casting problem if I use the ISpecialCollection< interface?
public interface ISpecialCollection<T> : IList<T>
{
}
public class SpecialCollection<T> : BindingList<T>, ISpecialCollection<T>
{
public new void Add (T item)
{
base.Add(item);
}
}
class Program
{
static void Main(string[] args)
{
IList<ItemType> list = new SpecialCollection<ItemType>();
list.Add(new ItemType());
}
}
You should override the protected BindingList.InsertItem
method (MSDN). Add
, Insert
and such all call this to do the actual adding adding and raise appropriate events. Raise your event, and then call base.InsertItem
to do the rest.
The most straightforward route is to subclass the Collection<T>
class. This is the collection class in the BCL which is designed to be subclassed and have it's behavior overriden. Subclassing other types like BindingList<T>
or List<T>
will just cause you pain.
Once you subclass Collection<T>
, you can override Add and create your own event to listen to.
I have done something similar as I needed to capture the ItemAdding and ItemAdded event
The magic bit is the new keyword that will override the inherited class' method
// class that inherits generic List and hides the add item
public class ListWithEvents<T> : List<T>
{
public event EventHandler ItemAdding;
public event EventHandler ItemAdded;
public new void Add(T item)
{
if (ItemAdding != null)
ItemAdding(item, EventArgs.Empty);
base.Add(item);
if (ItemAdded != null)
ItemAdded(item, EventArgs.Empty);
}
}
// Using the class
protected override void OnLoad(EventArgs e)
{
ListWithEvents<int> lstI = new ListWithEvents<int>();
lstI.ItemAdded += new EventHandler(lstI_ItemAdded);
lstI.ItemAdding += new EventHandler(lstI_ItemAdding);
}
void lstI_ItemAdding(object sender, EventArgs e)
{
throw new NotImplementedException();
}
void lstI_ItemAdded(object sender, EventArgs e)
{
throw new NotImplementedException();
}
Something like:
public class PreProcessBindingList<T> : Collection<T>
{
public AddingNewEventHandler AddingNew;
public override void Add(T item)
{
PreProcess(item);
base.Add(item);
AddingNewEventHandler addingNew = this.AddingNew;
if (addingNew != null)
{
addingNew(this, new AddingNewEventArgs(item));
}
}
}
The right way to do this is to extend Collection<T>
and override the InsertItem
method. You can raise your event there before calling base.InsertItem.
Use the C5 collections library. C5
's collections are already set up to be able to fire events on several operations, including clearing the collection, adding items, removing items, inserting items, and general collection changes.
As well, the C5 library collections implement the System.Collection.Generic
ICollection
and IList
interfaces where appropriate, and so can be dropped in as the implementation even if a library is only expecting, e.g. an SCG.ICollection
.
EDIT: I forgot to mention a portion of your requirements; many of those events I mentioned above are cancelable events, and are fired before the action has affected the underlying collection, allowing you to make changes or reject additions, removals, etc.
Use ObservableCollection. It has events that monitor when the collection is changing. I believe that it is primarily used for WPF, but I have used it with ASP.NET projects also.
精彩评论