• C#:委托和自定义事件


    1. 委托概述

    “委托”相当于C++中的“函数指针”,委托必须与所要“指向”的函数在“参数”和“返回类型”上保持一致;

    // 定义Person类
    public class Person {
        public string Name = "Rain Man";
        public string Speak(string words) {
            Console.WriteLine(this.Name + " said: " + words);
            return words;
        }
    }
    
    // 定义委托
    public delegate string Dele_Speak(string str);
    
    class Program {
        static void Main(string[] args) {
            Person p = new Person();                    // 实例化Person类
            Dele_Speak dp = new Dele_Speak(p.Speak);    // 实例化委托:变量dp实际上就是指向p.Speak函数的指针
            dp("Welcome to my blog!");                  // 输出:Rain Man said: Welcome to my blog!
            Console.ReadLine();
        }
    }
    • 代理“Dele_Speak”与“Speak”方法在参数和返回类型保持一致;
    • “Dele_Speak dp = new Dele_Speak(p.Speak)”,实际上就是创建了一个“dp”指针,指向“p.Speak”方法
    • “dp("Welcome to my blog!")”,实际上就是“p.Speak("Welcome to my blog!")”

    2. 多路广播

    // 定义Person类
    public class Person {
        public string Speak(string words) {
            Console.WriteLine("Speak: " + words);
            return "111";
        }
        public string Say(string words) {
            Console.WriteLine("Say: " + words);
            return "222";
        }
        public string Translate(string words) {
            Console.WriteLine("Translate: " + words);
            return "333";
        }
    }
    // 声明代理 public delegate string Dele_Str(string str); class Program { static void Main(string[] args) { Person p = new Person(); // 实例化Person类 Dele_Str dp_Speak = new Dele_Str(p.Speak); // 实例化委托指向 p.Speak Dele_Str dp_Say = new Dele_Str(p.Say); // 实例化委托指向 p.Say Dele_Str dp_Translate = new Dele_Str(p.Translate); // 实例化委托指向 p.Transpate // 多路广播 dp_Speak = dp_Speak + dp_Say; dp_Speak = dp_Speak + dp_Translate; string str = dp_Speak("Rain Man"); Console.WriteLine(str); // 输出:333 Console.ReadLine(); } }

    在Person类中创建了三个函数:Speak、Say、Translate,这三个函数在参数和返回类型上相同,因此可是使用同一个委托(Dele_Str)。

    多路委托:使用同一个委托“指向”不同的函数,使这几个函数可以“计算”,其执行逻辑如下:

    执行:
        string str = dp_Speak("Rain Man");
    输出:
        Speak: Rain Man
        Say: Rain Man
        Translate: Rain Man
    
    实际上就是执行下述代码:
        p.Speak("Rain Man");
        p.Say("Rain Man");
        p.Translate("Rain Man");
    
    返回值:即最后一个函数的返回值

    3. 事件代理

    有两个窗体:

    • FrmMain:该窗体中有一个按钮“btnAdd”,当点击此按钮时通过ShowDialog()方法打开“FrmUserAdd”窗体
    • FrmUserAdd: 该窗体中有一个按钮“btnOK”,当点击此按钮时“对外”(对FrmMain窗体)发送一个“UserAddEvent”事件,通过该事件将“FrmUserAdd”中填写的“用户信息”传至“FrmMain”窗体中。

    3.1 FrmUserAdd窗体:

    public partial class FrmUserAdd : Form 
    { // 1. 定义事件参数类 public class UserAddEventArgs : EventArgs { public User AddedUser; public UserAddEventArgs(User user) { this.AddedUser = user; } } // 2. 定义委托,并指定参数类型 public delegate void UserAddEventHandler(object sender, UserAddEventArgs e); // 3. 定义事件,并指定该事件的委托类型 public event UserAddEventHandler UserAddEvent; private void btnOK_Click(object sender, EventArgs e) { User user = new User(1, "Rain Man", ""); UserAddEventArgs args = new UserAddEventArgs(user); if (UserAddEvent != null) { this.UserAddEvent(this, args); } } }

    3.1.1. 自定义事件参数类:UserAddEventArgs

    自定义的事件参数类“UserAddEventArgs”必须继承自“EventArgs”类,在此基础上添加了public成员“AddedUser”

    3.1.2 定义委托:UserAddEventHandler

    • 注意该委托的参数类型,第二个参数为“自定义的事件参数”。
    • 该委托用于在“FrmMain”窗体中实例化,实例化后绑定事件处理函数“OnUserAdd”。

    3.1.3 定义事件变量:UserAddEvent

    “UserAddEvent”变量可以理解为“UserAddEventHandler”委托的一个实例化对象,即

    public UserAddEventHandler UserAddEvent;    // 在该示例中把"event"修饰符去掉也是可以的

    3.2 FrmMain窗体

    public partial class FrmMain : Form {
        // UserAddEvent事件绑定的处理函数
        private void OnUserAdd(object sender, FrmUserAdd.UserAddEventArgs e) {
            MessageBox.Show(e.AddedUser.username);
        }
    
        private void btnAdd_Click(object sender, EventArgs e) {
            FrmUserAdd frm = new FrmUserAdd();
            FrmUserAdd.UserAddEventHandler dele_fn = new FrmUserAdd.UserAddEventHandler(OnUserAdd);
    
            frm.UserAddEvent += dele_fn;
            frm.ShowDialog();
        }
    }

    3.2.1 FrmUserAdd.UserAddEventHandler dele_fn = new FrmUserAdd.UserAddEventHandler(OnUserAdd);

    dele_fn为“UserAddEventHandler”的一个实例(指针),它指向事件处理函数“OnUserAdd”

    3.2.2 frm.UserAddEvent += dele_fn;

    可以看出此处实际就是“多路广播”,同时也可以看出“UserAddEvent”事件变量实际就是“UserAddEventHandler”委托的一个实例。

    3.3 执行逻辑

    该示例看似复杂,其实质是将本在“一个窗体”中的实现,拆成了“两个窗体”。下面将两个窗体的代码合成“一个窗体”

    public partial class FrmUserAdd : Form {
        // 定义事件参数
        public class UserAddEventArgs : EventArgs {
            public User AddedUser;
            public UserAddEventArgs(User user) {
                this.AddedUser = user;
            }
        }
    
        // 定义委托,并指定参数类型
        public delegate void UserAddEventHandler(object sender, UserAddEventArgs e);
    
        // 定义事件,并指定该事件的“委托”
        public UserAddEventHandler UserAddEvent;
        public event UserAddEventHandler UserAddEvent;
        
        // UserAddEvent事件绑定的处理函数
        private void OnUserAdd(object sender, FrmUserAdd.UserAddEventArgs e) {
            MessageBox.Show(e.AddedUser.username);
        }
    
        private void btnOK_Click(object sender, EventArgs e) {
            User user = new User(1, "Rain Man", "");
            UserAddEventArgs args = new UserAddEventArgs(user);
    
            FrmUserAdd.UserAddEventHandler dele_fn = new FrmUserAdd.UserAddEventHandler(OnUserAdd);
            this.UserAddEvent += dele_fn;
    
            if (UserAddEvent != null)
            {
                this.UserAddEvent(this, args);
            }
        }
    }
  • 相关阅读:
    [JS11] 状态栏滚动
    [JS10] 获取时间
    [JS9] document's bgColor改变背景颜色
    [JS8] 显示从(0,0)到(0,0)的坐标
    [JS7] 显示从0到99的100个数字
    使用StringBuilder或StringBuffer简单优化
    启动一个线程的三种方法
    设置IE浏览器指定的功能
    jquery 判断元素是否存在于数组中
    Hibernate validator验证
  • 原文地址:https://www.cnblogs.com/rainman/p/3650925.html
Copyright © 2020-2023  润新知