|
//Cat类是事件的生成者,通过OnCry()方法引发Cry事件
//但Cat类并不知道谁会监听Cry事件,以及如何理Cry事件,它只是告诉环境Cry事件发生了
//通俗的解释是:猫叫了,但猫并不知道它的叫声对环境有什么影响
public class Cat
{
//定义一个事件,表示猫叫
public static event CryEventHandler Cry;
//猫的描述信息
private string description;
public string Description
{
get { return description; }
set { description = value; }
}
public Cat(string description)
{
this.description = description;
Console.WriteLine("Cat:" + this.description + " coming.");
}
public virtual void OnCry()
{
Console.WriteLine("Cat:MiaoMiao");
//将事件的发送者和事件信息作为参数传递给事件处理函数
CryEventArgs e = new CryEventArgs();
e.Description = this.description;
if (Cry != null)
{
Cry(this, e);
}
}
}
//Mouse类是事件的订阅者,定义了Cry事件发生时的处理方法Run()
//通俗的解释是:老鼠在夜间行动时,时刻都在堤防着猫,如果听到猫叫声马上离开
public class Mouse
{
public Mouse()
{
Cat.Cry += new CryEventHandler(Run);
Console.WriteLine("Mouse:I go to find something,and I must always listen cat's crying.");
}
//老鼠听到猫叫声,会先判断是哪种猫,然后再采取下一步行动
public void Run(object sender, CryEventArgs e)
{
string catDescription = e.Description;
//注释掉的这句效果是一样的
//string catDescription = ((Cat)sender).Description;
if (catDescription.Equals("aBenCat"))
{
Console.WriteLine("Mouse:" + catDescription + ",I am not afraid!");
}
else
{
Console.WriteLine("Mouse:" + catDescription + ",I must run!");
}
}
}
public class Demo2
{
public static void Main(string[] args)
{
Mouse mouse = new Mouse();
Cat cat1 = new Cat("aBenCat");
cat1.OnCry();
Cat cat2 = new Cat("smartCat");
cat2.OnCry();
Console.ReadLine();
}
}
运行后控制台输出为:
Mouse:I go to find something,and I must always listen cat's crying.
Cat:aBenCat coming.
Cat:MiaoMiao...
Mouse:aBenCat,I am not afraid!
Cat:smartCat coming.
Cat:MiaoMiao...
Mouse:smartCat,I must run!
通过上面的两个示例可以看到,事件的本质是委托,事件发生时,会去执行通过委托指定的回调函数,但回调函数不是由事件的发生者指定,而是由事件的订阅者来指定的,这就形成了一种松耦合关系。
事件和委托的关系让人迷惑,感觉是因为.NET中定义的事件多是由系统自动触发的,而不是像上面的例子在Main函数中调用了Cat.OnCry()方法。如System.Web.UI.Button类的Click事件,我们只要在客户端点击Button就自动触发了Click事件,并没有在Page类调用Button.OnClick()方法,实际上也不可以调用,因为该方法的访问权限是portected。但我们仔细研究Button类不难发现,当单击按钮时,处理窗体回发事件的RaisePostBackEvent()方法就会执行(感兴趣的朋友可以进一步研究为什么会执行),在Button类就是在这个方法中调用了OnClick方法。下面给出Button类中和Click事件相关的代码:
//定义一个委托
public delegate void EventHandler(object sender, EventArgs e);
//Button类实现,省略了与Click事件无关的代码
public class Button : WebControl, IButtonControl, IPostBackEventHandler
{
//用作委托列表的关键字
private static readonly object EventClick;
static Button()
{
EventClick = new object();
}
//添加或移除事件处理程序
public event EventHandler Click
{
add
{
base.Events.AddHandler(EventClick, value);
}
remove
{
base.Events.RemoveHandler(EventClick, value);
}
}
//protected表明只能是自己或子类调用,不允许其它类调用
protected virtual void OnClick(EventArgs e)
{
EventHandler handler = (EventHandler)base.Events[EventClick];
if (handler != null)
{
handler(this, e);
}
}
//处理窗体发送给服务器时引发的事件,即Click事件
protected virtual void RaisePostBackEvent(string eventArgument)
{
base.ValidateEvent(this.UniqueID, eventArgument);
if (this.CausesValidation)
{
this.Page.Validate(this.ValidationGroup);
}
//EventArgs.Empty表示没有事件数据的事件,等同于EventArgs类的构造函数
this.OnClick(EventArgs.Empty);
}
}
(责任编辑:admin) |