How to Handle Add to List Event

How to handle add to list event?

You could inherit from List and add your own handler, something like

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

Warning

  1. Be aware that you have to re-implement all methods which add objects to your list. AddRange() will not fire this event, in this implementation.

  2. We did not overload the method. We hid the original one. If you Add() an object while this class is boxed in List<T>, the event will not be fired!

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

Raise event when a list has new item?

Have a look at BindingList<T> and ObservableCollection<T>. This answer explains the difference between the two.

Apart from binding, you can subscribe to the change events like so:

BindingList<T>.ListChanged:

items.ListChanged += (sender, e) => {
// handle the change notification
};

ObservableCollection<T>.CollectionChanged:

items.CollectionChanged += (sender, e) => {
// handle the change notification
};

Adding an Event Handler for a List

There are collections which raise events when the list changes (BindingList(of T) for one) but the events are only going to be available to the class/form where the list lives. For a broader implementation your Schedule Class can raise events.

  1. Make sure only Schedule makes changes to the list. That is, your List(Of T) should be a private member. Other objects should make changes thru it so that it is fully aware of all changes so that none are missed.

  2. Decide what is a change event. Add and delete an item are obvious, but depending on what is in ScheduleItem maybe .StartTime or similar properties are events as well. (That would actually require INotifyPropertyChanged on the item class)

  3. For just Add and Delete, every time Schedule adds or deletes an item from the internal List, it would raise the event to notify the subscribers.

  4. Who is going to consume (or get) these events? Forms? Other class structs?

A simple way to do this, once all changes are happening in the class which 'owns' the list is a custom event:

Public Class Schedule
Private MyList as List (Of ScheduleItem)

Public Event ScheduleChanged(sender As Object, e As EventArgs)

...
Public Sub AddItemToSchedule(....)
' I have no idea what is in a ScheduleItem....
...
MyList.Add(si)
' the point is that if it gets added / not a dupe etc, then:
' tell any subscribers that the sched changed:
RaiseEvent ScheduleChanged(Me, New EventArgs())
End Sub

Public Sub RemoveItem(...)
' do whatever to remove an item
' ...
MyList.Remove(si)
' tell subscribers the sched changed
RaiseEvent ScheduleChanged(Me, New EventArgs())
End Sub
End Class

An alternative to the private collection is for Schedule to inherit from something like Collection(of T). For the subscribers of the event:

Public Class SomeOtherClass

' These need a reference to the Schedule object
Private WithEvents Sched As Schedule
...
Public Sub New(scObj As Schedule)
Sched = scObj
End Sub
End Class

SomeOtherClass will now have a new entry in the Left VS Dropdown abs a related event:

Private Sub Sched_ScheduleChanged(sender As Object,
e as EventArgs) Handles Sched.ScheduleChanged
' add code here to respond to schedule changes

End Sub

Usage:

Dim foo = New SomeOtherClass(SchedObj)

Whatever is creating the SomeOtherClass object passes the Schedule object in the constructor. If it is being created by Schedule it would be Me.

If SomeOtherClass has access to Schedule you can forego the constructor argument:

Public Sub New()
Sched = mainSchedInstance
End Sub

In all cases, Schedule needs to exist or the code will be trying to hook to events on a Nothing object.

Notes

  • It might seem odd to pass the Sched object (Me) in all the events
    (who else would send ScheduleChanged events?). But the VS code analysis tools object to an event signature other than Object sender, EventArgs e.
  • If you want to pass information in the event such as what type of change, create a class which inherits from EventsArgs and add whatever properties you want. One of those could be the ScheduleItem added

There are other ways to implement this, for instance of it was Foo.Schedule and SomeOtherClass needs to know about the event. In this case, Schedule still generates the event, Foo subscribes to it and then raises its own ScheduleChanged event, passing along the event args. Other actors subscribe to the event on Foo. This is referred to as 'bubbling up' an event.


You can also create a small class with one method and does nothing more than raise an event. In this case, it would be created by Schedule and be available to any actor via a non private member. SomeOtherClass could get a reference to the Schedule.ScheduleChangeNotifier from Foo. When the list changes, Schedule calls the method which fires the event and Foo isn't involved.

This pattern is usually called an EventBus, but it can be thought of as a Broadcast-Receiver setup: Schedule uses the class to broadcast a notice, others use it to receive them as an event. It is useful when there is otherwise no need for the 2 actors to even know about each other.

An example would be Foo.Bar needing to know about something from Fizz.Blorg: Bar could receive those events without involving Fizz or Foo beyond getting the bus/notifier object to Bar.

It is less common than bubbling up events but sometimes very useful. Usually though if it seems that is the answer, I try to re-examine the design to see if things could be simplified.

How to add an event listener to all items in array

Instead of attaching listeners to each button, add one to the container (set) and, using event delegation, let that listener capture all the events that "bubble up" the DOM from its child elements, and call a function.

const set = document.querySelector('.set');
set.addEventListener('click', handleClick, false);

function handleClick(e) {
if (e.target.matches('button')) {
const { textContent } = e.target;
console.log(`Banging the ${textContent} drum!`);
}
}
<h1 id="title">Drum Kit</h1>
<div class="set">
<button class="w drum">w</button>
<button class="a drum">a</button>
<button class="s drum">s</button>
<button class="d drum">d</button>
<button class="j drum">j</button>
<button class="k drum">k</button>
<button class="l drum">l</button>
</div>
<footer>
Made with ❤️ in London.
</footer>

Cannot add click events to list items

Let's do something like this

<ul id="parent-list">
<li id="a">Item A</li>
<li id="b">Item B</li>
<li id="c">Item C</li>
<li id="d">Item D</li>
<li id="e">Item E</li>
<li id="f">Item F</li>
</ul>

Now write the javascript for this

<script type="text/javascript">
// locate your element and add the Click Event Listener
document.getElementById("parent-list").addEventListener("click",function(e) {
// e.target is our targetted element.
// try doing console.log(e.target.nodeName), it will result LI
if(e.target && e.target.nodeName == "LI") {
console.log(e.target.id + " was clicked");
}
});
</script>

Please refer to this write-up on Javascript Event Delegates
http://davidwalsh.name/event-delegate

Also, below link is the fiddle that I created
http://jsfiddle.net/REtHT/

hope this helps !

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


Related Topics



Leave a reply



Submit