事件学习一:直接事件模型+委托
文章参考总结一下博客
C#中的委托和事件(续) - Jimmy Zhang - 博客园 (cnblogs.com)
C#中委托和事件的区别 - Darren Ji - 博客园 (cnblogs.com)
C#中委托、事件和回调函数的理解 - 每天进步多一点 - 博客园 (cnblogs.com)
1.通过委托来执行方法
delegate int Transformer(int i); class Program { static void Main(string[] args) { Transformer t = Square; int result = t(2); Console.Read(); } static int Square(int a) { return a * a; } }
所有委托都有多播能力,可以使用+=运算符联结多个委托实例。
Transformer t = Square1;
t += Square2;
委托是不可变的,调用+=和-=实质上是创建一个委托实例,并把它赋给已有变量。
C#委托和事件的使用示例 - vickylinj - 博客园 (cnblogs.com)可以看委托的使用。
2.通过事件来执行方法
事件是一种使用有限的委托功能实现广播(发布)者/订阅者模型的结构,使用事件的主要目的是保证订阅者之间部相互干扰。事件自身就是委托类型。
- 发布者是指拥有某事件的类或者结构
- 订阅者是指向发布者注册的类或者结构
- 事件处理程序是指由订阅者注册到事件的方法,在发布者触发事件时执行
摘自C#沉淀-事件:发布订阅模式_东南有大树的博客-CSDN博客_c# 发布订阅模式
标准事件模式
class Model { public Model(int a1) { MyProperty = a1; } public int MyProperty { get; set; } } class Stock//它就是广播者 { public event EventHandler<Model> ModelEvent; protected virtual void OnModelEvent(Model e) { ModelEvent?.Invoke(this, e);//第一个参数表示事件的广播者,e表示需要传递的额外信息 } private int price; public int Price { get { return price; } set { if (price == value) return; price = value; OnModelEvent(new Model(price));//属性改变了的时候通知订阅者 } } } class Program { static void Main(string[] args) { Stock stock = new Stock(); stock.ModelEvent += stock_ModelEvent; stock.Price = 8;//改变 Console.Read(); } static void stock_ModelEvent(object sender,Model e) { Console.WriteLine(e.MyProperty); } }
通过如上可以引出----当一个类中的数据改变时可以使用事件来通知另外的一个类。
class Model { public Model(int a1) { MyProperty = a1; } public int MyProperty { get; set; } } class Stock { public event EventHandler<Model> ModelEvent; protected virtual void OnModelEvent(Model e) { ModelEvent?.Invoke(this, e);//第一个参数表示事件的广播者,e表示需要传递的额外信息 } Thread thread1; public void Start() { thread1 = new Thread(new ThreadStart(Method)); thread1.IsBackground = true; thread1.Start(); } void Method() { for (int i = 0; i < 10; i++) { Thread.Sleep(1000); OnModelEvent(new Model(i));//属性改变了的时候通知订阅者 } } } static void Main(string[] args) { Stock stock = new Stock(); stock.ModelEvent += stock_ModelEvent; stock.Start(); Console.Read(); } static void stock_ModelEvent(object sender,Model e) { Console.WriteLine(e.MyProperty); }
通过上诉还可引出---该通知功能还可以用在线程中。
有了委托为什么还要有事件??摘自C#中的委托与事件并存的理由 - ____轨迹 - 博客园 (cnblogs.com)
委托可被任意调用者修改,甚至抹去所有的委托链,而对于事件,只能由订阅者自己决定订阅或者移除事件。事件的密封性较好,他从本质层面上反映出了事件是属于发布者的,订阅者只能决定自己订阅的事件,不能影响发布者
的所有订阅对象。你为了反映这一事实,就不能使用委托来替代。
举例1:通过委托和事件实现窗口之间的传值
子窗口
public delegate void ChildFormHandler(string value); public partial class ChildForm : Form { public event ChildFormHandler ChildFormEvent; public ChildForm() { InitializeComponent(); } private void btnChild_Click(object sender, EventArgs e) { ChildFormEvent("a");//执行第一步 this.Close();//执行第三步 } }
父窗口
private void btnParent_Click(object sender, EventArgs e) { ChildForm childForm = new ChildForm(); childForm.ChildFormEvent += new ChildFormHandler(Method); childForm.Show(); } void Method(string value)//执行第二步 { }
总结:
○ 委托就是一个类,也可以实例化,通过委托的构造函数来把方法赋值给委托实例
○ 触发委托有2种方式: 委托实例.Invoke(参数列表),委托实例(参数列表)
○ 事件是一个用event关键字修饰的委托类型的变量
○ 通过+=为事件注册多个委托实例或多个方法
○ 通过-=为事件注销多个委托实例或多个方法
○ EventHandler就是一个委托
委托较直接调用方法优点:
1.相当于用方法作为另一方法参数(类似于C的函数指针)
2.在两个不能直接调用的方法中作为桥梁,如:在跨线程的方法调用就得用委托
3.当不知道方法具体实现什么时使用委托,如:事件中使用委托
4.解耦
直接事件模型的缺点:
1.程序运行期在容器中动态生成一组相同控件的时候,需要显示书写事件订阅代码。
2.当户控件的内部事件不能被外界所订阅,必须为用户控件定义新的事件用以向外界暴露内部事件。