您的位置:首页 > 其它

事件与委托--这篇文章算是讲的浅显明白

2004-08-24 09:48 232 查看
Download source files - 6.86 Kb
Download demo project - 3.75 Kb

Introduction

When I was trying to learn events and delegates, I read a lot of articles to completely understand what they are and how to use them, and now I want to present them all here, everything I learned, most of the things you need to learn.

What are delegates?

Delegate and Event concepts are completely tied together. Delegates are just function pointers, That is, they hold references to functions.

A
Delegate
is a class. When you create an instance of it, you pass in the function name (as a parameter for delegate's constructor) to which this delegate will refer.

Every delegate has a signature. For example:

Delegate int SomeDelegate(string s, bool b);

is a delegate declaration. When I say this delegate has a signature, I mean that it returns an
int
type and takes 2 parameters of type
string
and
bool
.

I said, when you instantiate delegates, you pass in the function name to which this delegate will refer as its constructor parameter. The important thing to notice is that only functions that have the same signature as the delegate, can be passed as a parameter.

Consider the following function:

private int SomeFunction(string str, bool bln){...}

You can pass this function to
SomeDelegate
's constructor, because of their similar signatures.

SomeDelegate sd= new SomeDelegate(SomeFunction);

Now,
sd
refers to
SomeFunction
, in other words,
SomeFunction
is registered to
sd
. If you call
sd
,
SomeFunction
will be invoked. Keep in mind what I mean by registered functions. Later, we will refer to registered functions.

sd("somestring", true);

Now that you know how to use delegates, let's understand events...

Understanding Events

A
Button
is a class, when you click on it, the
click
event fires.
A
Timer
is a class, every millisecond a
tick
event fires.

Want to understand what's happening? Let's learn through an example:


This is the scenario: we have a class named
Counter
. This class has a method named
CountTo(int countTo, int reachableNum)
which starts counting from 0 to
countTo
, and raises an event named
NumberReached
whenever it reaches the
reachableNum
.


Our class has an event:
NumberReached
. Events are variables of type delegates. I mean, if you want to declare an event, you just declare a variable of type some delegate and put
event
keyword before your declaration like this:

public event NumberReachedEventHandler NumberReached;

In the above declaration,
NumberReachedEventHandler
is just a delegate. Maybe it was better to say:
NumberReachedDelegate
, but notice that Microsoft doesn't say
MouseDelegate
or
PaintDelegate
, instead it offers:
MouseEventHandler
and
PaintEventHandler
. It's a convention to say
NumberReachedEventHandler
instead of
NumberReachedDelegate
. OK? Good!

You see, before we declare our event, we need to define our delegate (our event handler). It could be something like this:

public delegate void NumberReachedEventHandler(object sender,
NumberReachedEventArgs e);

As you see, our delegate's name is:
NumberReachedEventHandler
, and its signature contains a
void
return value and 2 parameters of type
object
and
NumberReachedEventArgs
. If you somewhere want to instantiate this delegate, the function passed in as constructor parameter should have the same signature as this delegate.

Have you ever used
PaintEventArgs
or
MouseEventArgs
in your code to determine the position of mouse, where it was moving, or the
Graphics
property of the object which raised the
Paint
event? Actually, we provide our data for the user in a class which is derived from
EventArgs
class. For example, in our example, we want to provide the number which was reached. And here is the class definition:

public class NumberReachedEventArgs : EventArgs

If it wouldn't be necessary to provide the user with any information, we just use the
EventArgs
class.

Now, every thing is prepared to take a look inside our
Counter
class:

namespace Events
if(ctr == reachableNum)

Good question! If you want to know why we called indirectly, take another look at
OnNumberReached
's signature:

protected virtual void OnNumberReached(NumberReachedEventArgs e)


You see, this method is
protected
, it means it's available for classes which are derived from this class (inheriting classes).
This method is also
virtual
, this means that it could be overridden in a derived class.

And this is very useful. Suppose you are designing a class which inherits from
Counter
class. By overriding
OnNumberReached
method, you can do some additional work in your class before the event gets raised. An example:

protected override void OnNumberReached(NumberReachedEventArgs e)

Note that if you don't call
base.OnNumberReached(e)
, the event will never be raised! This might be useful when you are inheriting from some class and want to eliminate some of its events! An interesting trick, huh?

As a real world example, you can just create a new ASP.NET Web Application and take a look inside the code behind generated. As you see, your page inherits from
System.Web.UI.Page
class. This class has a
virtual
and
protected
method name
OnInit
. You see that
InitializeComponent()
method is called inside the overridden method as an extra work, and then
OnInit(e)
is called in the base class:

Notice that
NumberReachedEventHandler
delegate is defined outside our class, inside the namespace, visible to all classes.

OK. Now, it's time to practically use our
Counter
class:

In our sample application, we have 2 textboxes named
txtCountTo
and
txtReachable
as follows:

private void cmdRun_Click(object sender, System.EventArgs e)

private void oCounter_NumberReached(object sender, NumberReachedEventArgs e)
oCounter.NumberReached += new NumberReachedEventHandler(
oCounter_NumberReached);
oCounter.NumberReached += new NumberReachedEventHandler(
oCounter_NumberReached2);[/code]
Now, after raising an event, both functions will be invoked one after another.

If somewhere in your code, based on conditions, you decided
oCounter_NumberReached2
not be invoked anymore on
NumberReached
event occurrences, you could simply do this:

oCounter.NumberReached -= new NumberReachedEventHandler(
oCounter_NumberReached2);

Finally

Don't forget to define these lines in your application's main constructor, instead of
cmdRun_Click
event handler. I defined them in my button click event handler just for the sake of simplicity! ;-)

public Form1()
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
oCounter= new Counter();
oCounter.NumberReached += new NumberReachedEventHandler(
oCounter_NumberReached);
oCounter.NumberReached += new NumberReachedEventHandler(
oCounter_NumberReached2);

The source code provided by this article is as above.

If your vote is less than 5, let me know the reason ;-). I hope you will be satisfied after reading this article!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: