简介
事件是使类具备向其它类通知发生的相关事情的能力。事件被分成两部分:一、引发或发送事件的类(称发布者);二、处理或接收事件的类(称订阅者)。事件也是类型的成员。在 .NET 的桌面应用程序中,按钮、列表框、文本输入框等控件都具有相关的事件,如按键响应、鼠标移动、点击等。
1、事件模型
事件一定是发布者(类)的内部逻辑触发的。事件的模型由事件发布者、事件成员、事件的响应、事件的处理(回调一个方法)及事件的订阅 五个部分组成。事件的订阅是以委托类型为基础的约束事件处理与事件绑定关联一起。下面通过一个图了解事件组成及关系。
示例:以 C# 中常见的定时器 Timer 为例,了解事件。
using System;
using System.IO;
using System.Timers;
namespace Fountain.Consoles.App
{
internal class Program
{
static void Main(string[] args)
{
try
{
// 事件的发布者
Timer timer = new Timer();
// 触发事件的逻辑
timer.Interval = 2000;
// 事件的订阅者
Log log= new Log();
log.RetentionTime = 20;
// 事件的订阅 (事件处理与事件关联在一起)
timer.Elapsed += log.Delete;
// 事件的发布者触发计时开始
timer.Start();
Console.ReadLine();
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
}
}
/// <summary>
/// 日志类
/// </summary>
public class Log
{
private object locker = new object();
private int retentionTime = 10;
/// <summary>
/// 保留时间
/// </summary>
public int RetentionTime
{
get { return retentionTime; }
set { retentionTime = value; }
}
/// <summary>
/// 事件处理(删除日志文件)
/// </summary>
public void Delete(object sender, ElapsedEventArgs e)
{
// 日志目录
string logDirectory = string.Format("{0}{1}", AppDomain.CurrentDomain.BaseDirectory, "Log");
try
{
lock (this.locker)
{
if(Directory.Exists(logDirectory))
{
// 获取所有匹配的日志文件
string[] files = Directory.GetFiles(logDirectory, "*.log");
// 遍历删除
foreach (string file in files)
{
if (File.GetCreationTime(file).AddDays(this.RetentionTime) < DateTime.Now)
{
File.Delete(file);
Console.WriteLine($"日志文件【{0}】被删除。", file);
}
}
}
}
}
catch (Exception exception)
{
Console.WriteLine($"删除日志文件异常: {0}", exception.Message);
}
}
}
}
2、事件声明
.NET 提供了很多带事件的类,如Timer、TextBox、Button 等,对于.NET 提供的,我们只用订阅相关事件,添加事件响应处理方法即可。
如需自定义一个事件,首先必须在需添加的类中声明该事件的委托类型,然后使用 event 关键字声明事件。
事件的声明有完整声明与简略声明两种方式。下面是事件声明的简单示例:
//声明一个委托类型,专门用来声明事件,约束事件处理器
public delegate void 委托类型名称(处理事件参数);
// 基于委托定义事件
public event 委托类型名称 事件名称;
// 声明委托类型字段
public delegate void TextChangedEventHandler(object sender,KeyEventArgs e);
// 简略声明事件
public static event TextChangedEventHandler TextChangedEvent;
//完整声明
public event TextChangedEventHandler TextChangedEvent
{
add
{
//事件处理器的添加器
this.TextChangedEventHandler += value;
}
remove
{
//事件处理器的移除器
this.TextChangedEventHandler -= value;
}
}
3、事件属性
1、发布者确定引发事件时间,订阅者确定对事件如何响应。
2、事件可被多个订阅,订阅者可以处理多个发布者的事件。
3、事件未被订阅,则事件不会被引发。
4、事件一般用于用户操作。
5、事件被多个订阅时,引发事件时同步调用事件处理程序。
6、事件基于 EventHandler 与 EventArgs 类。
4、事件与委托
事件并不是委托,只是借用委托类型来存储或引用事件处理,基于委托约束事件能够发送什么样的消息给事件的订阅者。把事件作为一种特殊的委托的实例,或者说是受限制的委托,是委托一种特殊应用,只是因为:1、事件声明用到了委托类型;2、可以直接用委托调用事件订阅者处理内容。
应用
本应用示例提供应用程序二个界面数据的同步,扫描界面扫描快递单号后,同步到一个放大展示界面。
事件的参数
using System;
namespace Fountain.WinForm.SyncDisplay
{
/// <summary>
/// 事件参数
/// </summary>
public class SyncEventArg : EventArgs
{
/// <summary>
/// 快递单号
/// </summary>
public string TrackingNo { get; set; }
}
}
事件发布者类,扫描界面:
using System;
using System.Windows.Forms;
namespace Fountain.WinForm.SyncDisplay
{
public partial class ScanForm : Form
{
//使用默认的事件处理委托,定义消息发布者事件
public event EventHandler SendMsgEvent;
/// <summary>
///
/// </summary>
public ScanForm()
{
InitializeComponent();
}
/// <summary>
/// 界面加载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ScanForm_Load(object sender, EventArgs e)
{
try
{
ShowForm showForm = new ShowForm();
// 事件的订阅 (事件处理与事件关联在一起)
SendMsgEvent += showForm.SysncTextChaned;
showForm.Show();
}
catch
{
}
}
/// <summary>
/// 文本输入框回车事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextBoxTrackingNo_KeyDown(object sender, KeyEventArgs e)
{
try
{
if (e.KeyCode == Keys.Enter)
{
if (!string.IsNullOrEmpty(this.TextBoxTrackingNo.Text))
{
// 事件触发通知
SendMsgEvent(this, new SyncEventArg() { TrackingNo = this.TextBoxTrackingNo.Text });
}
}
}
catch
{
}
}
}
}
事件订阅者类,显示界面:
using System;
using System.Windows.Forms;
namespace Fountain.WinForm.SyncDisplay
{
public partial class ShowForm : Form
{
/// <summary>
///
/// </summary>
public ShowForm()
{
InitializeComponent();
}
/// <summary>
/// 响应事件处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
internal void SysncTextChaned(object sender, EventArgs e)
{
try
{
//取到主窗体的传来的文本
SyncEventArg arg = e as SyncEventArg;
this.LabelTrackingNo.Text = arg.TrackingNo;
}
catch
{
}
}
}
}
效果:
小结
以上都是事件的相关内容,事件属于C#的高级语法,应用的场景很多。希望通过本篇对大家有帮助,敬请关注后续内容。如需应用示例完整代码关注留言。