| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4363 人关注过本帖, 1 人收藏
标题:【交流探讨】说说你本人对“事件”的理解……
只看楼主 加入收藏
skyzoneskyzone
Rank: 1
等 级:新手上路
威 望:1
帖 子:137
专家分:0
注 册:2008-10-6
收藏
得分:0 
windows上的一举一动都可以看作是windows消息,C#通过事件可以对这些消息进行处理.所以事件的作用很实用的.

读万卷书莫如行万里路,行路在问题答题之中。
2008-10-18 11:13
Wadialin
Rank: 1
等 级:新手上路
帖 子:243
专家分:0
注 册:2006-9-20
收藏
得分:0 
委托的声明

public delegate void MyDelegate(string str);

1.委托的定义和方法的定义类似,只是在前面加了一个delegate,但委托不是方法,它是一种类型。是一种特殊的类型,看成是一种新的对象类型比较好理解。用于对与该委托有相

同签名的方法调用。
2.委托相当于C++中的函数指针,但它是类型安全的。
3.委托是从System.Delegate派生,但不能象定义常规类型一样直接从System.Delegate派生,对委托的声明只能通过上面的声明格式进行定义。关键字delegate通知编译器这是一

个委托类型,从而在编译的时候对该类进行封装,对这一过程C#定义了专门的语法来处理这一过程。
4.不能从一个委托类型进行派生,因为它也是默认sealed的
5.委托即可以对静态方法进行调用也可以对实例方法进行调用。
6.每个委托类型包含一个自己的调用列表,当组合一个委托或从一个委托中删除一个委托时都将产生个新的调用列表。
7.两个不同类型的委托即使它们有相同的签名和返回值,但还是两个不同类型的委托。但其实在使用中可看作是相同的。


委托的比较

C#中对委托定义了两个操作符 == 和 !=
在以下情况下两个委托是相等的:
1.当两个委托都同时为null的时候
2.当两个委托都不为null时,下列情况下是相等的。
a.当两个委托的各自的调用列表只含有一个入口点的时候
   在下列情况下是相等的
   (1) 调用同一对象的同一静态方法
   (2) 调用同一对象的同一实例方法
b.当两个委托具有多个入口点时
   在下列情况下是相等的
   (1)只有当它们调用列表中的调用的方法按顺序都一一对应相同的对象及对象的同一方法的时候

如上所述的两个不同类型的委托但是它们具有相同的签名和返回值时,只要满足上述条件的,即使它们类型不同,但比较的结果也是相同的。

委托的异常处理

当调用该委托的方法中发生了异常时,首先在调用该委托的方法中搜寻catch语句块。如果没有,则去该委托调用的方法中去寻找有没有catch语句块,这和调用方法发生异常的处

理是一样的。

当调用一个为null的委托即委托中列表中不存在调用方法时,将发生NullRefrenceException

委托的注意点:
当一个委托有多个入口点的时候,调用委托将依该委托的调用列表中的方法的顺序依次调用.这些方法共享一个参数集合,所以当委托有返回值的时候调用完这个委托后的返回值是最

后一个方法的返回值或是有out参数.如果该委托的参数为ref(引用类型),那么在招待第一个方法的时候如果对这个参数的值有所改变,那么这个改变将会影响到后面的方法调用.

委托的一个例子

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建一个委托实例,封装C类的静态方法M1
            MyDelegate d1 = new MyDelegate(C.M1);
            d1("D1"); // M1

            // 创建一个委托实例,封装C类的静态方法M2
            MyDelegate d2 = new MyDelegate(C.M2);
            d2("D2"); // M2

            // 创建一个委托实例,封装C类的实例方法M3
            MyDelegate d3 = new MyDelegate(new C().M3);
            d3("D3"); // M3

            // 从一个委托d3创建一个委托实例
            MyDelegate d4 = new MyDelegate(d3);
            d4("D4"); // M3

            // 组合两个委托
            MyDelegate d5 = d1 + d2;
            d5 += d3;
            d5("D5"); // M1,M2,M3

            // 从组合委托中删除d3
            MyDelegate d6 = d5 - d3;
            d6("D6"); // M1,M2
            d6 -= d3; // 虽然d6调用列表中已经没有d3了,但这样只是不可能的移除没有错误发生
            d6("D6"); // M1,M2
            d6 -= d6;
            //d6("D6"); 此时d6的调用列表为空,d6为null,所以引发System.NullReferenceException

            MyDelegate d7 = new MyDelegate(C1.P1);
            d7("D7"); // C1.P1

            MyDelegate d8 = new MyDelegate(new C2().P1);
            d8("D8"); // C2.P1

        }
    }

    // 声明一个委托MyDelegate
    public delegate void MyDelegate(string str);

    public class C
    {
        public static void M1(string str)
        {
            Console.WriteLine("From:C.M1:   {0}", str);
        }

        public static void M2(string str)
        {
            Console.WriteLine("From:C.M2:   {0}", str);
        }

        public void M3(string str)
        {
            Console.WriteLine("From:C.M3:   {0}", str);
        }
    }

    public class C1
    {
        public static void P1(string str)
        {
            Console.WriteLine("From:C1.P1:   {0}", str);
        }
    }

    public class C2
    {
        public void P1(string str)
        {
            Console.WriteLine("From:C2.P1:   {0}", str);
        }
    }   
}

事件委托

事件概述

事件就是当对象或类状态发生改变时,对象或类发出的信息或通知。发出信息的对象或类称为"事件源",对事件进行处理的方法称为"接收者",通常事件源在发出状态改变信息时,它

并不知道由哪个事件接收者来处理.这就需要一种管理机制来协调事件源和接收者,C++中通过函数指针来完成的.在C#中事件使用委托来为触发时将调用的方法提供类型安全的封装


事件的声明

1.声明一个委托
public delegate void EventHandler(object sender, System.EventArgs e);

2.声明一个事件
public event EventHandler Changed;

3.引发一个事件
public OnChanged(EnventArgs e)
{
 if ( Changed != null)
 {
  Changed(this,e);
 }
}

4.定义事件处理程序
public MyText_OnChanged(Object sender,EventArgs e)
{
 ...
}

5.订阅事件(将事件处理程序添加到事件的调用列表中)

myText.Changed += EventHandler(MyText_OnChanged);

下面的一个小例子说明了怎样定义一个完整的事件机制:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {        
        static void Main(string[] args)
        {              
            MyText myText = new MyText();

            // 将事件处理程序添加到事件的调用列表中(即事件布线)
            myText.Changed += new MyText.ChangedEventHandler(myText_Changed);         
            
            string str = "";
            while (str != "quit")
            {
                Console.WriteLine("please enter a string:");
                str = Console.ReadLine();
                myText.Text = str;
            }
        }

        // 对Change事件处理的程序
        private static void myText_Changed(object sender, EventArgs e)
        {
            Console.WriteLine("text has been changed  :{0}\n" ,((MyText)sender).Text);
        }        
    }  

    public class MyText
    {
        private string _text = "";

        // 定义事件的委托
        public delegate void ChangedEventHandler(object sender, EventArgs e);

        // 定义一个事件
        public event ChangedEventHandler Changed;

        // 用以触发Change事件
        protected virtual void OnChanged(EventArgs e)
        {
            if (this.Changed != null)
                this.Changed(this, e);
        }

        // Text属性
        public string Text
        {
            get { return this._text; }
            set
            {
                this._text = value;
                // 文本改变时触发Change事件
                this.OnChanged(new EventArgs());
            }
        }
    }
}   

转自 http://

冷静~~
2008-10-18 11:56
Wadialin
Rank: 1
等 级:新手上路
帖 子:243
专家分:0
注 册:2006-9-20
收藏
得分:0 
C#事件机制归纳1.委派的实现过程。

首先来看一下委派,委派其实就是方法的传递,并不定义方法的实现。事件其实就是标准化了的委派,为了事件处理过程特制的、稍微专业化一点的组播委派(多点委派)。下面举一个例子,我觉得把委派的例子和事件的例子比较,会比较容易理解。

using System;

 

class Class1

{

       delegate int MathOp(int i1,int i2);

       static void Main(string[] args)

       {

               MathOp op1=new MathOp(Add);

               MathOp op2=new MathOp(Multiply);

               Console.WriteLine(op1(100,200));

              Console.WriteLine(op2(100,200));

               Console.ReadLine();

       }

       public static int Add(int i1,int i2)

       {

               return i1+i2;

       }

