关闭

委托和事件学习总结

537人阅读 评论(0) 收藏 举报
分类:

委托和事件学习总结

         有如下图所示的两个窗体Form1和Form2,点击Form1窗体上的button1按钮,弹出Form2窗体,然后在Form2窗体上点击button1按钮,修改Form1窗体的背景色或是给Form1窗体的TextBox赋值。

    

         按照最普通的想法,需要把Form1窗体对象作为一个变量传递给Form2窗体,并且把TextBox的修饰符改为public,然后在Form2窗体中就可以访问Form1窗体中的TextBox并给它赋值。但这样做存在安全隐患,因为我们可以在Form2窗体中任意改动Form1窗体,一般来说,这是不被允许的。

         学习了面向对象之后,我想,也许可以用接口来实现这一功能。我们定义一个接口,里面有一个未实现的可以改变窗体背景色的方法,然后让Form1窗体实现这个接口。在实现接口的方法中,我们就可以让Form1窗体改变自己的属性。这样在Form2窗体中,我们直接定义一个接口类型的变量,然后调用这个接口所定义的方法就可以达到目的。具体代码如下:        

public interface IChangecolorable
    {
        voidSetColor();
    }
         public partial class Form1 : Form,IChangecolorable
    {
        publicForm1()
        {
            InitializeComponent();
        }
        privatevoid button1_Click(objectsender, EventArgs e)
        {
            Form2f2 = new Form2();
            f2.SetColor = this;
            f2.Show();
        }
        public void SetColor()
        {
            this.BackColor= Color.AliceBlue;
        }
       
    }
         public partial class Form2 : Form
    {
        publicForm2()
        {
            InitializeComponent();
        }
        public IChangecolorable SetColor { get; set; }
        privatevoid button1_Click(objectsender, EventArgs e)
        {
            SetColor.SetColor();
 
            Formf = SetColor as Form1;
            f.Controls.Clear();
 
            SetTxt("金e山¦?打䨰字Á?!ê?");
 
        }
    }

         但是,固然我们可以用接口实现这个功能,但在Form2窗体中,我们仍然可以把接口变量SetColor强转为Form1类型的对象,因为我们在Form1窗体中把Form1对象本身赋值给了SetColor变量,强转后,这个对象仍然是Form1窗体。就算Form1里面的控件都是private类型,我们仍然可以通过窗体的属性Controls来对窗体控件进行操作,因为Controls存储了当前窗体的所有控件。因此这样的做法也不是太好。

         那么,我们是不是可以让外部类仅仅只能访问Form1窗体中改变属性值的方法SetColor,而不允许访问其它任何成员呢?当然可以,这就要用到委托。通过委托,我们可以把改动属性这一动作委托给第三方,在类的外部,我们就可以通过这个委托来访问这个方法来达到目的,但不能访问类内部的其它任何成员。

         委托是一种数据类型,用于存储某种格式的方法。广义上来讲,委托也是一种多态。委托就是将方法或函数当作变量来处理,我们可以给委托类型的变量进行赋值、运算和方法传递等操作。定义委托时,使用delegate关键字。如果没有显式指定访问修饰符,委托的默认访问修饰符为internal。声明委托时,要有返回类型、委托名和参数列表,如果没有参数,参数列表可以为空。如下:

         public delegate void DelegateSetTxt(string text);

       在Form2窗体中,我们可以声明一个委托类型的变量SetTxt作为属性:

       public DelegateSetTxt SetTxt { get;set; }

       然后在显示Form2窗体之前,我们为这个属性赋值:

       Form2f2 = new Form2();

    //f2.SetColor = this;

    f2.SetTxt= SetTxt;

f2.Show();

注意,给委托变量赋值时,这个值只能是方法名,并且方法名后面不能有小括号。而且这个方法的返回类型和参数类型必须和委托一致。否则,就会报错。上面的写法是一个简写方式,原本的写法应该是new一个委托类型的对象,然后把方法名作为一个参数传递进去。如下:f2.SetTxt = new DelegateSetTxt(SetTxt);

在Form2窗体中触发按钮点击事件时,我们直接调用这个委托的Invoke方法就可以。当调用了Invoke方法时,相当于调用了委托变量里存储的方法。

SetTxt.Invoke("金山打字!");

如果这个委托没有参数,那Invoke方法也不必添加参数。我们还可以进一步简写调用委托,直接在委托变量名后面跟参数列表。

SetTxt("金山打字!");

这种在一个类中生成另一个类的对象,又在另一个类中通过某些事件返回调用这个类中的方法,调用完成后又返回另一个类的模式叫做回调函数。

如果赋给委托类型变量的方法是私有的,那我们还可以在外部访问到这个方法吗?肯定是可以的。因为我们不是通过类的对象来调用这个方法,而是通过委托来调用的。把一个方法赋值给委托时,是把这个方法的地址赋值给了委托。所以在外部可以通过委托调用私有方法。

       委托既然是一个类型,那么它也具有其它基本类型或自定义类型所具有的特点。我们同样也可以把一个委托类型的变量当作一个参数进行传递。当调用这样的方法时,我们直接给这个方法传递一个与委托一致的方法的方法名即可。

       当我们给委托赋值时,是把一个方法的地址存入委托中的一个数组中,这个数组可以存储多个方法的地址。因此我们可以为一个委托赋值多个不同的方法,这就是多路广播委托,简称多播委托。在多播委托中,必须先用“=”给委托类型的变量赋一个初始值后,才能用“+=”给该委托类型的变量赋予多个值。多播委托执行存入里面的方法的顺序一般是按照添加顺序来执行的,但这并不是绝对的。

       事件就是行为和动作,它是一种特殊的委托类型的变量。Windows就是一个基于事件的驱动模型。声明事件时,使用event关键字。用event关键字实现事件机制的好处是不可以修改事件已经注册的值,不可以冒充进行事件通知。在C#里面,我们一般不可以自定义事件,但可以自定义控件中模拟事件运行机制。事件本身就是一个多播委托,因此,给一个事件赋值时,需要用“+=”来赋值,如下为Button的Click事件:

       this.button1.Click += new System.EventHandler(this.button1_Click);

我们也可以省去newEventHandler这个过程而直接把this.button1_Click方法赋予Click事件。当在一个类里面声明了一个事件时,只能在本类里面触发这个事件。外界只能用“+=”和“-=”为事件注册和注销方法,而不能使用“=”为事件赋值,更不可以主动触发事件。

       事件和委托的区别是什么呢?它们是没有可比性的,事件的本质就是委托,它是委托类型的一个对象。委托所起到的就是一个占位的作用,因为它不知道将来要执行的方法的具体代码,此时可以先用委托类型的变量来代替方法的调用。在实际调用前,需要为委托赋值,否则为null。事件的作用与委托一样,只不过多了些限制,不管我们声明的事件的访问修饰符是公共的还是私有的,在编译之后,它都是private,我们都不能通过赋值的方式访问它,只能为事件注册和注销方法,并且事件只能在类的内部被触发。而委托不同,我们可以在类的外部使用“=”覆盖委托所注册的方法,这存在安全隐患。因此事件也相当于是对委托进行的封装。

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:49353次
    • 积分:899
    • 等级:
    • 排名:千里之外
    • 原创:39篇
    • 转载:11篇
    • 译文:0篇
    • 评论:3条