如何处理添加到列表事件?

时间:2009-08-19 13:28:07

标签: c# events list event-handling

我有一个这样的清单:

List<Controls> list = new List<Controls>

如何处理在此列表中添加新职位?

当我这样做时:

myObject.myList.Add(new Control());

我想在我的对象中做这样的事情:

myList.AddingEvent += HandleAddingEvent

然后在我的HandleAddingEvent委托处理中将位置添加到此列表中。我该如何处理添加新的位置事件?我怎样才能举办这个活动?

10 个答案:

答案 0 :(得分:63)

我相信您所寻找的内容已经成为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);

答案 1 :(得分:39)

您可以从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...");
        }
    }
}

警告

  1. 请注意,您必须重新实现将对象添加到列表中的所有方法。在此实施中,AddRange()不会触发此事件。

  2. 我们 没有超载 该方法。我们藏了原来的。如果您在Add()中装入此类时List<T>某个对象, 事件将不会被触发

  3. 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!!!
    

答案 2 :(得分:26)

您需要的是一个类,它包含集合中发生的任何类型修改的事件。最好的课程是BindingList<T>。它具有针对每种类型突变的事件,您可以使用它们来修改事件列表。

答案 3 :(得分:16)

您无法使用List<T>执行此操作。但是,您可以使用ObservableCollection<T>执行此操作。请参阅ObservableCollection<T> Class

答案 4 :(得分:2)

一个简单的解决方案是为项目中的列表引入Add方法并在那里处理事件。它没有满足对事件处理程序的需求,但对某些小项目非常有用。

AddToList(item) // or
AddTo(list,item)
////////////////////////

void AddTo(list,item)
{
    list.Add(item);
    // event handling
}

而不是

list.Add(item);

答案 5 :(得分:1)

您无法使用开箱即用的标准集合执行此操作 - 它们只是不支持更改通知。您可以通过继承或聚合现有集合类型来构建自己的类,也可以使用实现BindingList<T>IBindingList并通过ListChanged事件支持更改通知。

答案 6 :(得分:1)

要捎带Ahmad使用扩展方法,您可以创建自己的类,其中列表是私有的,具有公共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<>方法的访问权限......因此在您需要大量功能的情况下可能没用。

答案 7 :(得分:1)

无需添加事件只需添加方法。

public class mylist:List<string>
{
  public void Add(string p)
  {
     // Do cool stuff here
     base.Add(p);
  }
}

答案 8 :(得分:0)

要明确:如果只需要遵守标准功能,则应该使用ObservableCollection(T)或其他现有的类。永远不要重建您已经拥有的东西。

..但是..如果您需要特殊事件并且需要更深入地研究,则不应从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>

实现添加前和添加后事件的示例:

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>();

这将我们带到下一步:使用接口而不是类。您的代码不应依赖于实现细节!

答案 9 :(得分:0)

//列表替代程序类

public class ListWithEvents<T> : List<T>
    {

        public delegate void AfterChangeHandler();

        public AfterChangeHandler OnChangeEvent;        

        public Boolean HasAddedItems = false;
        public Boolean HasRemovedItems = false;

        public bool HasChanges
        {
            get => HasAddedItems || HasRemovedItems;
            set
            {                
                HasAddedItems = value;
                HasRemovedItems = value; 
            }
        }

        public new void Add(T item)
        {
            base.Add(item);
            HasAddedItems = true;
            if(OnChangeEvent != null) OnChangeEvent();
            OnChange();
        }

        public new void AddRange(IEnumerable<T> collection)
        {
            base.AddRange(collection);
            HasAddedItems = true;
            if (OnChangeEvent != null) OnChangeEvent();
            OnChange();
        }

        public new void Insert(int index,T item)
        {
            base.Insert(index, item);
            HasAddedItems = true;
            if (OnChangeEvent != null) OnChangeEvent();
            OnChange();
        }

        public new void InsertRange(int index, IEnumerable<T> collection)
        {
            base.InsertRange(index, collection);
            HasAddedItems = true;
            if (OnChangeEvent != null) OnChangeEvent();
            OnChange();
        }


        public new void Remove(T item)
        {
            base.Remove(item);
            HasRemovedItems = true;
            if (OnChangeEvent != null) OnChangeEvent();
            OnChange();
        }

        public new void RemoveAt(int index)
        {
            HasRemovedItems = true;
            if (OnChangeEvent != null) OnChangeEvent();
            OnChange();
        }

        public new void RemoveRange(int index,int count)
        {
            HasRemovedItems = true;
            if (OnChangeEvent != null) OnChangeEvent();
            OnChange();
        }

        public new void Clear()
        {
            base.Clear();
            HasRemovedItems = true;
            if (OnChangeEvent != null) OnChangeEvent();
            OnChange();
        }

        public virtual void OnChange()
        {

        }
  
    }