一、什么是事件
组成一个事件的五个部分:事件的拥有者、事件拥有者的某个事件成员、事件订阅器、事件响应者以及事件响应者的成员。
简单来说事件实质就是:事件的拥有者(Event source)的某个事件成员(Event,成员)被调用导致订阅该事件的事件响应者(Event Subcriber)调用事件处理成员(Event Handler,成员)被触发(本质上就是一个回调函数被调用)。
*
**事件的作用:事件与属性类似本质是一个包装器,目的是为了更好的保护类内部的委托类型成员,事件只能被+=或-=,在这一过程中实际上操作的是事件拥有者的委托类型成员,从而保护类内部的委托类型成员不被外部随意修改。
二、事件的声明与定义方式
上面我们已经知道到了什么是事件,事件的组成的五个部分(事件的拥有者、事件拥有者的某个事件成员、事件订阅器、事件响应者以及事件响应者的成员)。一个事件的发生必不可少的需要这五个部分,事件订阅过程可以清楚的看清这五个部分各自的作用
事件订阅过程
因此我们定义和声明一个事件必须先定义和声明这五个部分,并创建对应的对象实例,最后在调用事件的订阅,才能完成一个完整的事件定义过程。值得注意的是并不是任意对象的任意事件与事件处理都可以建立联系,形成订阅的关系,能够形成事件的订阅的前提是时间拥有者发生的事件的方法签名(包含方法名,参数的类型数量和顺序)与事件处理方法的方法签名一致才能形成订阅。
事件声明完整格式
using System;
using System.Threading;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
// 1.事件拥有者
var customer = new Customer();
// 2.事件响应者
var waiter = new Waiter();
// 3.Order 事件成员 5. +=事件订阅
customer.Order += waiter.Action;//实际上是事件处理方法waiter.Action加入到了类内委托orderEventHandler但为了保护该委托不被随意访问,设计了一个Order事件来间接修改委托字段,类似属性来保护类内字段。
// customer.Order += new OrderEventHandler(waiter.Action);通过添加委托类型实例来修改事件从而添加到类内委托orderEventHandler,与上一句等效。
customer.Action();
customer.PayTheBill();
}
}
// 该类用于传递点的是什么菜,作为事件参数,需要以 EventArgs 结尾,且继承 EventArgs
public class OrderEventArgs:EventArgs
{
public string DishName { get; set; }
public string Size { get; set; }
}
// 声明一个委托类型,因为该委托用于事件处理,所以以 EventHandler 结尾
// 注意委托类型的声明和类声明是平级的
public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
public class Customer
{
// 委托类型字段
private OrderEventHandler orderEventHandler;
// 完整事件所有者的事件声明,order是实际事件,oderEventHandler是他的一个委托
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 Think()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Let me think ...");
Thread.Sleep(1000);
}
if (this.orderEventHandler != null)
{
var e = new OrderEventArgs();
e.DishName = "Kongpao Chicken";
e.Size = "large";
//事件实际的委托类型字段被触发,事件才真正发生并通知被订阅的事件处理方法
this.orderEventHandler.Invoke(this,e);
}
}
public void Action()
{
Console.ReadLine();
this.Think();
}
}
public class Waiter //事件订阅者类型定义
{
// 4.事件处理器
public 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 *= 0.5;
break;
case "large":
price *= 1.5;
break;
default:
break;
}
customer.Bill += price;
}
}
}
事件声明简略格式
一种 filed-like 的声明格式。filed-like:像字段声明一样 。
与上例只有事件声明和事件触发两处不同。
1、在定义事件过程中省略了对类内委托类型字段的完整声明 private OrderEventHandler orderEventHandler;以及事件内部的方法,类似属性的简略声明,会有编译器自动生成一个委托类型字段
2、在实际调用时,原本应该触发的是一个类内委托类型字段,但由于使用简略声明并未定义该字段,所以表面上看上去是使用了事件来触发(this.Order.Invoke),但实际上事件本身右边只能使用+=或-=操作符,这里之所以可以这样用实际上还是编译器做了优化,触发的还是由编译器自动生成的委托类型字段。
using System;
using System.Threading;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
// 1.事件拥有者
var customer = new Customer();
// 2.事件响应者
var waiter = new Waiter();
// 3.Order 事件成员 5. +=事件订阅
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
{
// **简略事件声明**,看上去像一个委托(delegate)类型字段
public event OrderEventHandler Order;
public double Bill { get; set; }
public void PayTheBill()
{
Console.WriteLine("I will pay ${0}.",this.Bill);
}
public void Think()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Let me think ...");
Thread.Sleep(1000);
}
if (this.Order != null)
{
var e=new OrderEventArgs();
e.DishName = "Kongpao Chicken";
e.Size = "large";
this.Order.Invoke(this,e);//
}
}
public void Action()
{
Console.ReadLine();
this.Think();
}
}
public class Waiter
{
// 4.事件处理器
public 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 *= 0.5;
break;
case "large":
price *= 1.5;
break;
default:
break;
}
customer.Bill += price;
}
}
}
三、常用的几种事件订阅方式
1、事件拥有者和事件响应者是完全不同的两个对象
using System;
using System.Windows.Forms;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
// 1.事件拥有者
var form = new Form();
// 3.事件响应者
var controller = new Controller(form);
form.ShowDialog();
}
}
class Controller
{
private Form form;
public Controller(Form form)
{
if (form != null)
{
this.form = form;
// 2.事件成员 Click 5.事件订阅 +=
this.form.Click += this.FormClicked;
}
}
// 4.事件处理器
private void FormClicked(object sender, EventArgs e)
{
this.form.Text = DateTime.Now.ToString();
}
}
}
2、事件的拥有者和响应者是同一个对象
一个对象拿着自己的方法去订阅和处理自己的事件。
该示例中事件的拥有者和响应者都是 from。示例中顺便演示了继承:
using System;
using System.Windows.Forms;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
// 1.事件拥有者 3.事件响应者 都是 from
var form= new MyForm();
// 2.事件成员 Click 5.事件订阅 +=
form.Click += form.FormClicked;
form.ShowDialog();
}
}
// 因为无法直接修改 Form 类,所以创建了继承与 Form 类的 MyForm 类
class MyForm : Form
{
// 4.事件处理器
internal void FormClicked(object sender, EventArgs e)
{
this.Text = DateTime.Now.ToString();
}
}
}
3、事件的拥有者是事件响应者的一个字段成员
这种是用得最广的:
using System;
using System.Windows.Forms;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
// 3.事件响应者 form
var form = new MyForm();
form.ShowDialog();
}
}
class MyForm : Form
{
private TextBox textBox;
// 1.事件拥有者 button
private Button button;
public MyForm()
{
this.textBox = new TextBox();
this.button = new Button();
this.Controls.Add(this.button);
this.Controls.Add(this.textBox);
// 2.事件成员 Click 5.事件订阅 +=
this.button.Click += this.ButtonClicked;
}
// 4.事件处理器
private void ButtonClicked(object sender, EventArgs e)
{
this.textBox.Text = "Hello, World!!!!";
}
}
}
最后
以上就是欣慰月饼最近收集整理的关于C#事件的声明与定义一、什么是事件二、事件的声明与定义方式三、常用的几种事件订阅方式的全部内容,更多相关C#事件内容请搜索靠谱客的其他文章。
发表评论 取消回复