好了,言规正传,首先我们来说说委托和事件。
首先我们来看一个通俗的理解。
比如说一个公司(场景),你是老板,手下有两个员工,小张和小王。
你命令小王,如果小张玩游戏,则小王扣去小张500元钱。
这就是现实中的委托。
实际上,在写程序中,程序员就是老板,小张和小王就是两个对象。小张玩游戏是一个方法,小张还有一个游戏事件,他玩游戏激发这个事件。而小王就是事件处理对象,他负责把小张的钱扣除500。
所以,委托有如下几个要素:
1 激发事件的对象--就是小张
2 处理对象事件的对象--就是小王
3 定义委托,就是你让小王监视小张。
实际上,委托用来保存一个方法的引用。委托是一个类,当你对它实例化时,要提供一个引用函数,将其作为它构造函数的参数。
public delegate void MyEventHanlder(object sender,EventArgs e)
这是,所谓的委托签名实际上指的是object和EventArgs类型的形参。
看下面的函数:
private void MyFunction(object sender,EventArgs e){...}
你可以将这个方法传递给委托的构造函数,如下:
MyEventHanlder eh=new MyEventHanlder (MyFunction);
这句话表达的含义是:如果你调用了eh,你就调用了MyFunction。
现在我们再来看事件:
事件是委托类型的变量。意思是:如果给事件命名,用event关键字和要使用的委托类型申明它即可,如下所示:
public event MyEventHanlder click;
现在我们还没有还没有实际引发这个事件,看下面的代码:
2using System.Web.UI;
3
4namespace CustomComponents
5{
6 /**//// <summary>
7 /// SuperButton1 的摘要说明。
8 /// </summary>
9 //public delegate void MyEventHandler(object sender,EventArgs e);
10
11 public class SuperButton1 : Control, IPostBackEventHandler
12 {
13 // 声明Click事件委托
14 public event EventHandler Click;
15
16 // 定义OnClick事件处理程序
17 protected virtual void OnClick(EventArgs e)
18 {
19 if (Click != null)
20 {
21 Click(this, e);
22 }
23 }
24
25 // 实现RaisePostBackEvent方法,处理回发事件
26 public void RaisePostBackEvent(string eventArgument)
27 {
28 OnClick(EventArgs.Empty);
29 }
30
31 protected override void Render(HtmlTextWriter output)
32 {
33 output.Write("<INPUT TYPE=submit name=" + this.UniqueID +
34 " Value='确定' />");
35 }
36 }
37
38}
39
以上代码,有以下几点要弄清楚原因:
1.如果有自定义的委托,则一定要在类外定义,因为所有的类(包括在webform.aspx)页面中都需调用。如以上已被注释的代码:public delegate void MyEventHandler(object sender,EventArgs e);
2.if (Click != null)
{
Click(this, e);
}
可以调用所有注册方法,换句话理解,如果在页面上调用使用此控件时,需要首先注册方法,如下:
this.SuperButton11.Click1+= new System.EventHandler(this.SuperButton11_Click);否则会提示错误。
3.为什么要在OnClick方法前加上protected virtual修辞符。
关键字protected限定了 只有从该类继承的类才能调用该类中的所有方法。
关键字virtual 表明了 在继承类中可以重写该方法。
这两点非常有用,假设你在写一个从SuperButton1继承而来的类,通过重写OnClick方法,你可以在事件触发之前,进行一次其他的工作。
protected override void OnClick(NumberReachedEventArgs e)
{
base.OnClick(e);
}
注意:如果你没有调用base.OnClick(e), 那么从不会触发这个事件!在你继承该类而想剔出它的一些其他事件时,使用该方式是非常有用的。
4.还要注意我们用的是+= 而不是=;这是因为委托是特殊的对象,它可以引用多个对象(在这里是指它可以引用多个函数)。如下代码:
this.SuperButton11.Click1+= new System.EventHandler(this.SuperButton11_Click);
this.SuperButton11.Click1+= new System.EventHandler(this.SuperButton12_Click);
5.优化事件:
原因:1.假设你在页面上多次使用这个控件,编译器将为每个事件委托实例生成一个字段。如果事件的数目很大,则一个委托一个字段的存储成本可能无法接受。.所以推荐采用另外一种优化的事件实现。
2.另外,在Onclick方法的实现过程中,当用一个事件属性时,必须从EventHandlerList中取回委托,并转换成EventHandler类型。
相关代码表示如下:
2using System.Web.UI;
3
4namespace CustomComponents
5{
6 /**//// <summary>
7 /// SuperButton1 的摘要说明。
8 /// </summary>
9 //public delegate void MyEventHandler(object sender,EventArgs e);
10
11 public class SuperButton1 : Control, IPostBackEventHandler
12 {
13 // 声明Click事件委托
14 private static readonly object ClickKey = new object();
15
16 public event EventHandler Click
17 {
18 add
19 {
20 Events.AddHandler(ClickKey, value);
21 }
22 remove
23 {
24 Events.RemoveHandler(ClickKey, value);
25 }
26 }
27
28
29 // 定义OnClick事件处理程序
30 protected virtual void OnClick(EventArgs e)
31 {
32 EventHandler Click =(EventHandler)Events[ClickKey];
33 if (Click != null)
34 {
35 Click(this, e);
36 }
37 }
38
39 // 实现RaisePostBackEvent方法,处理回发事件
40 public void RaisePostBackEvent(string eventArgument)
41 {
42 OnClick(EventArgs.Empty);
43 }
44
45 protected override void Render(HtmlTextWriter output)
46 {
47 output.Write("<INPUT TYPE=submit name=" + this.UniqueID +
48 " Value='确定' />");
49 }
50 }
51
52}