can't wrap my mind around events

  • Thread starter Thread starter John Salerno
  • Start date Start date
J

John Salerno

My general problem with events seems to be that there are so many parts
to them, and I'm not sure where they all go or when you use which parts.
For example, there's the delegate, the event name, the event handler,
then the coding that wires it together. For the most part, I do
understand these things, but I get confused when it comes to putting it
all together.

More specifically, here's some code from a book:

this.txtMonthlyInvestment.TextChanged += new
System.EventHandler(this.txtMonthlyInvestment_TextChanged);

First off, do you need the 'this' keyword? Second, where does this code
go? In the Load event of the form that contains the text box?

Another example:

ProductList products = new ProductList(); //an array list object

products.Changed += new EventHandler(ChangedHandler);

Why isn't 'this' used in the second example? Is the book being
inconsistent, or is it a different situation? (In the book, it says it's
calling it from a different class, but I don't know what that means
exactly: "To handle an event from another class, you create an instance
of the class that raises the event and assign it to a class variable.")

Where does that first line go? (The declaration of products). The above
two lines are the entire example (except for the event handler itself),
so I think some stuff has been left out. It doesn't show which class
it's included in.


Basically I'm just very lost when it comes to events, and I always have.
I don't understand where all the code goes for each 'part', and that's
probably what it all comes down to, I guess.

Any help would be appreciated, or any suggestions for sites that clearly
explain events.

Thanks,
John
 
John Salerno said:
My general problem with events seems to be that there are so many parts
to them, and I'm not sure where they all go or when you use which parts.
For example, there's the delegate, the event name, the event handler,
then the coding that wires it together. For the most part, I do
understand these things, but I get confused when it comes to putting it
all together.

More specifically, here's some code from a book:

this.txtMonthlyInvestment.TextChanged += new
System.EventHandler(this.txtMonthlyInvestment_TextChanged);

First off, do you need the 'this' keyword?
Nope.

Second, where does this code
go? In the Load event of the form that contains the text box?

Well, you can put it wherever you want - but obviously the event won't
fire your handler until you've hooked it up.
Another example:

ProductList products = new ProductList(); //an array list object

products.Changed += new EventHandler(ChangedHandler);

Why isn't 'this' used in the second example? Is the book being
inconsistent, or is it a different situation? (In the book, it says it's
calling it from a different class, but I don't know what that means
exactly: "To handle an event from another class, you create an instance
of the class that raises the event and assign it to a class variable.")

That's just wrong. You don't need to have a member variable with a
reference to an instance in order to subscribe to an event - you just
need to have a reference for long enough to subscribe.
Where does that first line go? (The declaration of products). The above
two lines are the entire example (except for the event handler itself),
so I think some stuff has been left out. It doesn't show which class
it's included in.

Basically I'm just very lost when it comes to events, and I always have.
I don't understand where all the code goes for each 'part', and that's
probably what it all comes down to, I guess.

Any help would be appreciated, or any suggestions for sites that clearly
explain events.

There's nothing particularly magical about them - that's possibly
what's confusing you. Just think of the "+=" as calling an "add" method
and "-=" as calling a "remove" method, and think of a delegate as a
list of handlers. The only odd thing about delegates are C#'s handling
of += and -= (for the delegates themselves, not events), which are
actually calls to static methods which is how you can add to null...
 
John said:
More specifically, here's some code from a book:

this.txtMonthlyInvestment.TextChanged += new
System.EventHandler(this.txtMonthlyInvestment_TextChanged);

First off, do you need the 'this' keyword? Second, where does this code
go? In the Load event of the form that contains the text box?

this always refers to the current class instance. In your case, since
it is accessing text boxes, 'this' probably refers to the current form.
It may not be necessary to use 'this'. The author of the code may
have used it to stress that the txtMonthlyInvestment is part of the
current form. As to where it goes, it is normally placed in the
constructor of the form or in the load event. All that really matters
is that the line of code is executed before you need to catch the
events.
Another example:

ProductList products = new ProductList(); //an array list object

products.Changed += new EventHandler(ChangedHandler);
Why isn't 'this' used in the second example? Is the book being
inconsistent, or is it a different situation? (In the book, it says it's

It might be inconsistent, but 'this' may not be required here. It just
depends on where the code appears.
calling it from a different class, but I don't know what that means
exactly: "To handle an event from another class, you create an instance
of the class that raises the event and assign it to a class variable.")

Where does that first line go? (The declaration of products). The above
two lines are the entire example (except for the event handler itself),
so I think some stuff has been left out. It doesn't show which class
it's included in.

The declaration of Products could be anywhere. It could be at the top
of your form class. It could be a private variable inside a method or
as a property to a user defined class. Perhaps the author was
intending that it be placed in the top of the form class.


I hope this helped a little. I'm sure, once you look at events more
closely, that it will become easier for you.
 
InLine Comments:

John Salerno said:
My general problem with events seems to be that there are so many parts to
them, and I'm not sure where they all go or when you use which parts. For
example, there's the delegate, the event name, the event handler, then the
coding that wires it together. For the most part, I do understand these
things, but I get confused when it comes to putting it all together.

More specifically, here's some code from a book:

this.txtMonthlyInvestment.TextChanged += new
System.EventHandler(this.txtMonthlyInvestment_TextChanged);

First off, do you need the 'this' keyword? Second, where does this code
go? In the Load event of the form that contains the text box?
You do not need the "this" keyword. This just means use this classes method
named txtMonthlyInvestment_TextChanged. Without it, if there was a public
method with the same name 'txtMonthlyInvestment_TextChanged' on the base
class, and none on the derived class, it would use the base class' method
(if it had the same signature).

The event gets fired after Page_Load but the events get "attached" prior to
Page_Load. So, to make sure the event fires, you would place it in
InitializeComponent (I believe that is the correct method, may be
Page_Init...can't remember).
Another example:

ProductList products = new ProductList(); //an array list object

products.Changed += new EventHandler(ChangedHandler);

Why isn't 'this' used in the second example? Is the book being
inconsistent, or is it a different situation? (In the book, it says it's
calling it from a different class, but I don't know what that means
exactly: "To handle an event from another class, you create an instance of
the class that raises the event and assign it to a class variable.")

Where does that first line go? (The declaration of products). The above
two lines are the entire example (except for the event handler itself), so
I think some stuff has been left out. It doesn't show which class it's
included in.
Once again, the 'this' keyword is not required. You have class A and class
B. Class A exposes an event, Event E. In class B, you want to catch Event
E for when class A raises it. So, you would create a class B instance and
assign it to a variable of type "B". Then you would add the event handler
for Event E on the variable of type "B". ? Understand :)\

HTH a little at least ;)

Mythran
 
Mythran said:
Once again, the 'this' keyword is not required. You have class A and class
B. Class A exposes an event, Event E. In class B, you want to catch Event
E for when class A raises it. So, you would create a class B instance and
assign it to a variable of type "B". Then you would add the event handler
for Event E on the variable of type "B". ? Understand :)\

I think this part is what confuses me.

Let's say you have class A, which is a button. The event for this class
is Click. You want class B to respond to this click. Now, is class B
responding to a particular button's Click event, or just any button that
is instantiated from class A?

For example: I have an OK button that was created from class A, and it's
on my main form. In class B, when I'm writing the code to wire the event
to the event handler, do I need to refer to this button specifically, or
do I simply create a new instance of A that isn't even used in the
program or anywhere on the form?
 
Let's say you have class A, which is a button. The event for this class
is Click. You want class B to respond to this click. Now, is class B
responding to a particular button's Click event, or just any button that
is instantiated from class A?

Think delegate as a function pointer. Think of A as an object that will
need to call a function when an action occur. An event is associated
with the instance of a class not the class itself and when the event
occur it needs to call a function that could be anywhere.

Instantiate A, wire the event you want to A, this could be in any other
class such as B. A is the object, when it's click it has a function
pointer to a function in B.
 
I had some trouble wrapping my head around them originally, but now I
consider them an indespensable tool.

Think of it like a radio broadcast. The message is only ever sent once,
but anyone that is 'tuned in' to the right station can hear the signal.

So, the broadcaster needs to declare a delegate (basically stating your
intention to broadcast). The delegate is then registered as an event in
a specific class (um, think of it like a radio station. Many stations
can be associated with one broadcaster)

Then, you need to set up your specific radios to tune into the Station
that you want to listen too. This is done by creating a function that
has the same signature as the original delegate. If the delegate says
it needs one string and two integers, then the 'Radio class' needs to
implement a function that takes one string and two integers as
parameters. This is the function that will process the request in any
way it decides too.

After this is done, you need to wire it all up. That's where the
Object.EventName += ... comes in. You must attach the event to the
function by creating a new Delegate reference to the function that will
eventually process the request.

So... (Warning, this was written in a text editor and is only for demo
purposes. Not sure if it will compile)

Namespace Broadcaster
{
public delegate void SendAMessage(string strMessage);

class RadioStation
{

public event SendAMessage BroadcastEvent;

public RadioStation() {}

public Broadcast Something(string strMyMessage)
{
if(broadcastEvent != null) //This is important. Always test
before firing
{
BroadcastEvent(strMyMessage);
}
}

} //End Class


class Radio
{
public string _strRadioName;
public radio(RadioStation rsNewStation, string strRadioName)
{
_strRadioName = strRadioName;
rsNewStation.BroadcastEvent += new
SendAMessage(DisplayBroadcast);
}

public void DisplayBroadcast(string strStuff)
{
System.Forms.MessageBox.Show("Recieved from radio " +
_strRadioName + ": " + strStuff);
}
} //End class
} //End Namespace

/****************************/
Namespace Testing
{
using Broadcaster;
public class MyTest
{
public MyTest()
{
public RadioStation _rsHeavyMetalHeaven = new
RadioStation();

public Radio[3] _rRadio;

for(int i = 0; i < _rRadio.Length; i++)
{
_rRadio = new Radio(rsHeavyMetalHeaven);
}

}

Main()
{
MyTest = new MyTest();

MyTest.rsHeavyMetalHeaven.BroadcastSomething("Growl, growl,
DIE DIE DIE!");
MyTest.rsHeavyMetalHeaven.BroadcastSomething("That was
VegetarianDogs with 'die'. And now a word from our sponsor...");

}
}
}


This would be an even more effective example if there was another class
called say... OnlineListner that also implemented the BroadcastEvent
but did something different with it when the message is recieved.

Hope this helps a little.
 
I had some trouble wrapping my head around them originally, but now I
consider them an indespensable tool.

Think of it like a radio broadcast. The message is only ever sent once,
but anyone that is 'tuned in' to the right station can hear the signal.

So, the broadcaster needs to declare a delegate (basically stating your
intention to broadcast). The delegate is then registered as an event in
a specific class (um, think of it like a radio station. Many stations
can be associated with one broadcaster)

Then, you need to set up your specific radios to tune into the Station
that you want to listen too. This is done by creating a function that
has the same signature as the original delegate. If the delegate says
it needs one string and two integers, then the 'Radio class' needs to
implement a function that takes one string and two integers as
parameters. This is the function that will process the request in any
way it decides too (i.e. if different Radio classes implement an
abstract radio class, one can displays colors based on sound, one can
modulate out all the Bass notes, one just resends it).

After this is done, you need to wire it all up. That's where the
Object.EventName += ... comes in. This gets declared in the class that
you want to recieve the event (our Radio in this case). You must attach
the event to the function by creating a new Delegate reference to
whatever the end point is.

So... (Warning, this was written in a text editor and is only for demo
purposes. Not sure if it will compile)

Namespace Broadcaster
{
public delegate void SendAMessage(string strMessage);

class RadioStation
{

public event SendAMessage BroadcastEvent;

public RadioStation() {}

public void BroadcastSomething(string strMyMessage)
{
if(broadcastEvent != null) //This is important. Always test
before firing
{
BroadcastEvent(strMyMessage);
}
}

} //End Class


class Radio
{
public string _strRadioName;
public radio(RadioStation rsNewStation, string strRadioName)
{
_strRadioName = strRadioName;
rsNewStation.BroadcastEvent += new
SendAMessage(DisplayBroadcast);
}

public void DisplayBroadcast(string strStuff)
{
System.Forms.MessageBox.Show("Recieved from radio " +
_strRadioName + ": " + strStuff);
}
} //End class
} //End Namespace

/****************************/
Namespace Testing
{
using Broadcaster;
public class MyTest
{
public MyTest()
{
public RadioStation _rsHeavyMetalHeaven = new
RadioStation();

public Radio[3] _rRadio;

for(int i = 0; i < _rRadio.Length; i++)
{
_rRadio = new Radio(_rsHeavyMetalHeaven);
}

}

public Main()
{
MyTest = new MyTest();

MyTest._rsHeavyMetalHeaven.BroadcastSomething("Growl,
growl, DIE DIE DIE!");
MyTest._rsHeavyMetalHeaven.BroadcastSomething("That was
VegetarianDogs with 'die'. And now a word from our sponsor...");

}
}
}


This would be an even more effective example if there was another class
called say... OnlineListner that also implemented the BroadcastEvent
but did something different with it when the message is recieved.

Hope this helps a little.

Russ
 
John Salerno said:
Let's say you have class A, which is a button. The event for this
class is Click. You want class B to respond to this click. Now, is
class B responding to a particular button's Click event, or just any
button that is instantiated from class A?

Depends on whether or not the event was declared as static. But we won't
go there because I think that would just make things more confusing,

So assuming the event exists at the instance level, in other words that
every instance of A has its own Click event, an instance of class B will
be responding to events from an instance of class A.
For example: I have an OK button that was created from class A, and
it's on my main form. In class B, when I'm writing the code to wire
the event to the event handler, do I need to refer to this button
specifically, or do I simply create a new instance of A that isn't
even used in the program or anywhere on the form?

You need the instance of class A, the OK button, in order to wire it to
the instance of class B.

public class A
{
public event EventHandler Click;

// Normally, the method for raising an event is protected virtual,
// but this is just for demonstration purposes.
public void OnClick()
{
EventHandler handler = Click;

if(handler != null)
{
handler(this, EventArgs.Empty);
}
}
}

public class B
{
public B(A aInstance)
{
// Here we are connecting the event in an instance of
// class A to an instance of class B.
aInstance.Click += new EventHandler(HandleClick);
}

private void HandleClick(object sender, EventArgs e)
{
Console.WriteLine("Handled Click event.");
}
}

// Somewhere else in your application...

A a1 = new A();
B b1 = new B(a1);

A a2 = new A();
B b2 = new B(a2);

Now, an instance of class A called 'a1' is connected via the Click event
to an instance of class B called 'b1'. And an instance of class A called
a2 is connected via the Click event to an instance of class B called
'b2'.

When a1 raises its event through a call to the OnClick method, only b1
will respond to the event. Likewise, when a2 raises the Click event,
only b2 will respond.
 
Woah, thanks for all that. But the book I'm reading doesn't even talk
about declaring delegates separately! Now there's even more I have to learn!



I had some trouble wrapping my head around them originally, but now I
consider them an indespensable tool.

Think of it like a radio broadcast. The message is only ever sent once,
but anyone that is 'tuned in' to the right station can hear the signal.

So, the broadcaster needs to declare a delegate (basically stating your
intention to broadcast). The delegate is then registered as an event in
a specific class (um, think of it like a radio station. Many stations
can be associated with one broadcaster)

Then, you need to set up your specific radios to tune into the Station
that you want to listen too. This is done by creating a function that
has the same signature as the original delegate. If the delegate says
it needs one string and two integers, then the 'Radio class' needs to
implement a function that takes one string and two integers as
parameters. This is the function that will process the request in any
way it decides too (i.e. if different Radio classes implement an
abstract radio class, one can displays colors based on sound, one can
modulate out all the Bass notes, one just resends it).

After this is done, you need to wire it all up. That's where the
Object.EventName += ... comes in. This gets declared in the class that
you want to recieve the event (our Radio in this case). You must attach
the event to the function by creating a new Delegate reference to
whatever the end point is.

So... (Warning, this was written in a text editor and is only for demo
purposes. Not sure if it will compile)

Namespace Broadcaster
{
public delegate void SendAMessage(string strMessage);

class RadioStation
{

public event SendAMessage BroadcastEvent;

public RadioStation() {}

public void BroadcastSomething(string strMyMessage)
{
if(broadcastEvent != null) //This is important. Always test
before firing
{
BroadcastEvent(strMyMessage);
}
}

} //End Class


class Radio
{
public string _strRadioName;
public radio(RadioStation rsNewStation, string strRadioName)
{
_strRadioName = strRadioName;
rsNewStation.BroadcastEvent += new
SendAMessage(DisplayBroadcast);
}

public void DisplayBroadcast(string strStuff)
{
System.Forms.MessageBox.Show("Recieved from radio " +
_strRadioName + ": " + strStuff);
}
} //End class
} //End Namespace

/****************************/
Namespace Testing
{
using Broadcaster;
public class MyTest
{
public MyTest()
{
public RadioStation _rsHeavyMetalHeaven = new
RadioStation();

public Radio[3] _rRadio;

for(int i = 0; i < _rRadio.Length; i++)
{
_rRadio = new Radio(_rsHeavyMetalHeaven);
}

}

public Main()
{
MyTest = new MyTest();

MyTest._rsHeavyMetalHeaven.BroadcastSomething("Growl,
growl, DIE DIE DIE!");
MyTest._rsHeavyMetalHeaven.BroadcastSomething("That was
VegetarianDogs with 'die'. And now a word from our sponsor...");

}
}
}


This would be an even more effective example if there was another class
called say... OnlineListner that also implemented the BroadcastEvent
but did something different with it when the message is recieved.

Hope this helps a little.

Russ
 
Hmm, it's starting to make a little more sense. I appreciate all this help.

I think one thing that had me confused at first (and that I see a little
more clearly now because I've seen an entire program presented in the
book I'm reading) is that I didn't realize that 'products' in one class
was different than 'products' in another class. I never realized this
because the code was presented in pieces, until I got to the end of the
chapter. Now I realize that each 'products' is a private member of its
own class, and is independent of the other.
 
k. first off, this was GREAT exercise for me so thanks for the
googlespace.

This compiles in Mono (Fedora 4, Mono, MonoDevelop is my new toy :) -
can't get dovecot to work!!!) but I haven't figured out abstraction in
Mono so I had to implement everything three times... but this should be
a good example of delegates. Every call made to the BroadcastSomething
method in the 'RadioStation' class is handled by three entirely
independant 'Radio' objects. Two of them are BackwardsStation, one of
them is ForwardStation.
CODE:

//************RadioStationTesting.cs ---
// created on 9/6/2005 at 6:02 PM
namespace Broadcaster
{
using System.Diagnostics;
public delegate void SendAMessage(string strMessage);

public class RadioStation
{
public event SendAMessage BroadcastEvent;

public RadioStation() {}

public void BroadcastSomething(string strMyMessage)
{
if(BroadcastEvent != null) //This is important. Always test
//before firing
{
BroadcastEvent(strMyMessage);
}
}
} //End Class

public abstract class Radio
{
public string _strRadioName;
public Radio(RadioStation rsNewStation, string strRadioName)
{
_strRadioName = strRadioName;
rsNewStation.BroadcastEvent += new
SendAMessage(DisplayBroadcast);
}
public abstract void DisplayBroadcast(string strStuff);
} //End class

public class BackwardsStation:RadioStation
{
public string _strRadioName;
public BackwardsStation(RadioStation rsNewStation, string
strRadioName)
{
_strRadioName = strRadioName;
rsNewStation.BroadcastEvent += new
SendAMessage(DisplayBroadcast);
}

public void DisplayBroadcast(string strStuff)
{
string strTemp = "";
for(int i = strStuff.Length - 1; i > 0 ; i--)
{
strTemp += strStuff.Substring(i,1);
}
System.Console.WriteLine("Recieved from radio " +
_strRadioName + ": " + strTemp);
}
}

public class ForwardStation:RadioStation
{
public string _strRadioName;
public ForwardStation(RadioStation rsNewStation, string
strRadioName)
{
_strRadioName = strRadioName;
rsNewStation.BroadcastEvent += new
SendAMessage(DisplayBroadcast);
}

public void DisplayBroadcast(string strStuff)
{
System.Console.WriteLine("Recieved from radio " +
_strRadioName + ": " + strStuff);
}
}
}
/****************************/
namespace Testing
{
using Broadcaster;
using System.Collections;
public class MyTest
{
public RadioStation _rsHeavyMetalHeaven = new RadioStation();
public ArrayList _alRadio = new ArrayList();
private RadioStation RadioStation1;
private RadioStation RadioStation2;
private RadioStation RadioStation3;

public MyTest()
{
RadioStation1 = new BackwardsStation(_rsHeavyMetalHeaven,
"Radio #1");
RadioStation2 = new ForwardStation(_rsHeavyMetalHeaven,
"Radio #2");
RadioStation3 = new BackwardsStation(_rsHeavyMetalHeaven, "Radio
#3");
}
}
}
///-----------End File
//File: Main.cs
// project created on 9/6/2005 at 6:01 PM
using System;
using Testing;

class MainClass
{
public static void Main(string[] args)
{
MyTest mt= new MyTest();
mt._rsHeavyMetalHeaven.BroadcastSomething("Growl,growl...
DIE DIE DIE!");
mt._rsHeavyMetalHeaven.BroadcastSomething("That was
VegetarianDogs with 'die'. " +
"And now a word from our sponsor...");
}
}

OUTPUT:
--Sorry, I can't seem to capture my console window output in Fedora...
(I suck :{ )


Back to Windows Land:
If, in VS.Net (2003) you simply moved the Testing namespace to one
project, and the Broadcast namespace to a different one and included a
reference to Broadcast in Testing, you may start to see the value in
this. I have one class (a wrapper around a serial port driver) that
fires an event that is consumed by a windows form, a class on an
independant thread and Log4Net all at the same time, in multiple
projects and namespaces...

I have a different project where a Windows User control takes an object
from an independant thread as a parameter in the constructor (much like
Radio class). Basically it allows me to talk back to any independant
control from an entirely independant thread .

NOTE:
I have found that in any class I fire an event from, I MUST wrap the
call in a "!= null" check. Otherwise if no handler for the event is
ever created, it throws an exception. (Any opinions on this?)

k. Gonna give it a rest now. Hope nobody else ever has to go through my
pain to figure out delegates again. :)

Russ
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top