List<T> firing Event on Change

You seldom create a new instance of a collection class in a class. Instantiate it once and clear it instead of creating a new list. (and use the ObservableCollection since it already has the INotifyCollectionChanged interface inherited)

private readonly ObservableCollection<T> list;
public ctor() {
    list = new ObservableCollection<T>();
    list.CollectionChanged += listChanged;
}

public ObservableCollection<T> List { get { return list; } }

public void Clear() { list.Clear(); }

private void listChanged(object sender, NotifyCollectionChangedEventArgs args) {
   // list changed
}

This way you only have to hook up events once, and can "reset it" by calling the clear method instead of checking for null or equality to the former list in the set accessor for the property.


With the changes in C#6 you can assign a get property from a constructor without the backing field (the backing field is implicit)

So the code above can be simplified to

public ctor() {
    List = new ObservableCollection<T>();
    List.CollectionChanged += OnListChanged;
}

public ObservableCollection<T> List { get; }

public void Clear()
{
    List.Clear();
}

private void OnListChanged(object sender, NotifyCollectionChangedEventArgs args)
{
   // react to list changed
}

ObservableCollection is a List with a CollectionChanged event

ObservableCollection.CollectionChanged Event

For how to wire up the event handler see answer from Patrick. +1

Not sure what you are looking for but I use this for a collection with one event that fires on add, remove, and change.

public class ObservableCollection<T>: INotifyPropertyChanged
{
    private BindingList<T> ts = new BindingList<T>();

    public event PropertyChangedEventHandler PropertyChanged;

    // This method is called by the Set accessor of each property. 
    // The CallerMemberName attribute that is applied to the optional propertyName 
    // parameter causes the property name of the caller to be substituted as an argument. 
    private void NotifyPropertyChanged( String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public BindingList<T> Ts
    {
        get { return ts; }
        set
        {
            if (value != ts)
            {
                Ts = value;
                if (Ts != null)
                {
                    ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
                    {
                        OnListChanged(this);
                    };
                }
                NotifyPropertyChanged("Ts");
            }
        }
    }

    private static void OnListChanged(ObservableCollection<T> vm)
    {
        // this will fire on add, remove, and change
        // if want to prevent an insert this in not the right spot for that 
        // the OPs use of word prevent is not clear 
        // -1 don't be a hater
        vm.NotifyPropertyChanged("Ts");
    }

    public ObservableCollection()
    {
        ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
        {
            OnListChanged(this);
        };
    }
}

If you do not want to or can not convert to an Observable Collection, try this:

public class EventList<T> : IList<T> /* NOTE: Changed your List<T> to IList<T> */
{
  private List<T> list; // initialize this in your constructor.
  public event ListChangedEventDelegate ListChanged;
  public delegate void ListChangedEventDelegate();

  private void notify()
  {
      if (ListChanged != null
          && ListChanged.GetInvocationList().Any())
      {
        ListChanged();
      }
  }

  public new void Add(T item)
  {
      list.Add(item);
      notify();
  }

  public List<T> Items {
    get { return list; } 
    set {
      list = value; 
      notify();
    }
  }
  ...
}

Now, for your property, you should be able to reduce your code to this:

public EventList List
{
  get { return m_List.Items; }
  set
  {
      //m_List.ListChanged -= List_ListChanged;

      m_List.Items = value;

      //m_List.ListChanged += List_ListChanged;
      //List_ListChanged();
  }
}

Why? Setting anything in the EventList.Items will call your private notify() routine.

Tags:

C#

.Net