       public static int Multiply(int i1,int i2)

       {

              return i1*i2;

       }

}

 

首先代码定义了一个委托MathOp,其签名匹配与两个函数Add()和Multiply()的签名(也就是其带的参数类型数量相同):

delegate int MathOp(int i1,int i2);

Main()中代码首先使用新的委托类型声明一个变量,并且初始化委托变量.注意,声明时的参数只要使用委托传递的函数的函数名,而不加括号:

MathOp op1=new MathOp(Add);

(或为MathOp op1=new MathOp(Multiply);)

委托传递的函数的函数体:

public static int Add(int i1,int i2)

{

       return i1+i2;

}

public static int Multiply(int i1,int i2)

{

      return i1*i2;

}

然后把委托变量看作是一个函数名,将参数传递给函数。 Console.WriteLine(op1(100,200));

Console.WriteLine(op2(100,200));

 

 

2.事件的实现过程

using System;

 

class Class1

{

       static void Main(string[] args)

       {

               Student s1=new Student();

               Student s2=new Student();

               s1.RegisterOK +=new Student.DelegateRegisterOkEvent(Student_RegisterOK);

               s2.RegisterOK +=new Student.DelegateRegisterOkEvent(Student_RegisterOK);

               s1.Register();

               s2.Register();

               Console.ReadLine();

       }

       static void Student_RegisterOK()

       {

              Console.WriteLine("Hello");

       }

}

 

class Student

{

       public delegate void DelegateRegisterOkEvent();

       public event DelegateRegisterOkEvent RegisterOK;

       public string Name;

       public void Register()

       {

               Console.WriteLine("Register Method");

              RegisterOK();

       }

}

在Student类中,先声明了委托DelegateRegisterOkEvent(),然后使用event和要使用的委托类型(前面定义的DelegateRegisterOkEvent委托类型)声明事件RegisterOK(可以看作是委托的一个实例。):

public delegate void DelegateRegisterOkEvent();

public event DelegateRegisterOkEvent RegisterOK;

然后在Main()函数中,实例化Student类,然后s1.RegisterOK事件委托给了Student_RegisterOK 方法。通过“+=”(加等于)操作符非常容易地为.Net对象中的一个事件添加一个甚至多个响应方法;还可以通过非常简单的“-=”(减等于)操作符取消这些响应方法。

然后,当调用s1.Register()时,事件s1.RegisterOK发生。

 

3.C#中预定义事件处理方式

    学习事件,我觉得最不好理解的就是C#中预定义了事件,使我才开始学习事件时一头雾水。在查了些资料后,终于弄明白了一些,如下:

EventArgs是包含事件数据的类的基类,用于传递事件的细节。

EventHandler是一个委托声明如下(其在.Net类库中如下声明的)

public delegate void EventHandler( object sender , EventArgs e )
所以,所有形如:

void 函娄名(object 参数名,EventArgs 参数名);

的函数都可以作为Control类的Click事件响应方法了。如下面所定义的一个事件响应方法:

private void button1_Click(object sender, System.EventArgs e)

参数object sender表示引发事件的对象,(其实这里传递的是对象的引用,如果是button1的click事件则sender就是button1)System.EventArgs e 代表事件的相应信息,如鼠标的x,y值等。

下面我们研究一下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.Click 为System.EventHandler委派的实例事件。与委派中委派实例委托给某一方法非常相似)
把this.button1_Click方法绑定到this.button1.Click事件。

 

 

4.事件的参数的使用。

using System;

 

class Class1

{

       static void Main()

       {

               Student s1=new Student();

               s1.Name ="Student1";

               Student s2=new Student();

               s2.Name ="Student2";

              s1.RegisterOK +=new Student.DelegateRegisterOkEvent(Student_RegisterOK);

               s2.RegisterOK +=new Student.DelegateRegisterOkEvent(Student_RegisterOK);

 

               //当Register方法一执行,触发RegisterOK事件

               //RegisterOK事件一触发,然后执行Student_RegisterOK方法

               s1.Register();  

              s2.Register();

              Console.ReadLine();

       }

       static void Student_RegisterOK(RegisterOkArgs e)

       {

              Console.WriteLine(e.EventInfo);

       }

}

 

class Student

{

       public delegate void DelegateRegisterOkEvent(RegisterOkArgs e);

