目录
1、定义:单词Event译为事件
- 通顺的解释就是能够发生什么事
角色:使对象或类具备通知能力的成员
- 事件是一种使对象或类能够提供通知的成员
- 对象O拥有一个事件E,想表达的思想是:当事件E发生时,O有能力通知别的对象
使用:用于对象或类间动作协调与信息传递(消息推送)
原理:事件模型(event model)中的两个5
- 发生->响应中的5个部分——这里隐含订阅的关系
- 发生->响应中的5个动作——1.我有一个事件2.一个人或一群人关心我的事件3.我的事件发生了4.关心这个事的人依次被通知到,5.被通知的人根据事件拿到的消息(又称事件数据、事件参数、通知)对事件进行响应(又称处理事件)
提示:事件多用于桌面、手机登开发的客户端编程,因为是通过事件来驱动的。MVC、MVP、MVVM等模式,是事件模式更高级,更有效的玩法。日常开发的时候,使用已有事件的机会比较多,自己声明事件的机会比较少,所以先学使用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;
namespace 事件
{
class Program
{
static void Main(string[] args)
{
#region 简单的事件
/*
//1、事件的拥有者timer
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000;
//声明一个Boy变量
//3、事件的响应者
Boy boy = new Boy();
Girl girl = new Girl();
//事件处理器
//事件订阅 事件+=事件处理器
timer.Elapsed += boy.Aciton;
timer.Elapsed += girl.Action;
//打开
timer.Start();
*/
#endregion
#region 点击窗体出现当前时间
/*
//事件的拥有者
Form form = new Form();
//事件的响应者
Controller controller = new Controller(form);
form.ShowDialog();
*/
#endregion
#region 派生Form自己的类MyForm
/*
//事件的拥有者、事件的响应者
MyForm myForm = new MyForm();
//Click事件
//事件订阅 事件+=事件处理器
myForm.Click += myForm.FormClicked;
//运行
myForm.ShowDialog();
*/
#endregion
#region 点击显示Helloworld
MyForm1 myForm1 = new MyForm1();
myForm1.ShowDialog();
#endregion
Console.ReadKey();
}
}
#region 简单的事件处理器
/// <summary>
/// 跳针处理器
/// </summary>
class Boy
{
//事件处理器
internal void Aciton(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Jump!");
}
}
/// <summary>
/// 另一个处理器
/// </summary>
class Girl
{
internal void Action(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Sing!");
}
}
#endregion
#region 点击出现当前时间
class Controller
{
private Form form;
public Controller(Form form)
{
if (form!=null)
{
this.form = form;
//为form挂接一个事件处理器
//事件订阅
this.form.Click += this.FormCliched;
}
}
//事件处理器
private void FormCliched(object sender, EventArgs e)
{
this.form.Text = DateTime.Now.ToString();
}
}
#endregion
#region 派生创建自己的类
class MyForm : Form
{
//事件处理器
internal void FormClicked(object sender, EventArgs e)
{
this.Text = DateTime.Now.ToString();
}
}
#endregion
#region 点击显示Helloworld
#endregion
class MyForm1:Form
{
private TextBox textBox;
private Button button;
public MyForm1()
{
this.textBox = new TextBox();
this.button = new Button();
this.Controls.Add(this.button);
this.Controls.Add(this.textBox);
this.button.Click += this.ButtonClicked;
this.button.Text = "Say Hello!";
this.button.Top=100;
}
private void ButtonClicked(object sender, EventArgs e)
{
this.textBox.Text = "Hello World!!!!!!!!!!!!!!!!";
}
}
}
2、实例:派生(继承)与扩展(extends)
事件模型的五个组成部分
- 1、事件的拥有者(event source,对象)
- 2、事件成员(event,成员)
- 3、事件响应者(event subscriber,对象)
- 4、事件处理器(event handler ,成员)——本质是一个回调方式
- 5、事件订阅——把事件处理器与事件关联在一起,本质是一种以委托类型为基础的约定
3、注意:
- 事件处理器是方法成员
- 挂接事件处理器的时候,可以使用委托类型,也可以直接使用方法名,这是个“语法糖”
- 事件处理器对事件的订阅不是随意的,匹配与否由声明事件时所使用的委托类型来检测
- 事件可以同步调用也可以异步调用
4、事件的声明
完整声明、简略声明(字段式声明、field-like)
有了委托字段属性为什么还需要事件
所以事件的本质是委托字段的一个包装器
- 这个包装器对委托字段的访问起限制作用,相当于一个蒙版
- 封装(encapsulation)的重要功能就是隐藏
- 事件对外界隐藏了委托实例的大部分功能,仅暴露添加/移除事件处理器的功能
- 添加/移除事件处理器的时候可以直接使用方法名,这是委托所不具备的功能
用于声明事件的委托类型的命名约定
用于声明Foo事件的委托,一般命名为FooEventHandler(除非是一个非常通用的事件约束)
FooEventHandler委托的参数一般有两个
- 第一个是object类型,名字为sender,实际上就是事件的拥有者、事件的source
- 第二个是EventArgs类的派生类类名一般为FooEventArgs,参数名为e也就是事件参数
- 触发Foo事件的方法一般命名为OnFoo即因何而发、事出有因
- 访问级别为protected、不能为public
5、事件的命名约定
- 带有时态的动词或动词短语
- 事件拥有者正在做什么事情,用进行时;事件拥有者做完了什么事情,用完成时
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 事件2
{
class Program
{
static void Main(string[] args)
{
#region 完整声明方式调用
Customer customer = new Customer();
Watier watier = new Watier();
//事件订阅
customer.Order += watier.Action;
//触发事件
customer.Aciton();
customer.PayTheBill();
#endregion
#region 简略声明格式调用
/*
Customer customer = new Customer();
Watier watier = new Watier();
//事件订阅
customer.Order += watier.Action;
//触发事件
//customer.Aciton();
customer.PayTheBill();
//之外随便访问字段
OrderEventArgs e = new OrderEventArgs();
e.DisName = "manhanquanxi";
e.Size = "large";
OrderEventArgs e2 = new OrderEventArgs();
e2.DisName = "Beer";
e2.Size = "large";
Customer badGuy = new Customer();
badGuy.Order += watier.Action;
badGuy.Order.Invoke(customer, e);
badGuy.Order.Invoke(customer, e2);
customer.PayTheBill();
*/
#endregion
//实例化一个事件发送器
KeyInputMonitor monitor = new KeyInputMonitor();
//实例化一个事件接收器
EventReceiver eventReceiver = new EventReceiver(monitor);
//运行
monitor.Run();
}
}
#region 完整声明方式
/// 声明数据类型
public class OrderEventArgs :EventArgs
{
public string DisName { get; set; }
public string Size { get; set; }
}
/// 声明委托类型
public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
/// 声明事件类
public class Customer
{
//声明委托类型的字段
private OrderEventHandler orderEventHandler;
//声明事件
public event OrderEventHandler Order
{
//事件处理器添加器
add
{
this.orderEventHandler += value;
}
//事件处理器移除器
remove
{
this.orderEventHandler -= value;
}
}
public double Bill { get; set; }
public void PayTheBill()
{
Console.WriteLine(" I Will Pay ${0}",this.Bill);
}
//事件的触发的方法
public void WalkIn()
{
Console.WriteLine("walk into the restaurant.");
}
public void SitDown()
{
Console.WriteLine("Sit Down.");
}
public void Think()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Let me think...");
Thread.Sleep(1000);
}
//判断是否为空
if (this.orderEventHandler!=null)
{
OrderEventArgs e = new OrderEventArgs();
e.DisName = "Kongpao Chicken";
e.Size = "large";
this.orderEventHandler.Invoke(this,e);
}
}
//进行操作
public void Aciton()
{
Console.ReadLine();
this.WalkIn();
this.SitDown();
this.Think();
}
}
//事件的响应者
public class Watier
{
public void Action(Customer customer, OrderEventArgs e)
{
Console.WriteLine("I Will serve you the dish -{0}",e.DisName);
double price = 10;
switch (e.Size)
{
case "small":
price = price * 0.5;
break;
case "large":
price = price * 1.5;
break;
default:
break;
}
customer.Bill += price;
}
}
#endregion
#region 简略声明格式
/*
/// 声明数据类型
public class OrderEventArgs : EventArgs
{
public string DisName { get; set; }
public string Size { get; set; }
}
/// 声明委托类型
public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
/// 声明事件类
public class Customer
{
//声明委托类型的字段
public OrderEventHandler Order;
public double Bill { get; set; }
public void PayTheBill()
{
Console.WriteLine(" I Will Pay ${0}", this.Bill);
}
//事件的触发的方法
public void WalkIn()
{
Console.WriteLine("walk into the restaurant.");
}
public void SitDown()
{
Console.WriteLine("Sit Down.");
}
public void Think()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Let me think...");
Thread.Sleep(1000);
}
//判断是否为空
//直接使用事件的名字来进行调用
if (this.Order != null)
{
OrderEventArgs e = new OrderEventArgs();
e.DisName = "Kongpao Chicken";
e.Size = "large";
this.Order.Invoke(this, e);
}
}
//进行操作
public void Aciton()
{
Console.ReadLine();
this.WalkIn();
this.SitDown();
this.Think();
}
}
//事件的响应者
public class Watier
{
public void Action(Customer customer, OrderEventArgs e)
{
Console.WriteLine("I Will serve you the dish -{0}", e.DisName);
double price = 10;
switch (e.Size)
{
case "small":
price = price * 0.5;
break;
case "large":
price = price * 1.5;
break;
default:
break;
}
customer.Bill += price;
}
}
*/
#endregion
#region 简单练习
internal class KeyEventArgs:EventArgs
{
private char keyChar;
public KeyEventArgs(char keyChar):base()
{
this.keyChar = keyChar;
}
public char KeyChar
{
get
{
return keyChar;
}
}
}
internal class KeyInputMonitor
{
//创建一个委托,类型为void
public delegate void KeyDownEventHandler(object sender, KeyEventArgs e);
//将创建的委托和特定事件关联,这里特定事件为KeyDown
public event KeyDownEventHandler KeyDown;
public void Run()
{
bool finished = false;
do
{
Console.WriteLine("Input a Char !");
string response = Console.ReadLine();
char resposeChar = (response == "") ? ' ' : char.ToUpper(response[0]);
//得到的按键信息的参数
KeyEventArgs keyEventArgs = new KeyEventArgs(resposeChar);
//触发事件
KeyDown(this, keyEventArgs);
} while (!finished);
}
}
internal class EventReceiver
{
public EventReceiver(KeyInputMonitor monitor)
{
//产生一个委托实例并添加到产生的事件列表中
monitor.KeyDown += new KeyInputMonitor.KeyDownEventHandler(this.OnKeyDown);
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
//真正的事件处理函数
Console.WriteLine("Capture key:{0}",e.KeyChar);
}
}
#endregion
}
6、事件与委托的关系
事件真的是以特殊方式声明的委托字段/实例吗?
不是!只是看起来像对比委托字段与事件的简化声明
事件声明的时候使用了委托类型,简化声明造成事件看上去像一个委托的字段(实例)
而event关键字更像一个修饰符——这就是错觉的来源之一
订阅事件看起来像个委托字段——这是错觉的又一来源
重申:事件的本质是加装在委托字段上的一个蒙版(mask),是个起掩蔽作用的包装器,这个用于阻挡非法操作的蒙版绝不是委托字段本身
为什么要使用委托类型来声明事件
- 站在source的角度来看,是为了表明source能对外传递那些消息
- 站在subscriber的角度来看,它是一种约束,是为了约束能够使用什么样签名的方法来处理(响应)事件
委托类型的实例将用于存储(引用)事件处理器