48 Stimmen

Wie kann man das Ereignis "Zur Liste hinzufügen" behandeln?

Ich habe eine Liste wie diese:

List<Controls> list = new List<Controls>

Wie wird das Hinzufügen neuer Positionen zu dieser Liste gehandhabt?

Wenn ich es tue:

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

Ich würde gerne etwas Ähnliches in meinem Objekt machen:

myList.AddingEvent += HandleAddingEvent

Und dann in meinem HandleAddingEvent Delegieren Sie das Hinzufügen von Positionen zu dieser Liste. Wie sollte ich das Ereignis "Hinzufügen einer neuen Position" behandeln? Wie kann ich dieses Ereignis verfügbar machen?

83voto

MattH Punkte 3967

Ich glaube, was Sie suchen, ist bereits Teil der API in der ObservableCollection(T) Klasse. Beispiel:

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

2 Stimmen

ObservableCollection<T> scheint der richtige Weg zu sein, um dies zu erreichen.

0 Stimmen

ObservableCollection muss im UI-Thread verwendet werden, wenn sie UI enthält. stackoverflow.com/a/2092036/623561

0 Stimmen

ObservableCollection<> ist fast ein vollwertiger Ersatz, aber natürlich mussten Methoden wie RemoveRange() fehlen, um nicht zu schwierig zu sein.

49voto

Paolo Tedesco Punkte 52228

Sie könnten von List erben und einen eigenen Handler hinzufügen, etwa wie

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...");
        }
    }
}

Warnung

  1. Beachten Sie, dass Sie alle Methoden, die Ihrer Liste Objekte hinzufügen, neu implementieren müssen. AddRange() wird dieses Ereignis in dieser Implementierung nicht ausgelöst.

  2. Wir nicht überlastet die Methode. Wir haben die ursprüngliche Methode versteckt. Wenn Sie Add() ein Objekt, während diese Klasse eingekreist ist List<T> die das Ereignis wird nicht ausgelöst !

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

5 Stimmen

MattH hat recht, das wäre die bessere Lösung. BindingList<T> würde auch eine Lösung sein. msdn.microsoft.com/de-us/library/ms132742.aspx

4 Stimmen

ObservableCollection<T> hebt seine Ereignisse nach der Aktion, nicht vorher. Aber die BindingList<T> hat die AddingNew Veranstaltung

1 Stimmen

Weder ObservableCollection noch BindingList erweitern List. Wenn Sie sie verwenden, verlieren Sie Funktionalität.

28voto

JaredPar Punkte 699699

Was Sie brauchen, ist eine Klasse, die Ereignisse für jede Art von Änderung, die in der Sammlung auftritt, hat. Die beste Klasse für diesen Zweck ist BindingList<T> . Sie enthält Ereignisse für jede Art von Mutation, die Sie dann zur Änderung Ihrer Ereignisliste verwenden können.

2 Stimmen

Meiner Erfahrung nach AddingNew Ereignis wurde nicht immer ausgelöst. ListChanged Veranstaltung mit e.ListChangedType == ListChangedType.ItemAdded war robuster

18voto

John Saunders Punkte 159011

Sie können dies nicht tun mit List<T> . Sie können es aber auch mit ObservableCollection<T> . Siehe ObservableCollection<T> Klasse .

0 Stimmen

Was ist der Unterschied zwischen Liste und Sammlung, wenn man sie trotzdem ableiten muss? Es gibt keine Ereignisse, die ausgelöst werden, wenn sich die Sammlung ändert.

0 Stimmen

Ein guter Fang. Ich weiß nicht, was ich mir dabei gedacht habe. Es ist ObservableCollection<T> die die Ereignisse enthält.

0 Stimmen

Das ist richtig :) wir mussten auf etwas hinweisen. ObservableCollection<T> und BindingList<T> sind in .Net 4.0; wenn Sie also diese Spezialität in .Net 3.5 oder früher benötigen, müssen Sie List oder Collection ableiten und benutzerdefinierte Ereignisse hinzufügen.

7voto

kara Punkte 3020

Um es klar zu sagen: Wenn Sie nur die Standardfunktionalitäten beachten müssen, sollten Sie die ObservableCollection(T) oder andere bestehende Klassen. Bauen Sie niemals etwas nach, was Sie bereits haben.

Aber: Wenn Sie besondere Ereignisse brauchen und tiefer gehen müssen, sollten Sie nicht von List ableiten! Wenn Sie von List ableiten, können Sie nicht überladen Add() um jede Anzeige zu sehen.

Ejemplo:

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

Es darf nicht überschrieben werden Add() , da man die Funktionen der Basisklasse ( Liskov-Substitutionsprinzip ).

Aber wie immer müssen wir dafür sorgen, dass es funktioniert. Wenn Sie jedoch Ihre eigene Liste erstellen möchten, sollten Sie dies durch die Implementierung der Schnittstelle tun: IList<T> .

Beispiel, das ein Before- und After-Add-Ereignis implementiert:

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
}

Jetzt haben wir alle Methoden, die wir wollen, und mussten nicht viel implementieren. Die wichtigste Änderung in unserem Code ist, dass unsere Variablen nun IList<T> 代わりに List<T> , ObservableCollection<T> oder was auch immer.

Und jetzt das große Aha-Erlebnis: All diese Geräte 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>();

Das bringt uns zum nächsten Punkt: Verwenden Sie Schnittstellen anstelle von Klassen. Ihr Code sollte niemals von Implementierungsdetails abhängen!

1 Stimmen

Warum ist diese Antwort nicht als Lösung markiert? Ich würde lieber dies tun, als die Implementierung von List tbh...

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X