       public event DelegateRegisterOkEvent RegisterOK;

       public string Name;

       public void Register()

       {

              Console.WriteLine("Register Method");

              RegisterOK(new RegisterOkArgs("Student Name: "+Name));

       }

}

class RegisterOkArgs:EventArgs

{

       public string EventInfo;

       public RegisterOkArgs(string eventInfo):base()

       {

              this.EventInfo =eventInfo;

       }

}

转自  http://

冷静~~
2008-10-18 11:57
小仙
Rank: 7Rank: 7Rank: 7
来 自:光之谷
等 级:贵宾
威 望:39
帖 子:1812
专家分:1
注 册:2008-8-8
收藏
得分:0 
回复 8# 静夜思 的帖子
呃。。怎么改标题的呢?我想的是合并再分离帖子。。。那样太麻烦了点。


仁者乐膳,智者乐睡。我都爱~
2008-10-18 21:48
zhutoudd
Rank: 1
等 级:新手上路
帖 子:29
专家分:0
注 册:2008-6-24
收藏
得分:0 
委托和事件我感觉最主用的地方还是用在于2个窗体之间的传值或第一个窗体想让第二个窗体做一些事情,必须要发出一个指令,就可以用委托和事件,如果直接传引用的话,给的权限太大,对系统不太安全,而且耦合太高
2008-10-19 10:19
飙马
Rank: 5Rank: 5
来 自:马里亚纳
等 级:贵宾
威 望:15
帖 子:779
专家分:280
注 册:2007-3-28
收藏
得分:0 
刚开始时是学C#时,是在.net 1.1平台;刚转来.net 2.0时,确实有很多东西需要学习和适应;像委托、事件、反射这些,都是.net 2.0的精华。
   对应事件的理解,不能只停留在双击btnOK,生成btnOK_Click(object sender,EventArgs  e)这样的初级阶段,这属于以前VB6的阶段和含义,已经过时了。至少,这个按纽跟这个事件是如何关联,你是不清楚了,因为是系统来帮你完成了。
   举例,我希望在某个开关量设备连接上以后,每隔多少秒对输入端口扫描一次,如果发现有输入,有报告。这种情况就需要自己书写time事件:
  Timer t=new Timer(100);
  t.Elapsed += new ElapsedEventHandler(DeviceInputDetected)
  public void DeviceInputDetected(ElapsedEventArgs e)
  {
      //扫描;
      //报告
  }

[[it] 本帖最后由 飙马 于 2008-10-19 15:24 编辑 [/it]]
收到的鲜花
  • 静夜思2008-10-20 14:25 送鲜花  50朵   附言:好文章

IT精英如同彩票:平凡的人像5块也中不到一样普遍,努力一点你中了5元保了个本。奖金越高,机率也就越小,付出的也越多,盖茨如同500万一样稀有。虽然每天忙碌而平凡,但我努力成为精英,做梦中了500万。
2008-10-19 14:57
skyzoneskyzone
Rank: 1
等 级:新手上路
威 望:1
帖 子:137
专家分:0
注 册:2008-10-6
收藏
得分:0 
public event DelegateRegisterOkEvent RegisterOK;这一句怎么解释?

读万卷书莫如行万里路,行路在问题答题之中。
2008-10-20 09:59
maibarry
Rank: 1
等 级:新手上路
帖 子:54
专家分:7
注 册:2008-10-21
收藏
得分:0 
好帖。学习!学习。
2008-10-22 15:23
skyzoneskyzone
Rank: 1
等 级:新手上路
威 望:1
帖 子:137
专家分:0
注 册:2008-10-6
收藏
得分:0 
我们也能模拟一个模块具有点击功能的吗?

读万卷书莫如行万里路,行路在问题答题之中。
2008-10-23 20:18
小仙
Rank: 7Rank: 7Rank: 7
来 自:光之谷
等 级:贵宾
威 望:39
帖 子:1812
专家分:1
注 册:2008-8-8
收藏
得分:0 
回复 19# skyzoneskyzone 的帖子
很好的想法,尝试下自定义控件。。呃。。你不会是想的象网页那样的热点吧。。


仁者乐膳,智者乐睡。我都爱~
2008-10-23 20:23
快速回复:【交流探讨】说说你本人对“事件”的理解……
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.021398 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved