• 如何在.NET自定义控件中实现自己的事件(转)


    事件教程
    本教程展示如何在 C# 中声明事件、调用事件和挂接到事件。
     
    示例文件
    请参见“事件”示例以下载和生成本教程中所讨论的示例文件。
     
    其他阅读材料
    event
    delegate
    处理和引发事件
    委托教程
    Windows 窗体中事件处理程序的介绍
    教程
    C# 中的“事件”是当对象发生某些有趣的事情时,类向该类的客户提供通知的一种方法。事件最常见的用途是用于图形用户界面;通常,表示界面中的控件的类具有一些事件,当用户对控件进行某些操作(如单击某个按钮)时,将通知这些事件。
     
    但是事件未必只用于图形界面。事件为对象提供一种通常很有用的方法来发出信号表示状态更改,这些状态更改可能对该对象的客户很有用。事件是创建类的重要构造块,这些类可在大量的不同程序中重复使用。
     
    使用委托来声明事件。如果您尚未学习“委托教程”,您应先学习它,然后再继续。请回忆委托对象封装一个方法,以便可以匿名调用该方法。事件是类允许客户为其提供方法(事件发生时应调用这些方法)的委托的一种方法。事件发生时,将调用其客户提供给它的委托。
     
    除声明事件、调用事件和与事件挂钩的示例以外,本教程还介绍下列主题:
     
    事件和继承
    接口中的事件
    .NET Framework 指南
    示例 1
    下面的简单示例展示一个 ListWithChangedEvent 类,该类类似于标准的 ArrayList 类,而且,每当列表内容更改时,该类均调用 Changed 事件。这样一个通用用途的类可在大型程序中以多种方式使用。
     
    例如,某字处理器可能包含打开的文档的列表。每当该列表更改时,可能需要通知字处理器中的许多不同对象,以便能够更新用户界面。使用事件,维护文档列表的代码不需要知道需要通知谁,一旦文档列表发生了更改,将自动调用该事件,正确通知每个需要通知的对象。使用事件提高了程序的模块化程度。

    // events1.cs
    using System;
    namespace MyCollections 
    {
       
    using System.Collections;

       
    // A delegate type for hooking up change notifications.
       public delegate void ChangedEventHandler(object sender, EventArgs e);

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

          
    // Invoke the Changed event; called whenever list changes
          protected virtual void OnChanged(EventArgs e) 
          
    {
             
    if (Changed != null)
                Changed(
    this, e);
          }


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


          
    public override void Clear() 
          
    {
             
    base.Clear();
             OnChanged(EventArgs.Empty);
          }


          
    public override object this[int index] 
          
    {
             
    set 
             
    {
                
    base[index] = value;
                OnChanged(EventArgs.Empty);
             }

          }

       }

    }


    namespace TestEvents 
    {
       
    using MyCollections;

       
    class EventListener 
       
    {
          
    private ListWithChangedEvent List;

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


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


          
    public void Detach() 
          
    {
             
    // Detach the event and delete the list
             List.Changed -= new ChangedEventHandler(ListChanged);
             List 
    = null;
          }

       }


       
    class Test 
       
    {
          
    // Test the ListWithChangedEvent class.
          public static void Main() 
          
    {
          
    // Create a new list.
          ListWithChangedEvent list = new ListWithChangedEvent();

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

          
    // Add and remove items from the list.
          list.Add("item 1");
          list.Clear();
          listener.Detach();
          }

       }

    }

    输出
    This is called when the event fires.
    This is called when the event fires.
    代码讨论
    声明事件   若要在类内声明事件,首先必须声明该事件的委托类型(如果尚未声明的话)。
    public delegate void ChangedEventHandler(object sender, EventArgs e);
    委托类型定义传递给处理该事件的方法的一组参数。多个事件可共享相同的委托类型,因此仅当尚未声明任何合适的委托类型时才需要执行该步骤。
     
    接下来,声明事件本身。
     
    public event ChangedEventHandler Changed;
    声明事件的方法与声明委托类型的字段类似,只是关键字 event 在事件声明前面,在修饰符后面。事件通常被声明为公共事件,但允许任意可访问修饰符。
     
    调用事件   类声明了事件以后,可以就像处理所指示的委托类型的字段那样处理该事件。如果没有任何客户将委托与该事件挂钩,该字段将为空;否则该字段引用应在调用该事件时调用的委托。因此,调用事件时通常先检查是否为空,然后再调用事件。
    if (Changed != null)
    Changed(this, e);
    调用事件只能从声明该事件的类内进行。
     
    与事件挂钩   从声明事件的类外看,事件像个字段,但对该字段的访问是非常受限制的。只可进行如下操作:
    在该字段上撰写新的委托。
    从字段(可能是复合字段)移除委托。
    使用 += 和 -= 运算符完成此操作。为开始接收事件调用,客户代码先创建事件类型的委托,该委托引用应从事件调用的方法。然后它使用 += 将该委托写到事件可能连接到的其他任何委托上。
     
    // 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);
    事件和继承
    当创建可以从中派生的通用组件时,事件中有时出现似乎会成为问题的情况。由于事件只能从声明它们的类中调用,因此派生类不能直接调用在基类内声明的事件。虽然这有时符合需要,但通常使派生类能够自由调用事件更合适。这通常通过为事件创建受保护的调用方法来实现。通过调用该调用方法,派生类便可以调用此事件。为获得更大的灵活性,调用方法通常声明为虚拟的,这允许派生类重写调用方法。这使得派生类可以截获基类正在调用的事件,有可能对这些事件执行它自己的处理。
     
    在前面的示例中,这已用 OnChanged 方法实现。如果需要,派生类可调用或重写该方法。
     
    接口中的事件
    事件和字段之间的另一个差异是,事件可放在接口中,而字段不能。当实现接口时,实现类必须在实现接口的类中提供相应的事件。
     
    .NET Framework 指南
    尽管 C# 语言允许事件使用任意委托类型,但“.NET Framework”对于应为事件使用的委托类型有一些更严格的指南。如果打算将您的组件与“.NET Framework”一起使用,您可能希望遵守这些指南。
     
    “.NET Framework”指南指示用于事件的委托类型应采用两个参数:指示事件源的“对象源”参数和封装事件的其他任何相关信息的“e”参数。“e”参数的类型应从 EventArgs 类派生。对于不使用其他任何信息的事件,“.NET Framework”已定义了一个适当的委托类型:EventHandler。
     
    示例 2
    下面的示例是“示例 1”的修改版本,它遵守“.NET Framework”指南。该示例使用 EventHandler 委托类型。

    // events2.cs
    using System;
    namespace MyCollections 
    {
       
    using System.Collections;

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

          
    // Invoke the Changed event; called whenever list changes:
          protected virtual void OnChanged(EventArgs e) 
          
    {
             
    if (Changed != null)
                Changed(
    this,e);
          }


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


          
    public override void Clear() 
          
    {
             
    base.Clear();
             OnChanged(EventArgs.Empty);
          }


          
    public override object this[int index] 
          
    {
             
    set 
             
    {
                
    base[index] = value;
                OnChanged(EventArgs.Empty);
             }

          }

       }

    }


    namespace TestEvents 
    {
       
    using MyCollections;

       
    class EventListener 
       
    {
          
    private ListWithChangedEvent List;

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


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


          
    public void Detach() 
          
    {
             
    // Detach the event and delete the list:
             List.Changed -= new EventHandler(ListChanged);
             List 
    = null;
          }

       }


       
    class Test 
       
    {
          
    // Test the ListWithChangedEvent class:
          public static void Main() 
          
    {
          
    // Create a new list:
          ListWithChangedEvent list = new ListWithChangedEvent();

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

          
    // Add and remove items from the list:
          list.Add("item 1");
          list.Clear();
          listener.Detach();
          }

       }

    }

    输出
    This is called when the event fires.
    This is called when the event fires.
  • 相关阅读:
    hdu 1281 棋盘游戏(二分匹配)
    UVA 12545 Bits Equalizer
    算法之匈牙利算法
    I题 hdu 1234 开门人和关门人
    H题 hdu 2520 我是菜鸟,我怕谁
    G题 hdu 1466 计算直线的交点数
    F题 hdu 1431 素数回文
    E题hdu 1425 sort
    D题 hdu 1412 {A} + {B}
    有12个球,外形相同,其中一个小球的质量与其他11个不同,给一个天平,需要几次把这个小球找出来并且求出这个小球是比其他的轻还是重
  • 原文地址:https://www.cnblogs.com/cuihongyu3503319/p/527510.html
Copyright © 2020-2023  润新知