using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Event1
{
#if false
1、Event的普通定义就是“能够发生什么事情, a thing that happens, especially something important!”
2、C#中的事件的定义:使对象或类具备通知能力的成员
3、作用:用于对象或类间动作协调与信息传递(消息推送)
4、原理:事件模型(也叫“发生-响应”模型)
5个部分:eg:闹钟响了你起床,可以分解为5部分:(1)闹钟(事件的发出者/拥有者 event source) (2)响铃(事件event,可以附带一些信息即事件参数) ---(3)订阅(subscribe 你关心了闹铃事件)--- (4)你(事件订阅者/响应者event subscriber) (5)起床(对事件的响应,也叫处理事件或事件处理器 event handler)
5个动作:(1)我有一个事件 (2)一个人或一群人关心我这个事件 (3)我这个事件发生了 (4)关心这个事件的人会依次得到通知 (5)收到通知的人根据拿到的事件信息(又称事件参数/数据)对事件进行响应(处理事件)
5、常用场景
GUI编程
MVC MVP MVVM是事件模型的升级
绝大部分情况下都不需要自己定义事件,都是使用预定义的事件
6、事件和委托的关系
委托只是事件和事件处理器之间的的一种调用约定
#endif
class Program
{
static void Main(string[] args)
{
// 类最重要的三个部分(存储数据、做事情、通知别人)
// 属性:表示当前对象的状态
// 事件:表示对象能在什么情况下通知谁
// 方法:表示当前对象能做什么
#if true
// 模型1 *:(事件的拥有者、事件) 和 (事件订阅者、事件处理器) 两大部分分别独立,这是最基础的模型,也是MVC这些模式的雏形
// event source
System.Timers.Timer timer = new System.Timers.Timer(); // Forms命名空间里面也有Timer,这里是为了解决冲突写明确指明是System.Timers下的Timer
timer.Interval = 1000; // 1000ms
// event subscribers
Subscriber1 sub1 = new Subscriber1();
Subscriber2 sub2 = new Subscriber2();
// event --- +=(subscribe) --- event handler
timer.Elapsed += sub1.TimerEventHandler;
timer.Elapsed += sub2.TimerEventHandler;
// event source开始工作,每隔1000ms发出Elapsed事件通知
timer.Start();
#endif
#if true
// 模型2 ***:(事件订阅者、事件处理器) 内部包含 (事件的拥有者、事件) ,这是典型的GUI中常用模型,
// 比如 主窗口(按钮点击事件的订阅者)里面有一个按钮控件(event source) 订阅(subscribe) 按钮的点击事件(event) 并且拥有按钮点击事件的处理方法(event handler)
MainForm mainForm = new MainForm();
mainForm.ShowDialog();
#endif
#if false
// 模型3 **:事件订阅者和拥有者是同一个对象,事件 和 事件处理器都属于该对象,即自己使用自己的事件处理器处理自己的事件
MyForm form = new MyForm();
form.Click += form.FormClicked;
form.ShowDialog();
#endif
Console.ReadLine();
}
}
class Subscriber1
{
internal void TimerEventHandler(object sender, ElapsedEventArgs e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Subscriber1 handing timer's elapsed event!");
}
}
class Subscriber2
{
internal void TimerEventHandler(object sender, ElapsedEventArgs e)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Subscriber2 handing timer's elapsed event!");
}
}
class MainForm : Form
{
public MainForm()
{
this.Text = "MainForm";
this.Width = 400;
this.Height = 300;
this.FormBorderStyle = FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.textBox = new TextBox();
this.textBox.Top = 5;
this.textBox.Width = this.Width - 10;
this.textBox.Height = 25;
this.button = new Button();
this.button.Top = 10 + this.textBox.Height;
this.button.Width = this.Width - 10;
this.button.Text = "Button1";
this.oldButton = new Button();
this.oldButton.Top = this.button.Top + this.button.Height + 5;
this.oldButton.Width = this.Width - 10;
this.oldButton.Text = "Button2";
this.Controls.Add(this.textBox);
this.Controls.Add(this.button);
this.Controls.Add(this.oldButton);
// MainForm 订阅 button成员 的 Click 事件 安装的事件处理器为 ButtonClicked
this.button.Click += this.ButtonClicked;
// 一些事件处理器的旧式写法即显式使用委托的方式
//this.oldButton.Click += new EventHandler(OldButton_Click); // EventHandler是一个委托类型,现在直接传一个方法给它也将自动生成对应的委托,就跟上面那样
//this.oldButton.Click += delegate (object sender, EventArgs e)
//{
// // 这说白了就是个匿名委托
// this.textBox.Text = "MainForm's Button2 Clicked!";
//};
// 新式的Lambda表达式,甚至可以不写参数的类型,编译器会根据Click事件处理器对应的委托约束 (选中Click按下F12可以跳转) 来正确推导类型
this.oldButton.Click += (object sender, EventArgs e) =>
{
this.textBox.Text = "MainForm's Button2 Clicked!";
};
}
private void OldButton_Click(object sender, EventArgs e)
{
this.textBox.Text = "MainForm's Button2 Clicked!";
}
// 按钮点击事件的处理器
private void ButtonClicked(object sender, EventArgs e)
{
this.textBox.Text = "MainForm's Button1 Clicked!";
}
private TextBox textBox;
private Button button; // 事件的拥有者event source,它是事件订阅者MainForm的一个成员
private Button oldButton;
}
class MyForm : Form
{
internal void FormClicked(object sender, EventArgs e)
{
MessageBox.Show("Form Clicked!");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Event2
{
class Program
{
static void Main(string[] args)
{
// 事件拥有者
Customer customer = new Customer();
// 事件订阅者
Water water = new Water();
// 订阅事件、添加事件处理器
customer.Order += water.Action;
// customer.Order.Invoke // error 这就是为什么需要事件的原因,如果Order是一个委托,则它可以在外面任意调用,但是事件类型在外部是只能出现在 += 左边,不允许其他操作
// 此时如果是委托,那么别的一个顾客就可以帮一个不认识的顾客瞎点菜,即 customer2.Order.Invoke(customer, e);
// 由事件拥有者在某些条件下触发事件
customer.Action();
customer.PayTheBill();
}
}
public class OrderEventArgs : EventArgs
{
public string DishName { get; set; }
public string Size { get; set; }
}
// 约束事件和事件处理器的委托类型(即约束返回值、参数)
public delegate void OrderEventHandler(Customer sender, OrderEventArgs e);
// 事件拥有者
public class Customer
{
#if false
// 完整声明形式:
// 用于保存事件处理器(处理器也是受 OrderEventHandler 委托类型约束)
private OrderEventHandler orderEventHandler;
// 声明事件(使用 OrderEventHandler 委托类型作为约束条件)
public event OrderEventHandler Order
{
add
{
this.orderEventHandler += value; // 添加事件处理器
}
remove
{
this.orderEventHandler -= value;// 删除事件处理器
}
}
#endif
// 事件的简单声明形式(编译器在后台自动创建了OrderEventHandler委托类型的字段)
public event OrderEventHandler Order;
public double Bill { get; set; }
public void PayTheBill()
{
Console.WriteLine("Pay the bill ${0}", this.Bill);
}
public void WalkIntoRestaurant()
{
Console.WriteLine("Customer walk into the restaurant...");
}
public void SitDown()
{
Console.WriteLine("Customer sit down...");
}
public void BrowseDishMenu()
{
Console.ForegroundColor = ConsoleColor.Yellow;
for (int i = 0; i < 5; ++i)
{
Console.WriteLine("Browsing and choosing...");
Thread.Sleep(1000);
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Choose ok! Need a water...");
#if false
// 使用完整声明时:
// 判断是否有事件处理器
if (this.orderEventHandler != null)
{
OrderEventArgs e = new OrderEventArgs() { DishName = "Kongpao Chicken", Size = "normal" };
this.orderEventHandler.Invoke(this, e); // 触发事件
}
#endif
// 使用简单声明时
if (this.Order != null)
{
OrderEventArgs e = new OrderEventArgs() { DishName = "Kongpao Chicken", Size = "normal" };
this.Order.Invoke(this, e); // 触发事件
}
}
public void Action()
{
WalkIntoRestaurant();
SitDown();
BrowseDishMenu();
}
}
// 事件订阅者
public class Water
{
public void Action(Customer customer, OrderEventArgs e)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("Water: a new dish:{0}", e.DishName);
double price = 10.0;
switch (e.Size)
{
case "small":
price = price * 0.5;
break;
case "normal":
price = price * 1.0;
break;
case "big":
price = price * 1.5;
break;
default:
break;
}
customer.Bill += price;
}
}
}