下面的过程演示了如何将遵循标准 .NET 模式的事件添加到类和结构中。The following procedure demonstrates how to add events that follow the standard .NET pattern to your classes and structs. .NET 类库中的所有事件均基于 EventHandler 委托,定义如下:All events in the .NET class library are based on the EventHandler delegate, which is defined as follows:
C#publicdelegate void EventHandler(object sender, EventArgs e);
备注
.NET Framework 2.0 引入了泛型版本的委托 EventHandler<TEventArgs>。.NET Framework 2.0 introduces a generic version of this delegate, EventHandler<TEventArgs>. 下例演示了如何使用这两个版本。The following examples show how to use both versions.
尽管定义的类中的事件可基于任何有效委托类型,甚至是返回值的委托,但一般还是建议使用 EventHandler 使事件基于 .NET 模式,如下例中所示。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 pattern by using EventHandler, as shown in the following example.
名称 EventHandler
可能导致一些混淆,因为它不会实际处理事件。The name EventHandler
can lead to a bit of confusion as it doesn't actually handle the event. EventHandler 和泛型 EventHandler<TEventArgs> 均为委托类型。The EventHandler, and generic EventHandler<TEventArgs> are delegate types. 其签名与委托定义匹配的方法或 Lambda 表达式是事件处理程序,并将在引发事件时调用。A method or lambda expression whose signature matches the delegate definition is the event handler and will be invoked when the event is raised.
发布基于 EventHandler 模式的事件Publish events based on the EventHandler pattern
-
(如果无需随事件一起发送自定义数据,请跳过此步骤转到步骤 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.
C#public class CustomEventArgs : EventArgs { public CustomEventArgs(string message) { Message = message; } public string Message { get; set; } }
-
(如果使用的是泛型版本 EventHandler<TEventArgs>,请跳过此步骤。)声明发布类中的委托。(Skip this step if you are using the generic version of EventHandler<TEventArgs>.) Declare a delegate in your publishing class. 为其指定以
C#EventHandler
结尾的名称。Give it a name that ends withEventHandler
. 第二个参数指定自定义EventArgs
类型。The second parameter specifies your customEventArgs
type.public delegate void CustomEventHandler(object sender, CustomEventArgs args);
-
使用下列步骤之一来声明发布类中的事件。Declare the event in your publishing class by using one of the following steps.
-
如果没有任何自定义 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.
C#public event EventHandler RaiseCustomEvent;
-
如果使用非泛型版本 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.
C#public event CustomEventHandler RaiseCustomEvent;
-
如果使用泛型版本,则无需自定义委托。If you are using the generic version, you do not need a custom delegate. 而是在发布类中,将事件类型指定为
C#EventHandler<CustomEventArgs>
,替换尖括号中自定义类的名称。Instead, in your publishing class, you specify your event type asEventHandler<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.
C#using System;
namespace DotNetEvents
{
// Define a class to hold custom event info
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
}
// 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("Event triggered"));
}
// 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> raiseEvent = RaiseCustomEvent;
// Event will be null if there are no subscribers
if (raiseEvent != null)
{
// Format the string to send inside the CustomEventArgs parameter
e.Message += $" at {DateTime.Now}";
// Call to raise the event.
raiseEvent(this, e);
}
}
}
//Class that subscribes to an event
class Subscriber
{
private readonly string _id;
public Subscriber(string id, Publisher pub)
{
_id = id;
// Subscribe to the event
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: {e.Message}");
}
}
class Program
{
static void Main()
{
var pub = new Publisher();
var sub1 = new Subscriber("sub1", pub);
var sub2 = new Subscriber("sub2", pub);
// Call the method that raises the event.
pub.DoSomething();
// Keep the console window open
Console.WriteLine("Press any key to continue...");
Console.ReadLine();
}
}
}