views:

345

answers:

7

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 have 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());
  }
}
+1  A: 

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));
            }
        }
    }
Ian
I know but I've heard this could cause problems if someone casts it as an List and calls Add. In that case, the new Add method would not be called.
bsh152s
Yeah, you'd want to override it, not hide it.
Jeff Sternal
You can't override the BindingList.Add method. The best you can do is hide it.
Ian
See the edit for a way to solve the casting problem.
Ian
D'oh of course you can't. What Ian said. :)
Jeff Sternal
+1  A: 

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();
    }
Tim Jarvis
+1  A: 

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.

JaredPar
+3  A: 

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.

dbkk
A: 

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.

Jamie Ide
A: 

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.

Marcus Griep
A: 

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.

crazytmack
...ObservableCollection(Of T)...in the System.Collections.ObjectModel namespace in the WindowsBase.dll.
crazytmack