【问题标题】:How to handle add to list event?如何处理添加到列表事件?
【发布时间】:2010-11-20 23:00:00
【问题描述】:

我有一个这样的列表:

List<Controls> list = new List<Controls>

如何处理向此列表添加新位置?

当我这样做时:

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

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

myList.AddingEvent += HandleAddingEvent

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

【问题讨论】:

    标签: c# events list event-handling


    【解决方案1】:

    我相信您正在寻找的已经是 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);
    

    【讨论】:

    • ObservableCollection 看起来是完成此任务的正确方法。
    • ObservableCollection 如果包含 UI,则必须在 UI 线程上使用。 stackoverflow.com/a/2092036/623561
    • ObservableCollection 几乎是一个替代品,但当然它必须缺少像 RemoveRange() 这样的方法,这很困难。
    【解决方案2】:

    您可以从 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&lt;T&gt;事件将不会被触发

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

    【讨论】:

    • MattH 是正确的,那将是更好的解决方案。 BindingList 也是一个解决方案。 msdn.microsoft.com/en-us/library/ms132742.aspx
    • ObservableCollection&lt;T&gt; 在操作之后而不是之前引发其事件。但是BindingList&lt;T&gt;AddingNew 事件
    • ObservableCollection 或 BindingList 都不扩展 List。如果您使用它们,您将失去功能。
    • ObservableCollection 如果包含 UI,也必须在 UI 线程上使用。 stackoverflow.com/a/2092036/623561
    • if (null != OnAdd) 是什么?
    【解决方案3】:

    您需要的是一个类,该类具有针对集合中发生的任何类型的修改的事件。最好的课程是BindingList&lt;T&gt;。它包含每种突变类型的事件,然后您可以使用这些事件来修改您的事件列表。

    【讨论】:

    • 根据我的经验,AddingNew 事件并不总是被触发。 ListChanged 事件与 e.ListChangedType == ListChangedType.ItemAdded 更强大
    【解决方案4】:

    List&lt;T&gt; 无法做到这一点。但是,您可以使用ObservableCollection&lt;T&gt; 进行操作。见ObservableCollection&lt;T&gt; Class

    【讨论】:

    • 如果仍然需要派生,使用 List 或 Collection 有什么区别?集合更改时不会引发任何事件。
    • 好收获。我不知道我在想什么。有事件的是ObservableCollection&lt;T&gt;
    • 没错 :) 我们必须指出一些事情。 ObservableCollection 和 BindingList 在 .Net 4.0 中;因此,如果您在 .Net 3.5 中或必须派生 List 或 Collection 并添加自定义事件之前需要此专业。
    • @bahadirarslan - 这是不正确的,ObservableCollection 在 .NET 3.0 和 3.5 中。命名空间:System.Collections.ObjectModel 程序集:WindowsBase(在 WindowsBase.dll 中)
    【解决方案5】:

    要明确:如果您只需要观察标准功能,您应该使用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&lt;T&gt;

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

    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&lt;T&gt;,而不是List&lt;T&gt;ObservableCollection&lt;T&gt; 或其他任何东西。

    现在大惊喜:所有这些都实现了IList&lt;T&gt;

    IList<int> list1 = new ObservableCollection<int>();
    IList<int> list2 = new List<int>();
    IList<int> list3 = new int[10];
    IList<int> list4 = new MyList<int>();
    

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

    【讨论】:

      【解决方案6】:

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

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

      而不是

      list.Add(item);
      

      【讨论】:

        【解决方案7】:

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

        【讨论】:

        • 错了,正如其他答案所说,ObservableCollection 可以做到。
        【解决方案8】:

        为了支持 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&lt;&gt; 方法的访问...因此在您需要大量该功能的情况下可能没有用。

        【讨论】:

          【解决方案9】:

          无需添加事件,只需添加方法即可。

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

          【讨论】:

          • (new MyList() aus List).Add() 不会调用你的方法!你不覆盖你只隐藏基本方法。
          【解决方案10】:

          //列出覆盖类

          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()
                  {
          
                  }
            
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-05-13
            • 1970-01-01
            • 2013-10-15
            • 1970-01-01
            • 1970-01-01
            • 2014-08-03
            • 1970-01-01
            相关资源
            最近更新 更多