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);
}
}
}
C#:委托和自定义事件的更多相关文章
- C#委托五(自定义事件)
事件: "在发生其他类或对象关注的事情时,类或对象可以通过事件通知他们.发送(或引发)事件的类称为"发行者",接受(或处理)事件的类称为"订户".&q ...
- C# 窗体间传值(使用委托与自定义事件)
using System; using System.Drawing; using System.Windows.Forms; namespace 跨窗体调用控件 { public partial c ...
- 分享一个C#自定义事件的实际应用
在C#.NET的开发中,事件是经常接触到的概念,比如为按钮添加点击事件,并写入点击按钮触发事件要运行的代码.不管是ASP.NET还是WinForm等各种形式的应用程序,最经常是为系统生成的事件写具体代 ...
- javaScript事件机制深入学习(事件冒泡,事件捕获,事件绑定方式,移除事件方式,阻止浏览器默认行为,事件委托,模拟浏览器事件,自定义事件)
前言 JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间.可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码.这种在传统软 ...
- jQuery 学习笔记(5)(事件绑定与解绑、事件冒泡与事件默认行为、事件的自动触发、自定义事件、事件命名空间、事件委托、移入移出事件)
1.事件绑定: .eventName(fn) //编码效率略高,但部分事件jQuery没有实现 .on(eventName, fn) //编码效率略低,所有事件均可以添加 注意点:可以同时添加多个相同 ...
- JS自定义事件之选项卡
自定义事件是一种处理与DOM产生交互的代码逻辑片段之间耦合的很好的架构方法. 一个简单的jQuery插件——选项卡 让ul列表来响应点击事件.当用户点击一个列表项时,给这个列表项添加一个名为activ ...
- EventHandler委托与自定义委托
http://blog.csdn.net/uuxyz/article/details/7175248 EventHandler委托与自定义委托 自定义委托: //1. public delegate ...
- C# 自定义事件(EventArgs)
1,自定义事件: public class TextChangeEventArgs : EventArgs { private string message; public TextC ...
- Flex之自定义事件
1.通过dispatchEvent委托事件模式完成自定义事件: <?xml version="1.0" encoding="utf-8"?> < ...
随机推荐
- 前端项目构建之yeoman
各位好啊,我又和大家见面了,也许你已经不记得大明湖畔的容嬷嬷,但是只要记得博客园中的我就好,希望我的博客能像一股清风,为你驱散炎热的酷暑,好了,废话不多说,开始上干货,我今天带给大家的是前端工程化开发 ...
- Generator库co4.6使用及源码分析
原文链接 http://www.cnblogs.com/ytu2010dt/p/6043947.html co4.x已经抛弃了原来thunk转而结合promise实现. 一:promise proms ...
- 自己动手丰衣足食之轮播图一动态修改marginTop属性实现轮播图
引言 学习jQuery有年头了,刚开始学习时自己动手写过轮播图,放的久了以至于忘了大致思路了.现在转而做前端,抽空把jquery轮播图拿出来写一写,把各种思路都自己练习练习,这里主要使用动态修改mar ...
- 在线预览Office文件【效果类似百度文库】
引言 结合上个项目和目前做的这个项目,其中都用到了Office文件在线预览,目前项目中是用到公司购买的Ntko控件,该控件每次浏览文件时则会提示安装信任插件,很繁琐,而且浏览效果不好. 提到Offic ...
- LeetCode刷题系列
LeetCode 我们工作面试和提高自身数据结构和算法能力的时候往往需要刷刷题,我选择LeetCode是通过一个留学论坛了解的.专业,覆盖语种全面. 提前说说刷题的心得: 尽量手写代码,少使用IDE的 ...
- JS魔法堂:定义页面的Dispose方法——[before]unload事件启示录
前言 最近实施的同事报障,说用户审批流程后直接关闭浏览器,操作十余次后系统就报用户会话数超过上限,咨询4A同事后得知登陆后需要显式调用登出API才能清理4A端,否则必然会超出会话上限. 即使在页面 ...
- Hibernate —— Entity.hbm.xml
一.简述 1.对象关系映射文件,用于映射实体类和关系数据库数据表之间的一个 xml 文件. 2.通过 Entity.hbm.xml 映射文件,Hibernate 可以理解持久化类和数据表之间的对应关系 ...
- C#开发微信门户及应用(42)--使用Autofac实现微信接口处理的控制反转处理
在很多情况下,我们利用IOC控制反转可以很方便实现一些接口的适配处理,可以在需要的时候切换不同的接口实现,使用这种方式在调用的时候,只需要知道相应的接口接口,具体调用哪个实现类,可以在配置文件中动态指 ...
- [WCF编程]5.绑定概述
一.绑定概述 WCF提供了一个编程框架,可以抽象化服务创建的复杂过程.绑定允许开发人员将精力集中在问题本身上,而无需考虑如何创建允许系统运行的架构,因为WCF已经创建了架构. 绑定类型是开发人员控制W ...
- WPF模板
WPF的中模板有三种:ControlTemplate.ItemsPanelTemplate.DataTemplate,他们继承抽象类FrameworkTemplate,下面是它们的继承关系: Wind ...