如何:发布符合 .NET Framework 准则的事件(C# 编程指南)How to: Publish Events that Conform to .NET Framework Guidelines (C# Programming Guide)

下面的过程演示了如何将遵循标准 .NET Framework 模式的事件添加到类和结构中。The following procedure demonstrates how to add events that follow the standard .NET Framework pattern to your classes and structs. .NET Framework 类库中的所有事件均基于 EventHandler 委托,定义如下:All events in the .NET Framework class library are based on the EventHandler delegate, which is defined as follows:

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

备注

.NET Framework 2.0 引入了泛型版本的委托 EventHandler<TEventArgs>The .NET Framework 2.0 introduces a generic version of this delegate, EventHandler<TEventArgs>. 下例演示了如何使用这两个版本。The following examples show how to use both versions.

尽管定义的类中的事件可基于任何有效委托类型,甚至是返回值的委托,但一般还是建议使用 EventHandler 使事件基于 .NET Framework 模式,如下例中所示。Although events in classes that you define can be based on any valid delegate type, even delegates that return a value, it is generally recommended that you base your events on the .NET Framework pattern by using EventHandler, as shown in the following example.

发布基于 EventHandler 模式的事件To publish events based on the EventHandler pattern

  1. (如果无需随事件一起发送自定义数据,请跳过此步骤转到步骤 3a。)将自定义数据的类声明为对发布服务器和订阅者类均可见的范围。(Skip this step and go to Step 3a if you do not have to send custom data with your event.) Declare the class for your custom data at a scope that is visible to both your publisher and subscriber classes. 然后添加所需成员以保留自定义事件数据。Then add the required members to hold your custom event data. 在此示例中,将返回一个简单的字符串。In this example, a simple string is returned.

    public class CustomEventArgs : EventArgs  
    {  
        public CustomEventArgs(string s)  
        {  
            msg = s;  
        }  
        private string msg;  
        public string Message  
        {  
            get { return msg; }  
        }   
    }  
    
  2. (如果正在使用泛型版本 EventHandler<TEventArgs>,请跳过此步骤。)声明发布类中的委托。(Skip this step if you are using the generic version of EventHandler<TEventArgs> .) Declare a delegate in your publishing class. 为以 EventHandler 结尾的委托命名。Give it a name that ends with EventHandler. 第二个参数指定自定义 EventArgs 类型。The second parameter specifies your custom EventArgs type.

    public delegate void CustomEventHandler(object sender, CustomEventArgs a);  
    
  3. 使用下列步骤之一来声明发布类中的事件。Declare the event in your publishing class by using one of the following steps.

    1. 如果没有任何自定义 EventArgs 类,事件类型将为非泛型 EventHandler 委托。If you have no custom EventArgs class, your Event type will be the non-generic EventHandler delegate. 你无需声明该委托,因为它已在创建 C# 项目时包括的 System 命名空间中声明。You do not have to declare the delegate because it is already declared in the System namespace that is included when you create your C# project. 将以下代码添加到发布服务器类。Add the following code to your publisher class.

      public event EventHandler RaiseCustomEvent;  
      
    2. 如果使用非泛型版本 EventHandler 并且具有派生自 EventArgs 的自定义类,请声明发布类中的事件,并将步骤 2 中的委托用作类型。If you are using the non-generic version of EventHandler and you have a custom class derived from EventArgs, declare your event inside your publishing class and use your delegate from step 2 as the type.

      public event CustomEventHandler RaiseCustomEvent;  
      
    3. 如果使用泛型版本,则无需自定义委托。If you are using the generic version, you do not need a custom delegate. 而是在发布类中,将事件类型指定为 EventHandler<CustomEventArgs>,替换尖括号中自定义类的名称。Instead, in your publishing class, you specify your event type as EventHandler<CustomEventArgs>, substituting the name of your own class between the angle brackets.

      public event EventHandler<CustomEventArgs> RaiseCustomEvent;  
      

示例Example

下例通过使用自定义 EventArgs 类和 EventHandler<TEventArgs> 作为事件类型来演示之前的步骤。The following example demonstrates the previous steps by using a custom EventArgs class and EventHandler<TEventArgs> as the event type.

namespace DotNetEvents
{
    using System;
    using System.Collections.Generic;

    // Define a class to hold custom event info
    public class CustomEventArgs : EventArgs
    {
        public CustomEventArgs(string s)
        {
            message = s;
        }
        private string message;

        public string Message
        {
            get { return message; }
            set { message = value; }
        }
    }

    // Class that publishes an event
    class Publisher
    {

        // Declare the event using EventHandler<T>
        public event EventHandler<CustomEventArgs> RaiseCustomEvent;

        public void DoSomething()
        {
            // Write some code that does something useful here
            // then raise the event. You can also raise an event
            // before you execute a block of code.
            OnRaiseCustomEvent(new CustomEventArgs("Did something"));

        }

        // Wrap event invocations inside a protected virtual method
        // to allow derived classes to override the event invocation behavior
        protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<CustomEventArgs> handler = RaiseCustomEvent;

            // Event will be null if there are no subscribers
            if (handler != null)
            {
                // Format the string to send inside the CustomEventArgs parameter
                e.Message += $" at {DateTime.Now}";

                // Use the () operator to raise the event.
                handler(this, e);
            }
        }
    }

    //Class that subscribes to an event
    class Subscriber
    {
        private string id;
        public Subscriber(string ID, Publisher pub)
        {
            id = ID;
            // Subscribe to the event using C# 2.0 syntax
            pub.RaiseCustomEvent += HandleCustomEvent;
        }

        // Define what actions to take when the event is raised.
        void HandleCustomEvent(object sender, CustomEventArgs e)
        {
            Console.WriteLine(id + " received this message: {0}", e.Message);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Publisher pub = new Publisher();
            Subscriber sub1 = new Subscriber("sub1", pub);
            Subscriber sub2 = new Subscriber("sub2", pub);

            // Call the method that raises the event.
            pub.DoSomething();

            // Keep the console window open
            Console.WriteLine("Press Enter to close this window.");
            Console.ReadLine();

        }
    }
}

请参阅See also