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
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.We did not overload the method. We hid the original one. If you
Add()
an object while this class is boxed inList<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.
Make sure only
Schedule
makes changes to the list. That is, yourList(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.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 requireINotifyPropertyChanged
on the item class)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.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 sendScheduleChanged
events?). But the VS code analysis tools object to an event signature other thanObject 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 theScheduleItem
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
C# - Volatile Keyword Usage VS Lock
Is Configurationmanager.Appsettings Available in .Net Core 2.0
How to Know the Size of the String in Bytes
Cannot Implicitly Convert Type 'Int' to 'T'
Ascending/Descending in Linq - Can One Change the Order via Parameter
How to Get Ip of All Hosts in Lan
Selectively Suppress Custom Obsolete Warnings
How to Data Bind a List of Strings to a Listbox in Wpf/Wp7
How to Give Read/Write Permissions to a Folder During Installation Using .Net
Is There Any Connection String Parser in C#
Using Msbuild to Execute a File System Publish Profile
How to Handle Add to List Event
How to See What My Reactive Extensions Query Is Doing
Assign Format of Datetime with Data Annotations
Is It Secure to Store Passwords in Cookies
Loop Through All Controls of a Form, Even Those in Groupboxes