和 委托 类似,事件是后期绑定机制。 实际上,事件是建立在对 委托 的语言支持之上的。
事件是对象用于(向系统中的所有相关组件)广播已发生事情的一种方式。 任何其他组件都可以订阅事件,并在事件引发时得到通知。
许多图形系统都具有用于报告用户交互的事件模型。 这些事件会报告鼠标移动、按钮点击和类似的交互。 这是使用事件的最常见情景之一,但并非唯一的情景。
要使用事件首先就得定义委托,如下:
// 定义委托
public delegate void delegateTest();
然后再定义使用 event
关键字的事件:
// 定义事务
public event delegateTest eventTest;
对事件所依赖的事务赋值:
// 事件赋值
Program program = new Program();
program.eventTest = () => Console.WriteLine("我是事务中的方法");
调用事件:
// 调用事件
if(program.eventTest != null)
program.eventTest();
// 或者
program.eventTest.Invoke();
通过使用 +=
运算符增加订阅事件:
static void addMethod()
{
Console.WriteLine("我是增加的方法");
}
program.eventTest += addMethod;
使用 -=
运算符取消订阅:
program.eventTest -= addMethod;
请务必为表示事件处理程序的表达式声明局部变量。 这将确保取消订阅删除该处理程序。 如果使用的是 lambda 表达式的主体,则将尝试删除从未附加过的处理程序,此操作为无效操作。
完整示例:
class Program
{
// 定义委托
public delegate void delegateTest();
// 定义事件
public event delegateTest eventTest;
static void addMethod()
{
Console.WriteLine("我是增加的方法");
}
static void Main(string[] args)
{
// 事件赋值
Program program = new Program();
program.eventTest = () => Console.WriteLine("我是事务中的方法");
program.eventTest += addMethod;
program.eventTest -= addMethod;
// 调用时间
if(program.eventTest != null)
program.eventTest();
// 或者
program.eventTest?.Invoke();
}
}
.Net还内置了两个常用的委托类型 EventHandler 和 EventHandler
通常,任何事件都应包含两个参数:事件源和事件数据。
EventHandler 主要用于不包含数据,对包含数据的使用 EventHandler
对 .Net Core 中定义 EventHandler 和 EventHandler
在了解 .Net 内置委托值之前,我们先来了解一下 .Net 事件委托的标准签名:
void OnEventRaised(object sender, EventArgs args);
返回类型为 void。事件基于委托,而且是多播委托。对任何事件源都支持多个订阅服务器。 来自方法的单个返回值不会扩展到多个事件订阅服务器。
参数列表包含两种参数:发件人和事件参数。
sender
的编译时类型为 System.Object
,即使有一个始终正确的更底层派生的类型亦是如此。 按照惯例使用 object
。System.EventArgs
的类型。如果事件类型不需要任何其他参数,你仍将提供这两个参数。 应使用特殊值 EventArgs.Empty
来表示事件不包含任何附加信息。
示例:
class Program
{
static void Main(string[] args)
{
EventSample sample = new EventSample();
sample.ProcessCompeleted += Sample_ProcessCompeleted;
sample.Start();
}
// EventHandler 委托固定参数sender,args
private static void Sample_ProcessCompeleted(object sender, EventArgs args) => Console.WriteLine("处理完成");
}
class EventSample
{
// 事件
public event EventHandler ProcessCompeleted;
public void Start()
{
Console.WriteLine("开始作业");
// 业务逻辑
// 处理完毕后触发事件
OnProcessCompeleted(EventArgs.Empty);
}
// 触发事件
protected virtual void OnProcessCompeleted(EventArgs args) => ProcessCompeleted?.Invoke(this, args);
}
上面代码中,Sample_ProcessCompeleted() 方法多了两个与 EventHandler 匹配的参数。此外,当我们在方法中使用引发事件时,this 作为发送者传递。另外,我们的事件不需要数据,所以使用 EventArgs.Empty 。
大多数事件都会向订阅者发送一些数据。EventArgs 类是所有事件数据的基类。.NET 还包含了其它的内置事件数据类,如:SerialDataReceivedEventArgs 。它遵循以 EventArgs 结尾的命名方式。我们可以通过继承 EventArgs 来自定义事件数据。
示例:
public class ProcessCompeletedEventArgs : EventArgs
{
public bool IsCompeleted { get; set; }
///
/// 完成时间
///
public DateTime CompeletedAt { get; set; }
}
public class EventSample
{
//public delegate void Notify();
public event EventHandler ProcessCompeleted;
public void Start()
{
Console.WriteLine("开始作业");
//业务逻辑
ProcessCompeletedEventArgs e = new ProcessCompeletedEventArgs
{
IsCompeleted = true,
CompeletedAt =DateTime.Now
};
//处理完毕后触发事件
OnProcessCompeleted(e);
}
protected virtual void OnProcessCompeleted(ProcessCompeletedEventArgs e)
{
ProcessCompeleted?.Invoke(this, e);
}
}
class Program
{
static void Main(string[] args)
{
EventSample sample = new EventSample();
sample.ProcessCompeleted += Sample_ProcessCompeleted;
sample.Start();
Console.ReadKey();
}
private static void Sample_ProcessCompeleted(object sender, ProcessCompeletedEventArgs e)
{
Console.WriteLine("IsCompeleted:{0},CompletedAt:{1}", e.IsCompeleted, e.CompeletedAt);
Console.WriteLine("处理完成");
}
}
?.
运算符一起使用的相同的 Invoke()
方法语法。参考:
Microsoft C# 事件