事件揭秘

    趁着对委托的熟悉,我们就弄清楚事件吧,如果您还对委托不太了解,可以参考下这篇文章

    可能大多数人不太怎么关心事件是怎么形成的,只管一个控件上注册一个事件,然后再cs文件中填写相应该事件的代码,那么您如果想了解该方面的内容,希望本文对您有帮助。

   事件允许进行一种交互。其实事件是作为类型的成员。定义一个事件成员意味着类型就为我们提供了三种能力。

    *类型的静态方法或者对象的实例方法可以订阅类型事件。

    *类型的静态方法或者对象的实例方法可以注销类型事件。

    *事件发生时通知已订阅事件的方法

     定义一个对外提供一个或者多个事件的类型,需要遵循以下四个步骤。

  

一.定义一个用于存放所有需要发送给事件通知接收者的附加信息

    按照约定所有传递给事件处理程序的用于存放事件信息的类都该继承System.EventArgs,并且该类的名称以EventArgs结束。(通常包含一组私有字段以及一些对外提供这些字段的只读的公共属性  

代码
internal class NewmailEventArgs:EventArgs
{
   
private readonly String m_from,m_to,m_subject;
 
   
public NewMailEventArgs(String from,String to,String subject)
   {
      m_from
=from;
      m_to
=to;
      m_subject
=subject;
   } 
   
   
public String From {get {return m_from;}}
   
public String To   {get {return m_to;}}
   pulbic String Subject {
get {return m_subject;}}
}

 二.定义事件成员

    事件成员用 event 定义。

internal class MailManager
{
   
public event EventHandler<NewMailEventArgs> NewMail;
   ....
}

 NewMail是事件名称。事件成员类型是EventHandler<NewMailEventArgs>,其含义为所有事件通知的接收者都必须提供一个原型和EventHandler<NewMailEventArgs>委托类相匹配的回调方法。泛型System.EventHandler委托类型的定义如下:

public delegate void EventHandler<TEventArgs>(Object sender,TEventArgs e)Where TEventArgs:EventArgs;

因此方法原型必须是:

 这里我真是醍醐灌顶,这就是为什么我们总是在cs文件中看到事件定义总是是那样的(例: protected void Page_Load(object sender, EventArgs e), protected void btnOK_Click(object sender, EventArgs e))这里因为继承的缘故,该模式中要求sender参数类型为Object。

void MethodName(Object sender,NewMailEventArgs e);

 

 三.定义一个负责引发事件的方法来通知已订阅事件的对象事件已经发生

按照约定,类型定义一个受保护的虚方法,当引发事件时,这个类及其派生类中的代码可以调用这个虚方法。该方法有一个参数,即NewmailEventArgs对象。

代码
interanl class MailManager
{
   
protected virtual void OnNewMial(NewMailEventArgs e)
   {
      EventHandler
<NewMailEventArgs> temp=NewMail;
      
//通知所有已订阅事件对象
       if(temp!=null)temp(this,e);
   }
   .....
}

   

四.定义一个方法,将输入转化为期望事件

在定义类中,必须将一些方法可以将外部输入转化为引发事件的动作。

代码
internal class NewMail
{
  
public void SimulateNewMail(String from,String to,String object)
  {
     
//构建一个对象来存放我们希望传送给通知接收者的信息
     NewMailEventArgs e=new NewmailEventArgs(from,to,suject);
    
    
//调用虚方法以通知对象事件已经发生
     
//如果没有重写改方法,那么该对象通知所有订阅该事件的对象
     OnNewMial(e);
  }
}

那么一个事件完整的设计为

代码
internal class NewmailEventArgs:EventArgs
{
   
private readonly String m_from,m_to,m_subject;
 
   
public NewMailEventArgs(String from,String to,String subject)
   {
      m_from
=from;
      m_to
=to;
      m_subject
=subject;
   } 
   
   
public String From {get {return m_from;}}
   
public String To   {get {return m_to;}}
   pulbic String Subject {
get {return m_subject;}}
}

//声明一个委托
public delegate void EventHandler<TEventArgs>(Object sender,TEventArgs e)Where TEventArgs:EventArgs;

internal class MailManager
{
   
//一个事件实例
   public event EventHandler<NewMailEventArgs> NewMail;
  
   
   
protected virtual void OnNewMial(NewMailEventArgs e)
   {
      EventHandler
<NewMailEventArgs> temp=NewMail;
      
//通知所有已订阅事件对象 注意这里用的委托通知订阅事件的对象
       if(temp!=null)temp(this,e);
   }
   
   
public void SimulateNewMail(String from,String to,String object)
  {
     
//构建一个对象来存放我们希望传送给通知接收者的信息
     NewMailEventArgs e=new NewmailEventArgs(from,to,suject);
    
    
//调用虚方法以通知对象事件已经发生
     
//如果没有重写改方法,那么该对象通知所有订阅该事件的对象
     OnNewMial(e);
  }

}

" public event EventHandler<NewMailEventArgs> NewMail;"在编译器中会把它翻译为3个构造: 

代码
//1.一个初始化为null的委托私有字段
private EventHandler<NewMailEventArgs> NewMail=null;

//2.一个允许对象订阅事件的公共方法add_name
[MethodImpl(MethodImplOptions.Synchronized)]
public void add_NewMail(EventHandler<NewMailEventArgs>value)
{
    NewMail
=(EventHandler<NewMailEventArgs>)Delegate.Conbine(NewMail,value);
}

//一个允许对象注销事件的公共方法remove_name
[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_NewMail(EventHandler<NewMailEventArgs>value)
{
    NewMail
=(EventHandler<NewMailEventArgs>)Delegate.Remove(NewMail,value);
}

 当有方法订阅事件时,该字段就会指向一个EventHandler<NewMailEventArgs>委托实例,当监听者订阅了事件时,它只需要将委托类型实例添加到该委托类的链表即可。注销道理一样。

 

现在我们看一个例子,是一个提交类型按钮,这个按钮类型为submit,所以当点击其按钮时,其本身已经可以提交事件到服务器。

代码
代码
//声明一个委托
[SerializableAttribute] 
[ComVisibleAttribute(
true)] 
public delegate void EventHandler (Object sender,EventArgs e)

[DefaultEvent(
"Click")]
[toolboxData(
"<{0}:PostBackEventControl runat=server></{0}:PostBackEventControl>")]
public class PostBackEventControl:Control,IPostBackEventHandler
{
   
//事件名称 编译器其实这里实行3个构造
   public event EventHanlder Click;
   
   
//定义一个负责引发事件的方法来通知已订阅事件的对象事件已经发生
   protected virtual void OnClick(EventArgs e)
   {
      
if(Click!=null)
      {
         
//是通知订阅对象(其实这里就是调用了服务器一个方法)
         Click(this.e);
      }
   }
   
   
//触发事件
   public void RaisePostBackEvent(string eventArgument)
   {
      
//因为这里没有额外的信息传递所以赋空值
      OnClick(EventArgs.Empty);
   }
   
   Protected overrrid 
void Render(HtmlTextWriter output)
   {
      output.Write(
"<INPUT TYPE=submit name="+this.UniqueID+"Value='单击我'/>");
   }
}

注意RaisePostBackEvent(若要有该函数需要实现IPostBackEventHandler接口)需要被客户端触发才能执行。因为这里如果按钮被点击了框架会自动调用该函数(详细请点击这里

 相信大家多多少少有点明白事件是怎么一个过程了吧。

 

posted @ 2010-04-13 14:02  胡佳180815  阅读(2118)  评论(5编辑  收藏  举报