事件(event)和委托(delegate)的综合运用实例(WinForm控件事件执行流程和原理),和EventHandler委托

前言

关于委托前面已经写了:

C#中委托(delegate)和多播委托的理解
Action和Func泛型委托,委托,泛型,匿名函数,Lambda表达式的综合使用

其实初衷是为了解WinFrom中的控件或者COM组件中的各种事件运行的机制,里面涉及的知识整理起来还是比较多的,各种类型的委托,事件,和泛型等。

这里先整理事件(event),然后通过几个实例了解架构中的事件从激活到调用回调函数的具体过程。

事件(event)

事件的官方文档
事件基于委托,为委托提供了一种发布/订阅机制,

  1. 可将事件理解为一种特殊用途的委托,或者说是受限制的委托,是委托一种特殊应用;
  2. 事件里面其实就两个方法(即add_event()remove_event())和一个私有的委托变量,这两个方法里面分别是对这个私有的委托变量进行的合并和移除,当调用事件的 += 时其实是调用的事件里面的add_event()方法,同样 -= 调用的是remove_event()方法;
  3. 事件只能够从对象外部增加新的响应方法和删除已知的响应方法,而不能主动去触发事件和获取其他注册的响应方法等信息。如果使用公有的delegate则不能做这些限制,也就是说事件对委托做了限制,使委托使用起来更加方便。

可以以下面这个图来理解:
事件(event)和委托(delegate)的综合运用实例(WinForm控件事件执行流程和原理),和EventHandler委托_第1张图片

从图中我们可以理解什么是发布者和订阅者,

且为什么说事件是特殊用途的委托,是受限制的委托?
限制一:不同于委托和类同级(可以在类的外边或者里边声明),事件只能在类中声明;
限制二:事件只能在声明该事件的类(发布者)中被调用,在订阅者中只能通过 +=-= 绑定或者移除回调方法;
在这里插入图片描述

标准的事件模式的步骤:

  1. 声明委托;
    这里我们没有定义委托,因为我们采用的是框架定义好的EventHandler泛型委托,如何理解这种委托?
    EventHandler泛型委托:
    https://docs.microsoft.com/zh-cn/dotnet/api/system.eventhandler-1?view=netframework-4.7.2
    是一个预定义的委托,表示生成数据的事件的事件处理程序方法。 使用的优点EventHandler是你不需要代码自定义委托,如果您的活动生成的事件数据。 只需作为泛型参数提供的事件数据对象的类型。
    它类似于前面提到的ActionFunc泛型委托,我们调用时只需要传入一个派生自基类EventArgs的参数,框架会自动生成默认委托为可以封装返回值为空,一个参数为object类型;另一个参数为我们传入的TEventArgs参数。
[Serializable]
public delegate void EventHandler(object sender, TEventArgs e);
  1. 声明事件;
    事件由发布者声明,且只能声明在类的内部;
 public event EventHandler NewCarInfo;//步骤二:声明事件
  1. 构建回调方法;
    在订阅者中构建回调函数newCarIsHere
  2. 绑定回调方法;
    在带哦也是通过 +=绑定回调方法,-= 解绑;可以通过传入可以被委托封装的方法或者该委托的实例;
//dealer.NewCarInfo += bmw.newCarIsHere;//步骤四:绑定回调方法,方法一
 dealer.NewCarInfo += new EventHandler(bmw.newCarIsHere);//步骤四:绑定回调方法,方法二
  1. 构建触发事件的方法;
    触发事件的方法定义在发布者中,触发之前检查事件绑定的回调函数是否为空;事件的调用类似与没有返回值的方法的调用,传入事件参数:事件源和事件相关信息;
  2. 调用触发事件的方法。
namespace EventAndDelegate
{
    /// 
    /// 
    /// 
    /// 
    /// 
    class Program
    {
        static void Main()
        {
            carDealer dealer = new carDealer();
            consumer my= new consumer("My");
            //dealer.NewCarInfo += my.newCarIsHere;//步骤四:绑定回调方法,方法一
            dealer.NewCarInfo += new EventHandler(my.newCarIsHere);//步骤四:绑定回调方法,方法二           
            dealer.NewCar("BMW");//步骤六:调用触发事件的方法
            consumer you= new consumer("YOU");
            dealer.NewCarInfo += you.newCarIsHere;
            dealer.NewCar("AMG");
            dealer.NewCarInfo -= my.newCarIsHere;
            dealer.NewCar("AMG");          
            Console.ReadLine();
        }
    }
    public delegate void delegateMOT(int x,int y);
    
    /// 
    /// 事件发布者 carDealer
    /// 
    public class carDealer
    {
        public event EventHandler NewCarInfo;//步骤二:声明事件

        public void NewCar(string car)//步骤五:构建触发事件的方法
        {
            Console.WriteLine("carDealer,new car {0}", car);
            if (NewCarInfo != null)//判断委托是否为空,如果没有订阅程序,则为空
            {
                NewCarInfo(this, new carInfoEventArgs(car));//触发事件传入事件的发送者和和事件的相关信息
            }
        }
    }

    /// 
    /// 事件订阅者 consumer
    /// 
    public class consumer
    {
        private string name;

        public consumer(string name)
        {
            this.name = name;
        }
        /// 
        /// 步骤三:构建回调方法
        /// 
        /// 
        /// 
        public void newCarIsHere(object sender,carInfoEventArgs e)
        {
            Console.WriteLine("{0}:car {1} is new",name,e.car);
        }
    }

    /// 
    /// carInfoEventArgs 为事件参数,是一个只包含car属性的对象,注意继承EventArgs
    /// 
    public class carInfoEventArgs : EventArgs
    {
        public carInfoEventArgs(string car)
        {
            this.car = car;
        }
        public string car { get; private set; }
    }        
}

结果:

carDealer,new car BMW
My:car BMW is new
carDealer,new car AMG
My:car AMG is new
YOU:car AMG is new
carDealer,new car AMG
YOU:car AMG is new

你可能感兴趣的:(C#,委托,多播委托,泛型委托,事件)