Подтвердить что ты не робот

Как обрабатывать событие добавления в список?

У меня есть список вроде этого:

List<Controls> list = new List<Controls>

Как обрабатывать добавление новой позиции в этот список?

Когда я это сделаю:

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

Я хотел бы сделать что-то вроде этого в моем объекте:

myList.AddingEvent += HandleAddingEvent

И затем в моем делетете HandleAddingEvent, который добавляет позицию в этот список. Как я должен обрабатывать добавление нового события позиции? Как я могу сделать это событие доступным?

4b9b3361

Ответ 1

Вы можете наследовать от 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() не будет AddRange() это событие в этой реализации.

  2. Мы не перегружали метод. Мы спрятали оригинал. Если вы Add() объект, пока этот класс помещен в List<T> в 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!!!

Ответ 2

Я считаю, что то, что вы ищете, уже является частью API в классе ObservableCollection (T). Пример:

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

Ответ 3

Что вам нужно - это класс, который имеет события для любого типа модификации, которое происходит в коллекции. Лучший класс для этого - BindingList<T>. Он имеет события для каждого типа мутации, которые затем можно использовать для изменения списка событий.

Ответ 4

Вы не можете сделать это с помощью List<T>. Однако вы можете сделать это с помощью ObservableCollection<T>. См. ObservableCollection<T> Класс.

Ответ 5

Одно простое решение - ввести метод Add для списка в вашем проекте и обработать событие там. Он не отвечает на необходимость обработчика событий, но может быть полезен для небольших проектов.

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

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

вместо

list.Add(item);

Ответ 6

Вы не можете делать это со стандартными коллекциями из коробки - они просто не поддерживают уведомления об изменениях. Вы можете создать собственный класс, наследуя или агрегируя существующий тип коллекции, или вы можете использовать BindingList<T>, который реализует IBindingList и поддерживает уведомления об изменениях через событие ListChanged.

Ответ 7

Чтобы избавиться от использования методов расширения, 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<>, которые вы вручную раскрываете... следовательно, может оказаться нецелесообразным в тех случаях, когда вам нужна большая часть этой функциональности.

Ответ 8

Нет необходимости добавлять событие, просто добавьте метод.

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

Ответ 9

Для ясности: если вам нужно только соблюдать стандартные функциональные возможности, вы должны использовать 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(), потому что вы могли использовать функциональные возможности базового класса (принцип подстановки Лискова).

Но, как всегда, мы должны заставить это работать. Но если вы хотите создать свой собственный список, вам следует создать интерфейс: IList<T>.

Пример, который реализует событие before- и после добавления:

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

Что подводит нас к следующему пункту: используйте интерфейсы вместо классов. Ваш код никогда не должен зависеть от деталей реализации!