委托和事件

 
点击提交按钮、在窗体内移动鼠标、按下回车键、在I/O端口接收一个字符,这些都是事件(event),它们常常触发程序中一个或多个特殊事件处理例程(event handling routine)调用。
在.NET中事件实际上是类成员,与成员属性和方法一样。FCL中几乎每个类都有事件成员。
 
委托
将事件与处理方法关联起来的是委托对象(delegate object)。该对象维护着事件发生时要调用的方法列表。
声明:
public   delegate   void  Mystring ( string  msg);

声明委托时,C#编译器会创建一个sealed(密封)类,并以委托标识符(MyString)命名。该类定义了一个构造函数,它接收方法(可以是静态方法或实例方法)名作为其一个参数。该类还包含另外一些方法,以支持委托维护目标方法列表。这意味着,不同回调法。一个委托可以调用多个事件处理方法。
方法必须向委托注册,以便委托能调用这个方法。只有无返回值而且接受一个字符串参数的方法才能像这个委托注册。调用委托时,他会遍历其内部调用列表,并按照方法的注册顺序调用所有的注册方法。调用多个方法的过程称为组播(multicastring)。
组播委托
class  DelegataClass
{
    
public   delegate   void  MyString( string  s);
    
public   static   void  PrintLower( string  s)
    {
        Console.WriteLine(s.ToLower());
    }
    
public   static   void  PrintUpper( string  s)
    {
        Console.WriteLine(s.ToUpper());
    }

    
public   static   void  Main()
    {
        MyString MyDel;
        
// regester method to be called by delegate
        MyDel  =   new  MyString(PrintLower);
        MyDel 
+=   new  MyString(PrintUpper);
        MyDel(
" Happy birthday " );
    }
}
 
输出:
happy birthday
HAPPY BIRTHDAY 
   

注意,+=操作符用于向调用列表增加方法。相反地,可以使用-=来从操作符中删除方法。

前面的示例中委托同步的调用每一个方法,这说明,只要有前一个方法完成操作,才会调用后面的方法。这可能存在两个问题:某个方法可能被“挂起”,永远不返回控制,或是需要长时间来处理。它们都将阻塞整个系统的运用。为了解决这个问题.NET允许委托对方法执行异步调用。在这种情况下,被调用的方法与调用的方法将在不同的线程中运行,这样一来,调用方法能通过轮询来确定被调用方法何时结束,或者让被调用方法在完成时回调一个方法。

 
基于委托的事件处理
抽象的讲,.NET的事件模型基于贯彻者模式(Observer Design Pettern)。这个模式定义为“对象间存在一对多依赖关系,一个对象改变状态时,依赖此的所有对象都能得到通知并自动更新”。
  •   处理内置事件
MouseEventDown MouseEventHandler 都是FCL中与定义的。只需要实现事件处理程序,并向委托注册即可。
+= 操作符用于注册与事件相关的方法。
MouseEventDown  += new  MouseEventHandler(onMouseDown);
该语句的基本结构是:
this . event   +=   new   delegate (envet handler method);
要实现事件的处理程序,就必须提供委托定义的签名。在描述MouseEventHandler委托声明的文档中可以找到该签名。
 
public   delegate   void  MouseEventHandler( object  sender,MonthChangedEventArgs e)
  •   使用匿名方法和委托
.NET2.0 引入了一种称为匿名方法(anmoymous method) 的语言构造,有了匿名方法,就不需要单独的事件处理方法;相反,事件处理代码封装在委托代中。
this .MouseDown  +=   new  MouseEventHandler(OnMouseDown);
替换为下面的语句,这条语句会创建一个委托,其中包含调用委托时要执行的代码。
this .MouseDown  +=   delegate ( object  sender,EventArgs e)
{
lastX
= e.X;
lastY
= e.Y;
}
这个取代OnMouseDown的代码块不需要方法名,故称为匿名方法。其语法如下:
delegate  [(parameter - list)]{anonymose - method - block}
  •    关键字delegate放在调用委托时要执行的代码前面。
  •    参数列表(可选)用于像代码块传递数据。参数必须与委托声明的的参数相匹配。
  •    当C#编译器遇到匿名代码块时,将创建一个新,并在其中建立一个方法包含这个代码块。调用委托时会调用此方法。
public   class  TestDelegeteClass
{
    
// delegate declaretion
     public   delegate   void  MyString ( string  s);
    
public   static   void  Main()
    {
        
// register two anonymose methods with the delegate
        MyString myDel;
        myDel 
=   delegate ( string  s) { Console.WriteLine(s.ToLower()); };
        myDel 
=   + delegate ( string  s) { Console.WriteLine(s.ToUpper()); };

        
// invoke delegate 
        myDel( " My Name is Jiero " );
    }
}

 
调用委托时,它执行两个匿名方法中的代码,其结果就是将输入字符串分别全大写和全小写输出。

 

 
  •    定义委托来处理事件
委托签名应当定义一个void返回类型,而且要由Object和EventArgs类型的参数。sender参数用来标识事件发布者,这样客户就可以使用一个方法来处理和识别源于多方的事件。
.NET 提供了EventArgs类作为保存参数列表的泛型容器。这样做有几个好处,最重要的就是它使事件处理方法与事件发布者就诶出耦合。
要创建一个EventArgs类型用作参数,需要定义一个继承自EventArgs的新类。下面的例子中包含了一个string成员属性。这个成员属性的值在触发事件之前设置,在该事件中将把这个成员属性作为一个参数。

public   class  IOEventArgs : EventArgs
{
    
private   string  eventMsg;
    
public  IOEventArgs( string  msg){
        
this .eventMsg  =  msg;
    }
    
public   string  Msg{
        
get  {  return  eventMsg; }
    }
}

  •    它必须继承与EventArgs类。
  •    类名应当以EventArgs结尾。
  •    参数要定义为只读(readonly)字段或成员属性。
  •    使用构造函数来初始化值。
如果事件不生成数据,就没有必要创建一个类来作为EventArgs参数。而只需要简单的传递。EventArgs.Empty即可。
 
如果委托使用了EventHandler签名,可将Eventhandler用作委托,而不用创建你自己的委托。这是应为,EventHandler是.NET FCL的一部分,无需声明。
  •    定义定制事件
在编写自己的类时,常常要定义定制事件,在某些状态发生时发出通知。使用event关键字来指定委托,该委托将在事件发生时调用。
class  Class1
{
    
public   delegate   void  UserRequest( object  sender, EventArgs e);  // 定义委托
     public   event  UserRequest OnUserRequest;  // 定义一个委托类型的事件

    
public   void  run()
    {
        
while  ( true )
        {
            
if  (Console.ReadLine()  ==   " a " )
            {
// 事件监听
                OnUserRequest( this new  EventArgs());  // 产生事件
            }
        }
    }
}

class  Class2
{
    
static   void  Main( string [] args)
    {
        Class1 c1 
=   new  Class1();
        c1.OnUserRequest 
+=   new  Class1.UserRequest(c1_OnUserRequest);  // 委托实例化后绑定到事件
        c1.run();
    }

    
private   static   void  c1_OnUserRequest( object  sender, EventArgs e)
    {
// 事件处理方法
        Console.WriteLine( " 你触发了事件! " );
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值