现在的位置: 网页制作教程网站制作教程 >正文
C#

C#中委托和自定义事件

发表于2017/3/2 网站制作教程 0条评论 ⁄ 热度 2,413℃

本文主要介绍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;
    
    // 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);
        }
    }
}
  • 暂无评论