Simple Custom Event

simple custom event

This is an easy way to create custom events and raise them. You create a delegate and an event in the class you are throwing from. Then subscribe to the event from another part of your code. You have already got a custom event argument class so you can build on that to make other event argument classes. N.B: I have not compiled this code.

public partial class Form1 : Form
{
private TestClass _testClass;
public Form1()
{
InitializeComponent();
_testClass = new TestClass();
_testClass.OnUpdateStatus += new TestClass.StatusUpdateHandler(UpdateStatus);
}

private void UpdateStatus(object sender, ProgressEventArgs e)
{
SetStatus(e.Status);
}

private void SetStatus(string status)
{
label1.Text = status;
}

private void button1_Click_1(object sender, EventArgs e)
{
TestClass.Func();
}

}

public class TestClass
{
public delegate void StatusUpdateHandler(object sender, ProgressEventArgs e);
public event StatusUpdateHandler OnUpdateStatus;

public static void Func()
{
//time consuming code
UpdateStatus(status);
// time consuming code
UpdateStatus(status);
}

private void UpdateStatus(string status)
{
// Make sure someone is listening to event
if (OnUpdateStatus == null) return;

ProgressEventArgs args = new ProgressEventArgs(status);
OnUpdateStatus(this, args);
}
}

public class ProgressEventArgs : EventArgs
{
public string Status { get; private set; }

public ProgressEventArgs(string status)
{
Status = status;
}
}

Creating a Custom Event

Yes you can do like this :

Creating advanced C# custom events

or

The Simplest C# Events Example Imaginable

public class Metronome
{
public event TickHandler Tick;
public EventArgs e = null;
public delegate void TickHandler(Metronome m, EventArgs e);
public void Start()
{
while (true)
{
System.Threading.Thread.Sleep(3000);
if (Tick != null)
{
Tick(this, e);
}
}
}
}
public class Listener
{
public void Subscribe(Metronome m)
{
m.Tick += new Metronome.TickHandler(HeardIt);
}

private void HeardIt(Metronome m, EventArgs e)
{
System.Console.WriteLine("HEARD IT");
}
}
class Test
{
static void Main()
{
Metronome m = new Metronome();
Listener l = new Listener();
l.Subscribe(m);
m.Start();
}
}

Create a custom event in Java

You probably want to look into the observer pattern.

Here's some sample code to get yourself started:

import java.util.*;

// An interface to be implemented by everyone interested in "Hello" events
interface HelloListener {
void someoneSaidHello();
}

// Someone who says "Hello"
class Initiater {
private List<HelloListener> listeners = new ArrayList<HelloListener>();

public void addListener(HelloListener toAdd) {
listeners.add(toAdd);
}

public void sayHello() {
System.out.println("Hello!!");

// Notify everybody that may be interested.
for (HelloListener hl : listeners)
hl.someoneSaidHello();
}
}

// Someone interested in "Hello" events
class Responder implements HelloListener {
@Override
public void someoneSaidHello() {
System.out.println("Hello there...");
}
}

class Test {
public static void main(String[] args) {
Initiater initiater = new Initiater();
Responder responder = new Responder();

initiater.addListener(responder);

initiater.sayHello(); // Prints "Hello!!!" and "Hello there..."
}
}

Related article: Java: Creating a custom event

Create JavaScript custom event

Perhaps something like this?

function OnPrinterStateChanged(state) {
var evt = new CustomEvent('printerstatechanged', { detail: state });

window.dispatchEvent(evt);
}

//Listen to your custom event
window.addEventListener('printerstatechanged', function (e) {
console.log('printer state changed', e.detail);
});

An alternative solution would be to use function composition, but then it would be hard to remove specific listeners.

function OnPrinterStateChanged(state) {}

function compose(fn1, fn2) {
return function () {
fn1.apply(this, arguments);
fn2.apply(this, arguments);
};
}

//Add a new listener
OnPrinterStateChanged = compose(OnPrinterStateChanged, function (state) {
console.log('listener 1');
});

//Add another one
OnPrinterStateChanged = compose(OnPrinterStateChanged, function (state) {
console.log('listener 2');
});

EDIT:

Here's how you can do it with jQuery.

function OnPrinterStateChanged(state) {
var evt = $.Event('printerstatechanged');
evt.state = state;

$(window).trigger(evt);
}

//Listen to your custom event
$(window).on('printerstatechanged', function (e) {
console.log('printer state changed', e.state);
});

Custom events in jQuery?

Take a look at this:

(reprinted from the expired blog page http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ based on the archived version at http://web.archive.org/web/20130120010146/http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/)


Publish / Subscribe With jQuery

June 17th, 2008

With a view to writing a jQuery UI integrated with the offline functionality of Google Gears i’ve been toying with some code to poll for network connection status using jQuery.

The Network Detection Object

The basic premise is very simple. We create an instance of a network detection object which will poll a URL at regular intervals. Should these HTTP requests fail we can assume that network connectivity has been lost, or the server is simply unreachable at the current time.

$.networkDetection = function(url,interval){
var url = url;
var interval = interval;
online = false;
this.StartPolling = function(){
this.StopPolling();
this.timer = setInterval(poll, interval);
};
this.StopPolling = function(){
clearInterval(this.timer);
};
this.setPollInterval= function(i) {
interval = i;
};
this.getOnlineStatus = function(){
return online;
};
function poll() {
$.ajax({
type: "POST",
url: url,
dataType: "text",
error: function(){
online = false;
$(document).trigger('status.networkDetection',[false]);
},
success: function(){
online = true;
$(document).trigger('status.networkDetection',[true]);
}
});
};
};

You can view the demo here. Set your browser to work offline and see what happens…. no, it’s not very exciting.

Trigger and Bind

What is exciting though (or at least what is exciting me) is the method by which the status gets relayed through the application. I’ve stumbled upon a largely un-discussed method of implementing a pub/sub system using jQuery’s trigger and bind methods.

The demo code is more obtuse than it need to be. The network detection object publishes ’status ‘events to the document which actively listens for them and in turn publishes ‘notify’ events to all subscribers (more on those later). The reasoning behind this is that in a real world application there would probably be some more logic controlling when and how the ‘notify’ events are published.

$(document).bind("status.networkDetection", function(e, status){
// subscribers can be namespaced with multiple classes
subscribers = $('.subscriber.networkDetection');
// publish notify.networkDetection even to subscribers
subscribers.trigger("notify.networkDetection", [status])
/*
other logic based on network connectivity could go here
use google gears offline storage etc
maybe trigger some other events
*/
});

Because of jQuery’s DOM centric approach events are published to (triggered on) DOM elements. This can be the window or document object for general events or you can generate a jQuery object using a selector. The approach i’ve taken with the demo is to create an almost namespaced approach to defining subscribers.

DOM elements which are to be subscribers are classed simply with “subscriber” and “networkDetection”. We can then publish events only to these elements (of which there is only one in the demo) by triggering a notify event on $(“.subscriber.networkDetection”)

The #notifier div which is part of the .subscriber.networkDetection group of subscribers then has an anonymous function bound to it, effectively acting as a listener.

$('#notifier').bind("notify.networkDetection",function(e, online){
// the following simply demonstrates
notifier = $(this);
if(online){
if (!notifier.hasClass("online")){
$(this)
.addClass("online")
.removeClass("offline")
.text("ONLINE");
}
}else{
if (!notifier.hasClass("offline")){
$(this)
.addClass("offline")
.removeClass("online")
.text("OFFLINE");
}
};
});

So, there you go. It’s all pretty verbose and my example isn’t at all exciting. It also doesn’t showcase anything interesting you could do with these methods, but if anyone’s at all interested to dig through the source feel free. All the code is inline in the head of the demo page

Javascript Custom Events Handling Problem

The problem with your code is that you're dispatching three events from each of the three rows in the table, which is working perfectly, but the problem is that you're listening for these events from an entirely different branch.

Let me make it more clear, when a node emits an event, that event can only be caught (or listened) by its ancestor nodes (including the node itself).

So, in your code the event is being emitted by the table row (<tr>), so it can only be caught by any of its ancestors like <tbody> <table> and so on, but the node that is listening to this event is the <input id="myButton"> node, which is on an entirely different branch. So, the event never reaches the <input> node and you never see the alert.

I believe this error is because the this keyword refers to different nodes in both the places in your code. Inside the each loop, this refers to the table rows (<tr>), but outside the loop (inside the click handler) it refers to the input (<input id="myButton">) node.

NOTE: There's one more mistake in the code i.e. the object with the detail property should be passed as the second argument to the CustomEvent constructor not as the second argument to dispatchEvent.

Incorrect Code:

this.dispatchEvent(new CustomEvent("customEvent"), {
detail: "123",
});

Correct Code:

this.dispatchEvent(new CustomEvent("customEvent", {
detail: "123",
}));

In code snippet below I've moved the event listener inside the each loop, so now the events are being dispatched from the table rows and they are also being listened by the table rows. So, all the three rows are emitting a "customEvent" event and all the three rows are listening to a "customEvent" event.

So, the first row dispatches the "customEvent" event, which is caught by the first row's "customEvent" listener. Note that the other two listeners don't catch this event because they are not on the same branch, they are actually sibling nodes. Similarly the other two rows emit the "customEvent" event which is caught by their respective listeners, resulting in three alerts.

Also, note the way how the code is currently structured, the code for listening the event should be placed before the code for dispatching the event.

$("#myButton").on("click", function() {
$("#tfm").find("tbody tr").each(function(index) {
console.log(this)
this.addEventListener("customEvent", (event, args) => {
alert('messageRecieved');
});
this.dispatchEvent(new CustomEvent("customEvent", {
detail: "123"
}));
});
console.log(this);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<input id="myButton" type=button value="Press Me" />
</div>
<table id="tfm">
<thead>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>

How do I add custom events to classes in node?

You've got a couple options:

If you want to use instance.on you have to inherit from EventEmitter like so:

let EventEmitter = require('events').EventEmitter

class Farm extends EventEmitter {
constructor() {
super()
}

buyAnimals() {
this.emit('totalChanged', { value: 'foo' })
}
}

let testFarm = new Farm()
testFarm.on('totalChanged', value => {
console.log(value)
})

testFarm.buyAnimals()

If you prefer to use composition instead of inheritance, you can simply instantiate EventEmitter as a property and use instance.eventEmitter.on like so:

let EventEmitter = require('events').EventEmitter

class Farm {
constructor() {
this.eventEmitter = new EventEmitter()
}

buyAnimals() {
this.eventEmitter.emit('totalChanged', { value: 'foo' })
}
}

let testFarm = new Farm()
testFarm.eventEmitter.on('totalChanged', value => {
console.log(value)
})

testFarm.buyAnimals()


Related Topics



Leave a reply



Submit