1. 初步了解事件
举例:如果说手机有响铃事件,手机可以通过响铃事件来通知关注这个手机的人,或者说响铃事件让手机具备了通知关注者能力。当手机响铃时,站在手机的角度来看是在通知关注它的人,要求关注它的人采取行动;站在人的角度来看,人得到手机的通知可以采取行动了。伴随着通知,很多事件在发生的时候会产生一些与这个事件相关的数据,以智能手机为例,当响铃的时候肯定会伴随着一些其他的消息,站在手机的角度来看,他是在完成通知关注者的同时把相关的消息也发送给关注者了,而站在关注者的角度来看,除了被通知到了之外,还收到事件的主体手机经由事件发送过来的消息,把这种消息成为事件参数(EventArgs),当手机的关注者被通知之后就会去检查这个事件参数,然后根据事件参数里的内容进行相应的行动,把根据通知和事件参数来采取行动的行为成为响应事件/处理事件,处理事件时具体所做的事情就叫事件处理器(EventHandler)。
- 使对象或类具有通知能力的成员
- 事件的功能 = 通知 + 可选的事件参数(即详细信息)
- 用于对象或类间的动作协调与信息传递(消息推送)
加粗样式处理事件使用的模式:MVC、MVP、MVVM
2. 事件的应用
事件模型的五个组成部分
- 事件的拥有者:event source,对象
- 事件成员:event,成员
- 事件的响应者:event subscribe,对象
- 事件处理器:event handler,成员,本质上是一个回调方法
- 事件订阅:把事件处理器和事件关联在一起,本质上是一种以委托类型为基础的约定
(1)第一种类型
using System;
using System.Timers;
class Program
{
static void Main(string[] args)
{
//事件拥有者
Timer timer = new Timer();
timer.Interval = 1000;
//事件响应者
Boy boy = new Boy();
Girl girl = new Girl();
//事件订阅者,+=操作符左边是事件,右边是事件处理器
timer.Elapsed += boy.Action;
timer.Elapsed += girl.Action;
timer.Start();
Console.ReadLine();
}
}
class Boy
{
//事件处理器
internal void Action(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Jump");
}
}
class Girl
{
internal void Action(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Sing");
}
}
(2)第二种类型
using System;
using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
//事件拥有者
Form form = new Form();
Controller controller = new Controller(form);
form.ShowDialog();
}
}
class Controller
{
private Form form;
public Controller(Form form)
{
if(form != null)
{
this.form = form;
//事件是click,事件处理器是FormClicked
form.Click += this.FormClicked;
}
}
private void FormClicked(object sender, EventArgs e)
{
this.form.Text = DateTime.Now.ToString();
}
}
(3)第三种类型
事件的拥有者和事件的响应者是同一个对象
using System;
using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
MyForm form = new MyForm();
form.Click += form.FormClicked;
form.ShowDialog();
}
}
class MyForm : Form
{
internal void FormClicked(object sender, EventArgs e)
{
this.Text = DateTime.Now.ToString();
}
}
(4)第四种类型
事件的拥有者是事件响应者的一个字段成员,事件响应者用自己的方法订阅了自己成员的某个事件
using System;
using System.Windows.Forms;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
MyForm myForm = new MyForm();
myForm.ShowDialog();
}
}
class MyForm : Form
{
private TextBox textBox;
private Button button;
public MyForm()
{
this.textBox = new TextBox();
this.button = new Button();
this.Controls.Add(textBox);
this.Controls.Add(button);
this.button.Top = 100;
this.button.Click += this.ButtonClicked;
}
private void ButtonClicked(object sender, EventArgs e)
{
this.textBox.Text = "helloworld!";
}
}
}
事件是基于委托的:
- 第一层意思:事件需要委托类型来做一个约束。约束既规定事件能发送什么样的消息给响应者,也规定事件响应者能收到什么样的事件消息。这就决定了事件响应者的事件处理器,必须能够和这个约束匹配上,才能够订阅这个事件。
- 第二层意思:当事件响应者向事件拥有者提供了能够匹配这个事件的事件处理器之后,需要把事件处理器保存或者记录下来。能够记录或者说引用方法的任务,只有委托类型的实例能够做到。
using System;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//this.button3.Click += this.ButtonClicked;
this.button3.Click += new EventHandler(this.ButtonClicked);
//匿名方法
this.button3.Click += (object sender, EventArgs e) =>
{
this.textBox1.Text = "hello";
};
}
private void ButtonClicked(object sender, EventArgs e)
{
if(sender == this.button1)
{
this.textBox1.Text = "OK";
}
else if(sender == this.button2)
{
this.textBox1.Text = "no";
}
else
{
this.textBox1.Text = "hello";
}
}
}
}
3. 声明自定义事件
(1) 完整声明
using System;
using System.Threading;
using System.Windows.Forms;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
Customer customer = new Customer();
Waiter waiter = new Waiter();
customer.Order += waiter.Action;
customer.Action();
customer.PayTheBill();
}
}
public class OrderEventArgs:EventArgs
{
public string DishName { 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 in to the restuurant.");
}
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.DishName = "GongBao Chicken";
e.Size = "large";
this.orderEventHandler.Invoke(this, e);
}
}
public void Action()
{
Console.ReadLine();
this.WalkIn();
this.SitDown();
this.Think();
}
}
public class Waiter
{
internal void Action(Customer customer, OrderEventArgs e)
{
Console.WriteLine("I will serve you the dish-{0}.", e.DishName);
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;
}
}
}