Asp.Net教程,WinForm教程,Asp.Net MVC,vs2008教程,vs2010教程,Silverlight技术,源码下载,Asp.Net视频教程
全站热门标签
vs2010 Silverlight 存储过程 水晶报表 ADO.NET JavaScript LINQ AjaxPro DataGridView 面向对象 Extjs GridView XML DevExpress HTML教程 Oracle jQuery 分页 GDI+ Visual C++2010 MySQL Office2010 WPF MVC Dojo WCF4.0 VB.NET Sql2005 textbox cookie WCF WinForm Discuz!NT SQL经典语句 T-SQL checkbox ASPxGridView F# asp.net SQL VS2008新特性 DropDownList Access TreeView Ajax VS2008 页面执行时间 Flex 字符串 回调 VB2005 DataSet C#时间 ASP.NET性能优化 用户在线检测 动画
尚未分类 LINQ教程 Enterprise技术 性能优化/调试 水晶报表与打印 安全与加密 图形图像 文件处理基础教程 Web Services 内置对象 控件示例 正则表达式\采集 ADO.NET 缓存\泛型\线程 XML技术 Url重写\静态页 vs2008综合教程
当前位置: 主页 > ASP.NET教程 > 基础教程 >

委托和事件:从猫和老鼠的故事看事件(2)

时间:2010-07-29 10:09来源:未知 作者:admin 点击:

    //Cat类是事件的生成者,通过OnCry()方法引发Cry事件
    //但Cat类并不知道谁会监听Cry事件,以及如何理Cry事件,它只是告诉环境Cry事件发生了
    //通俗的解释是:猫叫了,但猫并不知道它的叫声对环境有什么影响
    public class Cat
    {
        //定义一个事件,表示猫叫
        public static event CryEventHandler Cry;

        //猫的描述信息
        private string description;

        public string Description
        {
            get { return description; }
            set { description = value; }
        }

        public Cat(string description)
        {
            this.description = description;
            Console.WriteLine("Cat:" + this.description + " coming.");
        }

        public virtual void OnCry()
        {
            Console.WriteLine("Cat:MiaoMiao");

            //将事件的发送者和事件信息作为参数传递给事件处理函数
            CryEventArgs e = new CryEventArgs();
            e.Description = this.description;

            if (Cry != null)
            {
                Cry(this, e);
            }
        }
    }


    //Mouse类是事件的订阅者,定义了Cry事件发生时的处理方法Run()
    //通俗的解释是:老鼠在夜间行动时,时刻都在堤防着猫,如果听到猫叫声马上离开
    public class Mouse
    {
        public Mouse()
        {
            Cat.Cry += new CryEventHandler(Run);
            Console.WriteLine("Mouse:I go to find something,and I must always listen cat's crying.");
        }
       
        //老鼠听到猫叫声,会先判断是哪种猫,然后再采取下一步行动
        public void Run(object sender, CryEventArgs e)
        {
            string catDescription = e.Description;
            //注释掉的这句效果是一样的
            //string catDescription = ((Cat)sender).Description;
            if (catDescription.Equals("aBenCat"))
            {
                Console.WriteLine("Mouse:" + catDescription + ",I am not afraid!");
            }
            else
            {
                Console.WriteLine("Mouse:" + catDescription + ",I must run!");
            }
        }
    }


    public class Demo2
    {
        public static void Main(string[] args)
        {
            Mouse mouse = new Mouse();

            Cat cat1 = new Cat("aBenCat");
            cat1.OnCry();

            Cat cat2 = new Cat("smartCat");
            cat2.OnCry();

            Console.ReadLine();
        }
    }
