事件的应用
实例演示
派生与拓展
事件模型的五个组成部分
1,事件的拥有者(event source,对象)
2,事件成员(event,成员)
3,事件的响应者(event subscriber,对象)
4,事件处理器(event handler,成员)-----本质上是一个回调方法
5,事件回调------把事件处理器与事件关联在一起,本质上是一种以委托类型为基础的约定
注意
事件处理器是成员方法
挂接事件处理器的时候,可以使用委托类型,也可以直接使用方法名,这是个语法糖
事件处理器对事件的订阅不是随意的,匹配与否由声明事件时所使用的委托类型来检测
事件可以同步调用也可以异步调用
事件的各种模型
事件的拥有者 订阅 事件的响应者
class Program { static void Main(string[] args) { System.Timers.Timer timer = new System.Timers.Timer();//事件的拥有者 timer.Interval = 1000; Boy boy = new Boy();//事件的响应者 //Elapsed为事件 Action为事件处理器 timer.Elapsed += boy.Action;//订阅操作 timer.Start(); } } class Boy { internal void Action(object sender, ElapsedEventArgs e) { Console.WriteLine("Jump"); } }
事件的拥有者和事件响应者不相同
static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //Application.Run(new Form1()); Form form = new Form(); Controller control = new Controller(form); form.ShowDialog(); } } public class Controller { private Form form; public Controller(Form form) { if (form!=null) { this.form = form; this.form.Click += this.ShowTime; } } private void ShowTime(object sender, EventArgs e) { this.form.Text = DateTime.UtcNow.ToString(); } }
事件的拥有者和事件的响应者是同一个对象
static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //Application.Run(new Form1()); MyForm form = new MyForm(); form.Click += form.Clicked; form.ShowDialog(); } } public class MyForm : Form { internal void Clicked(object sender, EventArgs e) { this.Text = DateTime.UtcNow.ToString(); } }
事件的拥有者是事件响应者的字段成员,事件的响应者用自己的方法订阅着自己字段成员的事件
static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //Application.Run(new Form1()); Button button = new Button(); TextBox textBox = new TextBox(); MyForm myForm = new MyForm(button, textBox); myForm.ShowDialog(); } } public class MyForm : Form { private Button Button; private TextBox TextBox; public MyForm(Button button,TextBox textBox) { this.Button = button; this.TextBox = textBox; this.Controls.Add(this.Button); this.Controls.Add(this.TextBox); this.Button.Text = "Click Me"; this.Button.Top = 100; this.Button.Click += this.showMessage; } private void showMessage(object sender, EventArgs e) { this.TextBox.Text = "233333"; } }
事件的声明
事件的声明
完整的声明
简略声明(字段式声明)
有了委托字段/属性,为什么还需要事件
为了程序的逻辑更加由道理,更加安全,谨防借刀杀人
所以事件的本质式委托类型字段的一个包装器
这个包装器对委托类型字段的访问起到限制作用,相当于一个模板
封装的一个重要功能就是隐藏
事件对外界隐藏了委托实例的大部分功能,仅暴露添加/移除事件处理器的功能
添加移除事件处理器的时候可以直接使用方法名,这是委托实例所不具备的
用于声明事件的委托类型的命名约定
用于声明Foo事件的委托,一般命名为FooEventHandel
FooEventHander类型的委托的参数一般有两个
第一个是object类型,名字为sengder,实际上就是事件的拥有者,事件的source
另一个是EventArgs类的派生类,类名一般为FooEventArgs参数名为e,也就是前面讲的事件参数,
虽然没有官方的说法,但我们可以把委托的参数列表看作是事件发生后发送给事件响应者的事件消息
触发Foo事件的方法一般命名为OnFoo,即因何引发,事出有因
访问级别为protected不能为public,不然又成了借刀杀人
事件的命名约定
带有动态的动词或者动词短语
事件拥有者正在做什么事情,用进行时。事件拥有者做完了什么事情,用完成时
事件完整namespace HelloWorld
namespace HelloWorld { class Program { static void Main(string[] args) { Customer customer = new Customer(); Waiter waiter = new Waiter(); //事件的订阅 customer.Order += waiter.Action; customer.StartEvent(); Console.ReadLine(); } } public delegate void OrderEventHander(Customer customer,OrderEventArgs eventArgs); public class OrderEventArgs:EventArgs { public string DishName { get; set; } public double DishPrice { get; set; } } //事件的拥有者 public class Customer { public string Name { get; set; } public OrderEventHander OrderEventHander; //事件 public event OrderEventHander Order { add { this.OrderEventHander += value; } remove { this.OrderEventHander -= value; } } //!!!!!重点!!!!! //事件的触发一般在事件的拥有者的内部逻辑 public void StartEvent() { if (this.OrderEventHander != null) { Customer customer = new Customer { Name = "Jack" }; OrderEventArgs e = new OrderEventArgs { DishName = "Pizza", DishPrice = 30 }; this.OrderEventHander.Invoke(customer,e); } } } //事件的响应者 public class Waiter { public void Action(Customer customer, OrderEventArgs eventArgs) { Console.WriteLine($"{customer.Name} please wait for your {eventArgs.DishName} and you should pay {eventArgs.DishPrice}"); } } }