如何:订阅和取消订阅事件(C# 编程指南)How to: Subscribe to and Unsubscribe from Events (C# Programming Guide)

如果想编写引发事件时调用的自定义代码,则可以订阅由其他类发布的事件。You subscribe to an event that is published by another class when you want to write custom code that is called when that event is raised. 例如,可以订阅某个按钮的 click 事件,以使应用程序在用户单击该按钮时执行一些有用的操作。For example, you might subscribe to a button's click event in order to make your application do something useful when the user clicks the button.

使用 Visual Studio IDE 订阅事件To subscribe to events by using the Visual Studio IDE

  1. 如果看不到“属性”窗口,请在“设计”视图中,右键单击要为其创建事件处理程序的窗体或控件,然后选择“属性” 。If you cannot see the Properties window, in Design view, right-click the form or control for which you want to create an event handler, and select Properties.

  2. 在“属性”窗口的顶部,单击“事件”图标 。On top of the Properties window, click the Events icon.

  3. 双击要创建的事件,例如 Load 事件。Double-click the event that you want to create, for example the Load event.

    Visual C# 会创建一个空事件处理程序方法,并将其添加到你的代码中。Visual C# creates an empty event handler method and adds it to your code. 或者,也可以在“代码”视图中手动添加代码 。Alternatively you can add the code manually in Code view. 例如,下面的代码行声明了一个在 Form 类引发 Load 事件时调用的事件处理程序方法。For example, the following lines of code declare an event handler method that will be called when the Form class raises the Load event.

    private void Form1_Load(object sender, System.EventArgs e)
    {
        // Add your form load event handling code here.
    }
    

    还会在项目的 Form1.Designer.cs 文件的 InitializeComponent 方法中自动生成订阅该事件所需的代码行。The line of code that is required to subscribe to the event is also automatically generated in the InitializeComponent method in the Form1.Designer.cs file in your project. 该代码行类似于:It resembles this:

    this.Load += new System.EventHandler(this.Form1_Load);  
    

以编程方式订阅事件To subscribe to events programmatically

  1. 定义一个事件处理程序方法,其签名与该事件的委托签名匹配。Define an event handler method whose signature matches the delegate signature for the event. 例如,如果事件基于 EventHandler 委托类型,则下面的代码表示方法存根:For example, if the event is based on the EventHandler delegate type, the following code represents the method stub:

    void HandleCustomEvent(object sender, CustomEventArgs a)  
    {  
       // Do something useful here.  
    }  
    
  2. 使用加法赋值运算符 (+=) 来为事件附加事件处理程序。Use the addition assignment operator (+=) to attach your event handler to the event. 在下面的示例中,假设名为 publisher 的对象拥有一个名为 RaiseCustomEvent 的事件。In the following example, assume that an object named publisher has an event named RaiseCustomEvent. 请注意,订户类需要引用发行者类才能订阅其事件。Note that the subscriber class needs a reference to the publisher class in order to subscribe to its events.

    publisher.RaiseCustomEvent += HandleCustomEvent;  
    

    请注意,前面的语法是 C# 2.0 中的新语法。Note that the previous syntax is new in C# 2.0. 此语法完全等效于必须使用 new 关键字显式创建封装委托的 C# 1.0 语法:It is exactly equivalent to the C# 1.0 syntax in which the encapsulating delegate must be explicitly created by using the new keyword:

    publisher.RaiseCustomEvent += new CustomEventHandler(HandleCustomEvent);  
    

    还可以通过使用 lambda 表达式添加事件处理程序:An event handler can also be added by using a lambda expression:

    public Form1()  
    {  
        InitializeComponent();  
        // Use a lambda expression to define an event handler.  
        this.Click += (s,e) => { MessageBox.Show(  
           ((MouseEventArgs)e).Location.ToString());};  
    }  
    

    有关详细信息,请参阅如何:在 LINQ 外部使用 Lambda 表达式For more information, see How to: Use Lambda Expressions Outside LINQ.

使用匿名方法订阅事件To subscribe to events by using an anonymous method

  • 如果以后不必取消订阅某个事件,则可以使用加法赋值运算符 (+=) 将匿名方法附加到此事件。If you will not have to unsubscribe to an event later, you can use the addition assignment operator (+=) to attach an anonymous method to the event. 在下面的示例中,假设名为 publisher 的对象拥有一个名为 RaiseCustomEvent 的事件,并且还定义了一个 CustomEventArgs 类以承载某些类型的专用事件信息。In the following example, assume that an object named publisher has an event named RaiseCustomEvent and that a CustomEventArgs class has also been defined to carry some kind of specialized event information. 请注意,订户类需要引用 publisher 才能订阅其事件。Note that the subscriber class needs a reference to publisher in order to subscribe to its events.

    publisher.RaiseCustomEvent += delegate(object o, CustomEventArgs e)  
    {  
      string s = o.ToString() + " " + e.ToString();  
      Console.WriteLine(s);  
    };  
    

    请务必注意,如果使用匿名函数订阅事件,事件的取消订阅过程将比较麻烦。It is important to notice that you cannot easily unsubscribe from an event if you used an anonymous function to subscribe to it. 这种情况下若要取消订阅,必须返回到该事件的订阅代码,将该匿名方法存储在委托变量中,然后将此委托添加到该事件中。To unsubscribe in this scenario, it is necessary to go back to the code where you subscribe to the event, store the anonymous method in a delegate variable, and then add the delegate to the event. 一般来说,如果必须在后面的代码中取消订阅某个事件,则建议不要使用匿名函数订阅此事件。In general, we recommend that you do not use anonymous functions to subscribe to events if you will have to unsubscribe from the event at some later point in your code. 有关匿名函数的详细信息,请参阅匿名函数For more information about anonymous functions, see Anonymous Functions.

取消订阅Unsubscribing

若要防止在引发事件时调用事件处理程序,请取消订阅该事件。To prevent your event handler from being invoked when the event is raised, unsubscribe from the event. 为了防止资源泄露,应在释放订户对象之前取消订阅事件。In order to prevent resource leaks, you should unsubscribe from events before you dispose of a subscriber object. 在取消订阅事件之前,在发布对象中作为该事件的基础的多播委托会引用封装了订户的事件处理程序的委托。Until you unsubscribe from an event, the multicast delegate that underlies the event in the publishing object has a reference to the delegate that encapsulates the subscriber's event handler. 只要发布对象保持该引用,垃圾回收功能就不会删除订户对象。As long as the publishing object holds that reference, garbage collection will not delete your subscriber object.

取消订阅事件To unsubscribe from an event

  • 使用减法赋值运算符 (-=) 取消订阅事件:Use the subtraction assignment operator (-=) to unsubscribe from an event:

    publisher.RaiseCustomEvent -= HandleCustomEvent;  
    

    所有订户都取消订阅事件后,发行者类中的事件实例将设置为 nullWhen all subscribers have unsubscribed from an event, the event instance in the publisher class is set to null.

请参阅See also