运行后控制台输出为:
      Mouse:I go to find something,and I must always listen cat's crying.
      Cat:aBenCat coming.
      Cat:MiaoMiao...
      Mouse:aBenCat,I am not afraid!
      Cat:smartCat coming.
      Cat:MiaoMiao...
      Mouse:smartCat,I must run!

      通过上面的两个示例可以看到,事件的本质是委托,事件发生时,会去执行通过委托指定的回调函数,但回调函数不是由事件的发生者指定,而是由事件的订阅者来指定的,这就形成了一种松耦合关系。
      事件和委托的关系让人迷惑,感觉是因为.NET中定义的事件多是由系统自动触发的,而不是像上面的例子在Main函数中调用了Cat.OnCry()方法。如System.Web.UI.Button类的Click事件,我们只要在客户端点击Button就自动触发了Click事件,并没有在Page类调用Button.OnClick()方法,实际上也不可以调用,因为该方法的访问权限是portected。但我们仔细研究Button类不难发现,当单击按钮时,处理窗体回发事件的RaisePostBackEvent()方法就会执行(感兴趣的朋友可以进一步研究为什么会执行),在Button类就是在这个方法中调用了OnClick方法。下面给出Button类中和Click事件相关的代码:

 //定义一个委托
    public delegate void EventHandler(object sender, EventArgs e);

    //Button类实现,省略了与Click事件无关的代码
    public class Button : WebControl, IButtonControl, IPostBackEventHandler
    {
        //用作委托列表的关键字
        private static readonly object EventClick;

        static Button()
        {
            EventClick = new object();
        }

        //添加或移除事件处理程序
        public event EventHandler Click
        {
            add
            {
                base.Events.AddHandler(EventClick, value);
            }
            remove
            {
                base.Events.RemoveHandler(EventClick, value);
            }
        }

        //protected表明只能是自己或子类调用,不允许其它类调用
        protected virtual void OnClick(EventArgs e)
        {
            EventHandler handler = (EventHandler)base.Events[EventClick];
            if (handler != null)
            {
                handler(this, e);
            }
        }

        //处理窗体发送给服务器时引发的事件,即Click事件
        protected virtual void RaisePostBackEvent(string eventArgument)
        {
            base.ValidateEvent(this.UniqueID, eventArgument);
            if (this.CausesValidation)
            {
                this.Page.Validate(this.ValidationGroup);
            }
            //EventArgs.Empty表示没有事件数据的事件,等同于EventArgs类的构造函数
            this.OnClick(EventArgs.Empty);
        }
    }
 

(责任编辑:admin)
Tags:委托
责任编辑:admin
返回顶部
------分隔线----------------------------
推荐内容
骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价 骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价
  • C#中Dictionary、ArrayList、Hashtable和数组Array

    C# 集合类 Array Arraylist List Hashtable Dictionary Stack Queue 1.数组是固定大小的,不能伸缩。虽然S...

  • PictureBox内的图片拖动功能

    当 PictureBox内的图片太大,超过PictureBox边框时可以用下面的方法来实现, 通过重绘来实现 : Code bool wselected = f...

  • Directory.GetCurrentDirectory和Application.

    System.IO.Directory.GetCurrentDirectory()方法用于获得应用程序当前工作目录。 System.Windows.Forms....

  • IConvertible接口

    IConvertible 接口 定义特定的方法,这些方法将实现引用或值类型的值转换为具有等效值的公共语言运行库类型。 命名空间: System 程序集: msc...

  • 将枚举类型的数据绑定到控件

    .NET Framework中的数据绑定有几个很酷的功能。你不仅可以将集合、数组、DataTable和DataView对象绑定到列表绑定(list-bound)...

  • 数组求和算法系列

    一直想写一个数组求和算法系列博客,但由于自己算法能力有限,完成不了,只能完成其中简单的部分,难的部分希望有园友愿意和我一起完成。在写这篇博客的过程中借用了别人的...

  • 细说C#构造器

    1.实例构造器和类 构造器是允许将类型的实例化为良好的状态的一种特殊方法。 当创建一个类型的实例时: 1)为实例的字段分配内存。 2)初始化对象的附加字段(类型...

  • 对象的序列化存入数据库,与反序列化

    开发过程中遇到一个问题,我想到的解决方法是将一个dictionary字典如何存如数据库,读出来的时候还是这个字典 然后接触到对象的序列化与反序列化。开始打算序列...

  • const限定修饰符用法总结(常量,指针,迭代器,函数参数,成员函数)

    const限定修饰符用法总结(常量,指针,迭代器,函数参数,成员函数)...

  • 回文算法

    回文:针对于字符串的中间位置两边对应位置相等。对于长度为n的字符串,需要比较的次数为N/2。 用2种方法对该应用实现算法如下: 1:采用字符串的substrin...

  • c# MACD算法实现

    c# MACD算法实现...

  • c#自杀程序的关键方法

    public static void TestForKillMyself() { string bat=@@echooff :tryagain del%1 if...

  • 对泛型进行反射

    今天在用反射的时候突然想到,之前从来没有对泛型对象进行反射,故决定尝试一下 首先要获取某个泛型类的Type,键入如下代码: Typet=Type.GetType...

  • C#遍历文件夹

    DirectoryInfo FileName = new DirectoryInfo( @D:\ ); 2 foreach (DirectoryInfo Nex...

  • .NET对象序列化—TimeSpan

    在 WebServices 中, TimeSpan 不能作为系统的 TimeSpan 作为参数,在客户端会生成新的 TimeSpan 类。 一、问题重现 创建一...