I have a list like this:
List<Controls> list = new List<Controls>
How to handle adding new position to this list?
When I do:
myObject.myList.Add(new Control());
I would like to do something like this in my object:
myList.AddingEvent += HandleAddingEvent
And then in my HandleAddingEvent
delegate handling adding position to this list. How should I handle adding new position event? How can I make this event available?
You could inherit from List and add your own handler, something like
using System;
using System.Collections.Generic;
namespace test
{
class Program
{
class MyList<T> : List<T>
{
public event EventHandler OnAdd;
public new void Add(T item) // "new" to avoid compiler-warnings, because we're hiding a method from base-class
{
if (null != OnAdd)
{
OnAdd(this, null);
}
base.Add(item);
}
}
static void Main(string[] args)
{
MyList<int> l = new MyList<int>();
l.OnAdd += new EventHandler(l_OnAdd);
l.Add(1);
}
static void l_OnAdd(object sender, EventArgs e)
{
Console.WriteLine("Element added...");
}
}
}
Warning
Be aware that you have to re-implement all methods which add objects to your list.
AddRange()
will not fire this event, in this implementation.We did not overload the method. We hid the original one. If you
Add()
an object while this class is boxed inList<T>
, the event will not be fired!
MyList<int> l = new MyList<int>();
l.OnAdd += new EventHandler(l_OnAdd);
l.Add(1); // Will work
List<int> baseList = l;
baseList.Add(2); // Will NOT work!!!
I believe What you're looking for is already part of the API in the ObservableCollection(T) class. Example:
ObservableCollection<int> myList = new ObservableCollection<int>();
myList.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
delegate(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
MessageBox.Show("Added value");
}
}
);
myList.Add(1);
What you need is a class that has events for any type of modification that occurs in the collection. The best class for this is BindingList<T>
. It has events for every type of mutation which you can then use to modify your event list.
You can't do this with List<T>
. However, you can do it with ObservableCollection<T>
. See ObservableCollection<T>
Class.
One simple solution is to introduce an Add method for the list in your project and handle the event there. It doesn't answer the need for an event handler but can be useful for some small projects.
AddToList(item) // or
AddTo(list,item)
////////////////////////
void AddTo(list,item)
{
list.Add(item);
// event handling
}
instead of
list.Add(item);
To be clear: If you only need to observe the standard-functionalities you should use ObservableCollection(T) or other existing classes. Never rebuild something you already got.
..But.. If you need special events and have to go deeper, you should not derive from List! If you derive from List you can not overloead Add()
in order to see every add.
Example:
public class MyList<T> : List<T>
{
public void Add(T item) // Will show us compiler-warning, because we hide the base-mothod which still is accessible!
{
throw new Exception();
}
}
public static void Main(string[] args)
{
MyList<int> myList = new MyList<int>(); // Create a List which throws exception when calling "Add()"
List<int> list = myList; // implicit Cast to Base-class, but still the same object
list.Add(1); // Will NOT throw the Exception!
myList.Add(1); // Will throw the Exception!
}
It's not allowed to override Add()
, because you could mees up the functionalities of the base class (Liskov substitution principle).
But as always we need to make it work. But if you want to build your own list, you should to it by implementing the an interface: IList<T>
.
Example which implements a before- and after-add event:
public class MyList<T> : IList<T>
{
private List<T> _list = new List<T>();
public event EventHandler BeforeAdd;
public event EventHandler AfterAdd;
public void Add(T item)
{
// Here we can do what ever we want, buffering multiple events etc..
BeforeAdd?.Invoke(this, null);
_list.Add(item);
AfterAdd?.Invoke(this, null);
}
#region Forwarding to List<T>
public T this[int index] { get => _list[index]; set => _list[index] = value; }
public int Count => _list.Count;
public bool IsReadOnly => false;
public void Clear() => _list.Clear();
public bool Contains(T item) => _list.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
public int IndexOf(T item) => _list.IndexOf(item);
public void Insert(int index, T item) => _list.Insert(index, item);
public bool Remove(T item) => _list.Remove(item);
public void RemoveAt(int index) => _list.RemoveAt(index);
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
#endregion
}
Now we've got all methods we want and didn't have to implement much. The main change in our code is, that our variables will be IList<T>
instead of List<T>
, ObservableCollection<T>
or what ever.
And now the big wow: All of those implement IList<T>
:
IList<int> list1 = new ObservableCollection<int>();
IList<int> list2 = new List<int>();
IList<int> list3 = new int[10];
IList<int> list4 = new MyList<int>();
Which brings us to the next point: Use Interfaces instead of classes. Your code should never depend on implementation-details!
You cannot do this with standard collections out of the box - they just don't support change notifications. You could build your own class by inheriting or aggregating a existing collection type or you could use BindingList<T>
that implements IBindingList
and supports change notifications via the ListChanged
event.
To piggy-back off Ahmad's use of Extension Methods, you can create your own class where the list is private with a public get
method and a public add
method.
public class MyList
{
private List<SomeClass> PrivateSomeClassList;
public List<SomeClass> SomeClassList
{
get
{
return PrivateSomeClassList;
}
}
public void Add(SomeClass obj)
{
// do whatever you want
PrivateSomeClassList.Add(obj);
}
}
However, this class only provides access to List<>
methods that you manually expose...hence may not be useful in cases where you need a lot of that functionality.
No need for adding an event just add the method.
public class mylist:List<string>
{
public void Add(string p)
{
// Do cool stuff here
base.Add(p);
}
}
来源:https://stackoverflow.com/questions/1299920/how-to-handle-add-to-list-event