zoukankan      html  css  js  c++  java
  • C#委托与事件

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    //****************************************事件与委托*************************************************************
     /* Observer设计模式中主要包括如下两类对象:
    Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是temprature字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。 Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器和显示器,它们采取的行动分别是发出警报和显示水温。 在本例中,事情发生的顺序应该是这样的:
    警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。 热水器知道后保留对警报器和显示器的引用。 热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法、显示器的ShowMsg()方法。 类似这样的例子是很多的,GOF对它进行了抽象,称为Observer设计模式:Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。* /
    /* 委托类型的名称都应该以EventHandler结束。 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。 事件的命名为 委托去掉 EventHandler之后剩余的部分。 继承自EventArgs的类型应该以EventArgs结尾。
     * 再做一下说明:
    委托声明原型中的Object类型的参数代表了Subject,也就是被监视对象,在本例中是 Heater(热水器)。回调函数(比如Alarm的MakeAlert)可以通过它访问触发事件的对象(Heater)。 EventArgs 对象包含了Observer所感兴趣的数据,在本例中是temperature。上面这些其实不仅仅是为了编码规范而已,这样也使得程序有更大的灵活性。比如说,如果我们不光想获得热水器的温度,还想在Observer端(警报器或者显示器)方法中获得它的生产日期、型号、价格,那么委托和方法的声明都会变得很麻烦,而如果我们将热水器的引用传给警报器的方法,就可以在方法中直接访问热水器了。*/

    namespace DelegateLearning
    {
        //热水器
        public class Heater
        {
            private int temperature;
            public string type = "RealFire 001"; // 添加型号作为演示
            public string area = "China Xi'an"; // 添加产地作为演示
            /*声明委托中,sender为被监视对象,回调函数通过它访问触发事件的对象;e为EventArgs对象包含了Observer所感兴趣的数据,即被监视的信息。
            /*委托类型的名称都应该以EventHandler结束。*/
            /*委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。*/
            public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);//声明委托
            /*事件名为委托名除去EventHandler剩下的部分*/
            //声明一个事件类似于声明一个进行了封装的委托类型的变量
            public event BoiledEventHandler Boiled; //声明事件
            // 定义BoiledEventArgs类,传递给Observer所感兴趣的信息
            public class BoiledEventArgs : EventArgs //继承EventArgs
            {
                public readonly int temperature;//temperature为类BoiledEventArgs的只读属性
                public BoiledEventArgs(int temperature)//构造函数,没有返回值,也不用void修饰
                {
                    this.temperature = temperature;
                }
            }
            // 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
            protected virtual void OnBoiled(BoiledEventArgs e)
            {
                if (Boiled != null)// 如果有对象注册,事件不为空
                {
                    Boiled(this, e); // 调用所有注册对象的方法
                }
            }
            // 烧水
            public void BoilWater()
            {
                for (int i = 0; i <= 100; i++)
                {
                    temperature = i;
                    if (temperature > 95)
                    {
                        //建立BoiledEventArgs 对象。
                        BoiledEventArgs e = new BoiledEventArgs(temperature);
                        OnBoiled(e); // 调用 OnBoiled方法
                    }
                }
            }
        }
        // 警报器
        public class Alarm
        {
            public void MakeAlert(Object sender, Heater.BoiledEventArgs e)
            {
                Heater heater = (Heater)sender; //这里是不是很熟悉呢?
                //访问 sender 中的公共字段
                Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
                Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
                Console.WriteLine();
            }
        }
        // 显示器
        public class Display
        {
            public static void ShowMsg(Object sender, Heater.BoiledEventArgs e)
            { //静态方法
                Heater heater = (Heater)sender;
                Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
                Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
                Console.WriteLine();
            }
        }
        class Program
        {
            static void Main()
            {
                Heater heater = new Heater();
                Alarm alarm = new Alarm();
                //以下给对象heater中的事件Boiled注册方法
                //将方法封装(注册)在委托类型变量(事件)里
                heater.Boiled += alarm.MakeAlert; //注册方法
                heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法
                heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册
                heater.Boiled += Display.ShowMsg; //注册静态方法
                heater.BoilWater(); //烧水,会自动调用注册过对象的方法
            }
        }
    }
    /*
     * 理解:事件的响应方法其实就是事件所封装的方法本身,如方法private void button1_Click(object sender, System.EventArgs e) 就是对事件button1_Click的响应方法,可以通过+=给事件注册其它方法。
     * private void OtherSomething(object sender,System.EventArgs e)
     * this.button1.Click += new System.EventHandler(OtherSomething);
     * 使用委托可以将多个方法绑定到同一个委托变量(事件),当调用此变量时(这里用“调用”这个词,是因为此变量代表一个方法),可以依次调用所有绑定的方法。
     *
     * Event封装了委托类型的变量。在类的内部,不管声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与在声明事件时使用的访问符相同。

     * ********************************************( object sender , EventArgs e )*********************************
     * ( object sender , EventArgs e ) 是C#里面的事件响应的代码
    EventArgs是包含事件数据的类的基类,用于传递事件的细节。
    EventHandler是一个委托(其在.Net类库中是如下声明的)
    委托声明为:public delegate void EventHandler( object sender , EventArgs e )
    所以,所有形如:  void 函数名(object 参数名,EventArgs 参数名); 的函数都可以作为Control类的Click事件响应方法了。Object的参数名一般用Source或Sender来表示,两个没有区别。
    如下面所定义的一个事件响应方法:
    private void button1_Click(object sender, System.EventArgs e)
    参数object sender表示引发事件的对象(其实这里传递的是对象的引用,如果是button1的click事件则sender就是button1)
    * System.EventArgs e 代表事件的相应信息。

    下面我们可以看下Button类的事件声明,以Click事件为例。
    public event EventHandler Click;
    这里定义了一个EventHandler类型的事件Click
    private void button1_Click(object sender, System.EventArgs e)
                 {
                           ...
                     }
    这是我们和button1_click事件所对应的方法。
    那我们怎么把这个方法和事件联系起来呢,请看下面的代码。
    this.button1.Click += new System.EventHandler(this.button1_Click);
     * 当button1按钮触发点击事件时再次触发this.button1_Click方法(+= 在原有基础上再加上,就是重新添加)
    把this.button1_Click方法绑定到this.button1.Click事件。
     *
    以上原理简单理解下就可以了,在实际操作中我们只需要在代码里面调用Web控件里面使用button控件,里面的属性OnClick="button1_Click" 语句便可以起到调用方法的功能了。在VS.NET中可以直接在设计页面加入button, 而上面红色的那行代码编译器会自动实现(可在cs代码文件里面看到)。
     *
     * *****************************************************EventHandler*************************************************************
     * EventHandler表示将处理不包含事件数据的事件的方法。
    命名空间:System
    程序集:mscorlib(在 mscorlib.dll 中)
    C#
    [SerializableAttribute]
    [ComVisibleAttribute(true)]
    public delegate void EventHandler (Object sender,EventArgs e)
     * sender 事件源, e 不包含任何事件数据的 EventArgs。
    备注:
    .NET Framework 中的事件模型基于具有事件委托,该委托将事件与事件处理程序连接。引发事件需要两个元素:
    一个是标识对事件提供响应的方法的委托,另一个是保存事件数据的类。
    委托是一个定义签名的类型,即方法的返回值类型和参数列表类型。可以使用委托类型来声明一个变量,该变量可以引用与委托签名相同的所有方法。
    事件处理程序委托的标准签名定义一个没有返回值的方法,其第一个参数的类型为 Object,它引用引发事件的实例,第二个参数从 EventArgs 类型派生,它保存事件数据。如果事件不生成事件数据,则第二个参数只是 EventArgs 的一个实例。否则,第二个参数为从 EventArgs 派生的自定义类型,提供保存事件数据所需的全部字段或属性。
    EventHandler 是一个预定义的委托,专用于表示不生成数据的事件的事件处理程序方法。如果事件生成数据,则必须提供自己的自定义事件数据类型,并且必须要么创建一个委托,其中第二个参数的类型为自定义类型,要么使用泛型 EventHandler 委托类并用自定义类型替代泛型类型参数。
    若要将事件与处理事件的方法关联,请向事件添加委托的实例。除非移除了该委托,否则每当发生该事件时就调用事件处理程序。
     */

  • 相关阅读:
    csharp: Cyotek.GhostScript.PdfConversion pdf convert image
    csharp: using Acrobat.dll pdf convert images in winform
    机器学习实战---K均值聚类算法
    机器学习实战---决策树CART回归树实现
    机器学习实战---决策树CART简介及分类树实现
    机器学习实战---线性回归(更好的使用正规方程求解)
    机器学习实战---逻辑回归梯度上升(更好的理解sigmoid函数的含义并改进)
    机器学习实战---朴素贝叶斯算法使用K折交叉验证
    机器学习实战---朴素贝叶斯算法
    机器学习实战---决策树ID3算法
  • 原文地址:https://www.cnblogs.com/getyoulove/p/3656096.html
Copyright © 2011-2022 走看看