c#中事件处理

注:这是一篇译自msdn英文版的文章,译完之后才发现中文版的msdn中已经翻译完了。唉,就当练英语了。

   这个指南向你展示在C#中怎样声明、调用和关连(hook up)事件(Event.

   在C#中,当一个类发生了某个对象感兴趣的事情的时候,那么就会提供一个事件,把发生的事情通知给使用这个类的对象。它和图形用户接口中使用的事件非常相似,典型的,在可视的控件的类的接口中,当用户对这些控件做了某些操作的时候,都会向这个控件发出通知事件,如点击一个按钮(button)。

但是,事件不仅仅在图形用户接口中使用,事件(Events)为对象提供了一种普通的方法,把这个对象的状态的变化以信号的方式发送给它的使用者。事件对于创建能够在不同程序间可复用的代码非常重要。

   事件是使用委托(delegates)来声明的,如果你没有学习过委托,那么开始学习下面的内容之前,需要先学习有关委托的内容(注:关于委托可以参考msdn中委托指南中的讲解,http://msdn.microsoft.com/en-us/library/aa288459(VS.71).aspx)。一个委托封装了一个回调方法,以便它能够被匿名调用。对于类来说,事件允许把这个类的使用者的一些方法(Method)委托给它,在类的事件发生的时候,那些被委托的方法将会被调用。也就是说,在类的事件发生时,会调用类的使用者所委托的方法。

   在这篇指南中除了提供事件的声明、调用和关连的例子以外,还对下列标题进行了介绍。

   ・     事件和继承

   ・     接口中的事件

   ・     .NET Framework 标准

1

   下面是一个简单的例子,类ListWithChangedEvent与标准的ArrayList类相似,每当List中的内容发生改变时,Changed事件就会被调用触发。像这样通用的类能够被很多程序中大多数方法使用。

   例如,一个文字处理器,可能维护打开的文档的列表,每当这个列表的内容发生变化时,在这个文字处理器中的很多不同的对象可能都需要被通知到,以便用户接口能够被更新。通过使用事件,维护文档列表的List不必知道谁需要被通知(在列表内容发生变化时),事件会自动的调用并且把当前的变化通知给每个需要的对象。通过使用事件,程序的模块化被增强了。

  1. // events1.cs
  2. using System;
  3. namespace MyCollections 
  4. {
  5.    using System.Collections;
  6.    // A delegate type for hooking up change notifications.
  7.    public delegate void ChangedEventHandler(object sender, EventArgs e);

  8.    // A class that works just like ArrayList, but sends event
  9.    // notifications whenever the list changes.
  10.    public class ListWithChangedEvent: ArrayList 
  11.    {
  12.       // An event that clients can use to be notified whenever the
  13.       // elements of the list change.
  14.       public event ChangedEventHandler Changed;

  15.       // Invoke the Changed event; called whenever list changes
  16.       protected virtual void OnChanged(EventArgs e) 
  17.       {
  18.          if (Changed != null)
  19.             Changed(this, e);
  20.       }

  21.       // Override some of the methods that can change the list;
  22.       // invoke event after each
  23.       public override int Add(object value) 
  24.       {
  25.          int i = base.Add(value);
  26.          OnChanged(EventArgs.Empty);
  27.          return i;
  28.       }

  29.       public override void Clear() 
  30.       {
  31.          base.Clear();
  32.          OnChanged(EventArgs.Empty);
  33.       }

  34.       public override object this[int index] 
  35.       {
  36.          set 
  37.          {
  38.             base[index] = value;
  39.             OnChanged(EventArgs.Empty);
  40.          }
  41.       }
  42.    }
  43. }

  44. namespace TestEvents 
  45. {
  46.    using MyCollections;

  47.    class EventListener 
  48.    {
  49.       private ListWithChangedEvent List;

  50.       public EventListener(ListWithChangedEvent list) 
  51.       {
  52.          List = list;
  53.          // Add "ListChanged" to the Changed event on "List".
  54.          List.Changed += new ChangedEventHandler(ListChanged);
  55.       }

  56.       // This will be called whenever the list changes.
  57.       private void ListChanged(object sender, EventArgs e) 
  58.       {
  59.          Console.WriteLine("This is called when the event fires.");
  60.       }

  61.       public void Detach() 
  62.       {
  63.          // Detach the event and delete the list
  64.          List.Changed -= new ChangedEventHandler(ListChanged);
  65.          List = null;
  66.       }
  67.    }

  68.    class Test 
  69.    {
  70.       // Test the ListWithChangedEvent class.
  71.       public static void Main() 
  72.       {
  73.       // Create a new list.
  74.       ListWithChangedEvent list = new ListWithChangedEvent();

  75.       // Create a class that listens to the list's change event.
  76.       EventListener listener = new EventListener(list);

  77.       // Add and remove items from the list.
  78.       list.Add("item 1");
  79.       list.Clear();
  80.       listener.Detach();
  81.       }
  82.    }
  83. }

  84. 输出:
  85. This is called when the eventfires.
  86. This is called when the eventfires.

  代码讨论:

  ・     声明事件。要在一个类的内部声明一个事件,首先必须声明一个委托(delegate)类型。

  代码中声明如下:

  public delegate void ChangedEventHandler(object sender,EventArgs e);

  委托(delegate)类型定义了一个传递给处理事件的方法的参数集,多个事件能够共享相同的委托类型,因此确认是否有合适的委托类型被声明是必要的步骤。

  接下来是事件自身的声明。

  代码中声明如下:

  public event ChangedEventHandler Changed;

  事件的声明就像一个委托类型的字段,在事件声明的关键字event之前,要有访问修饰关键字。事件通常被声明为public类型,但是其他的任意可访问的修饰词也是被允许的。

  ・用事件。一旦声明了一个事件,那它能理委托型的字段一样处理事件。如果没有使用者把委托接到个事件上,那么这个字段的null,则这个字段会指向事件时应该用的委托,用一个事件通常首先要检查这个字段的是否是null,然后再个事件。如下

if(Changed != null)

Changed(this, e)

注:只能从声明事件的类的内部来调用一个事件。

   ・关连事件(Hooking up to an event)。从声明事件的类的外部,一个事件看起来就像一个类的字段,但是访问这个字段是受到限制的,只有下面的事情可以做:

  1、  把新的委托关联到这个字段

  2、  从这个字段中把委托删除

 关联和删除委托时,可以使用+=-=操作符,要开始接受事件的请求,客户代码首先要创建事件类型委托所要引用的方法,这个方法应该由事件来调用,然后使用+=操作符把委托关联的事件字段上。如下面的代码。

 // Add "ListChanged" to the Changed event on "List":

 List.Changed += new ChangedEventHandler(ListChanged); 

 当客户代码完成了接收事件的请求时,可以使用-=操作符把委托从事件的关连中删除。如下记代码:

 // Detach the event and delete the list:

 List.Changed -= new ChangedEventHandler(ListChanged);

 

事件和继承(Events and Inheritance

  当创建一个通用的可以被继承的组件时,有些时候事件的继承似乎成为问题,尽管有些时候是希望给派生类适当的自由调用事件的能力,但是因为事件只能在声明它们的类的内部调用触发,派生类不能直接调用在基类中声明的事件。典型的可以通过在基类中创建protected类型的触发事件的方法来达到在派生类中调用的目的。为了使事件更灵活,触发事件的方法经常被声明成virtual类型的,允许派生类重写这个方法,这样就可以截获基类正在触发的事件,从而使得派生类能够在事件中做自己处理。

接口中的事件(Events in Interfaces

  事件和类字段之间的另一个不同点是,事件可以被放到接口中,而类字段不可以。当实现一个接口的时候,实现接口的类必须在实现类中提供相应的事件。

.Net Framework 标准(.NET Framework Guidelines

  尽管c#语言的事件允许使用任意的委托类型,但是.Net Framework对于事件所使用的委托类型有更严格的要求,如果打算把组件放到.Net Framework中使用,就需要了解下面的标准。

.Net Framework标准指出,用于事件的委托应该有两个参数,一个是对象源(object source参数,用于指示事件的发生源(即事件是谁触发的),另一个是”e”参数,它可以封装任意其他的关于事件的信息,”e”类型的参数应该继EventArgs类,对于不使用额外的其他信息的事件,.Net Framework已经定义了一个适当的委托类型:EventHandler

2

  下面的例子是按照.Net Framework的标准对例1修正后的版本,这个例子中使用了EventHandler委托类型。

  1. EventHandler委托类型。
  2. // events2.cs
  3. using System;
  4. namespace MyCollections 
  5. {
  6.    using System.Collections;

  7.    // A class that works just like ArrayList, but sends event
  8.    // notifications whenever the list changes:
  9.    public class ListWithChangedEvent: ArrayList 
  10.    {
  11.       // An event that clients can use to be notified whenever the
  12.       // elements of the list change:
  13.       public event EventHandler Changed;

  14.       // Invoke the Changed event; called whenever list changes:
  15.       protected virtual void OnChanged(EventArgs e) 
  16.       {
  17.          if (Changed != null)
  18.             Changed(this,e);
  19.       }

  20.       // Override some of the methods that can change the list;
  21.       // invoke event after each:
  22.       public override int Add(object value) 
  23.       {
  24.          int i = base.Add(value);
  25.          OnChanged(EventArgs.Empty);
  26.          return i;
  27.       }

  28.       public override void Clear() 
  29.       {
  30.          base.Clear();
  31.          OnChanged(EventArgs.Empty);
  32.       }

  33.       public override object this[int index] 
  34.       {
  35.          set 
  36.          {
  37.             base[index] = value;
  38.             OnChanged(EventArgs.Empty);
  39.          }
  40.       }
  41.    }
  42. }

  43. namespace TestEvents 
  44. {
  45.    using MyCollections;

  46.    class EventListener 
  47.    {
  48.       private ListWithChangedEvent List;

  49.       public EventListener(ListWithChangedEvent list) 
  50.       {
  51.          List = list;
  52.          // Add "ListChanged" to the Changed event on "List":
  53.          List.Changed += new EventHandler(ListChanged);
  54.       }

  55.       // This will be called whenever the list changes:
  56.       private void ListChanged(object sender, EventArgs e) 
  57.       {
  58.          Console.WriteLine("This is called when the event fires.");
  59.       }

  60.       public void Detach() 
  61.       {
  62.          // Detach the event and delete the list:
  63.          List.Changed -= new EventHandler(ListChanged);
  64.          List = null;
  65.       }
  66.    }

  67.    class Test 
  68.    {
  69.       // Test the ListWithChangedEvent class:
  70.       public static void Main() 
  71.       {
  72.       // Create a new list:
  73.       ListWithChangedEvent list = new ListWithChangedEvent();

  74.       // Create a class that listens to the list's change event:
  75.       EventListener listener = new EventListener(list);

  76.       // Add and remove items from the list:
  77.       list.Add("item 1");
  78.       list.Clear();
  79.       listener.Detach();
  80.       }
  81.    }
  82. }
  83. 输出:
  84. This is called when the event fires.
  85. This is called when the event fires.









 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值