我有一个这样的列表:
List<Controls> list = new List<Controls>
如何处理在此列表中添加新位置?
当我做:
myObject.myList.Add(new Control());
我想在我的对象中做这样的事情:
myList.AddingEvent += HandleAddingEvent
然后在我的HandleAddingEvent
代表处理中添加位置到此列表。我该如何处理添加新的位置事件?我怎样才能举办这个活动?
您可以从List继承并添加自己的处理程序,例如
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...");
}
}
}
AddRange()
不会解雇此事件。Add()
中装入这个类时List<T>
是一个对象,那么该事件不会被触发!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!!!
我相信您所寻找的内容已经成为ObservableCollection(T)课程中API的一部分。例:
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);
您需要的是一个类,它包含集合中发生的任何类型修改的事件。最好的类是BindingList<T>
。它具有针对每种类型的突变的事件,您可以使用它们来修改事件列表。
你不能用List<T>
做到这一点。但是,你可以用ObservableCollection<T>
来做。见ObservableCollection<T>
Class。
一个简单的解决方案是为项目中的列表引入Add方法并在那里处理事件。它不能满足对事件处理程序的需求,但对某些小项目非常有用。
AddToList(item) // or
AddTo(list,item)
////////////////////////
void AddTo(list,item)
{
list.Add(item);
// event handling
}
代替
list.Add(item);
您无法使用开箱即用的标准集合执行此操作 - 它们只是不支持更改通知。您可以通过继承或聚合现有集合类型来构建自己的类,也可以使用实现BindingList<T>
的IBindingList
并通过ListChanged
事件支持更改通知。
为了挽回艾哈迈德对扩展方法的使用,您可以使用公共get
方法和公共add
方法创建自己的类,其中列表是私有的。
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);
}
}
但是,此类仅提供对手动公开的List<>
方法的访问...因此在需要大量功能的情况下可能没用。
无需添加事件只需添加方法即可。
public class mylist:List<string>
{
public void Add(string p)
{
// Do cool stuff here
base.Add(p);
}
}
需要明确的是:如果您只需要遵守标准功能,则应使用ObservableCollection(T)或其他现有类。永远不要重建你已经拥有的东西。
..但..如果你需要特别的活动而且必须更深入,你不应该从List中派生出来!如果你从List派生,你不能覆盖Add()
以便看到每一个添加。
例:
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!
}
它不允许覆盖Add()
,因为你可以了解基类的功能(Liskov substitution principle)。
但一如既往,我们需要让它发挥作用。但是如果你想建立自己的列表,你应该通过实现一个接口来实现:IList<T>
。
实现before-after-add事件的示例:
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
}
现在我们已经拥有了我们想要的所有方法,并且不必实施太多。我们的代码的主要变化是,我们的变量将是IList<T>
而不是List<T>
,ObservableCollection<T>
或者什么。
现在大哇:所有这些都实现了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>();
这将我们带到下一点:使用接口而不是类。您的代码永远不应该依赖于实现细节!