[.net 面向对象编程基础] (21) 事件
2021-03-21 07:24
标签:oid pen 会同 empty 类图 microsoft 代码实现 cat 动物 本文转自:https://www.cnblogs.com/yubinfeng/p/4592387.html 事件(Event)是学习.net面向对象编程很重要的一部分,在学习事件之前,我们实际上已经在很多地方使用了事件,比如控件的click事件等,这些都是.net设计控件的时候已经定义好的事件。除此之外,我们同样可以自己定义事件。 事件实际上是一种消息机制,当然点击控件时,click就通知处理他的方法去处理,实际上就是前面说的委托。因此我们可以说:事件是一种具有特殊签名的委托。而事件/消息机制是windows的核心,因此我们必须掌握他。 为了更加容易理解事件,我们还是使用前面的动物的示例来说明,有两三只动物,猫(名叫Tom),还有两只老鼠(Jerry和Jack),当猫叫的时候,触发事件(CatShout),然后两只老鼠开始逃跑(MouseRun)。在使用代码实现这个示例之前,我们先看一下事件的书面定义. 1.什么是事件(Event)? 事件(Event)是类或对象向其他类或对象通知发生的事情的一种特殊签名的委托. 2.事件的声明 public event 委托类型 事件名; 事件使用event关键词来声明,他的返回类值是一个委托类型。 通常事件的命名,以名字+Event 作为他的名称,在编码中尽量使用规范命名,增加代码可读性。 3.事件示例 下面我们实现本篇开始的猫捉老鼠的示例 首先看一下UML图 如上UML类图,有猫(Cat)和老鼠(Mouse)两个类,里面包含其成员.当猫叫(CatShout)时,触发事件(CatShoutEvent),事件通知老鼠,然后老鼠跑路(MouseRun). 两个类的代码如下: 调用如下: 运行结果如下: 4.事件参数 上面的事件是最简单的事件,通过我们看到的事件,都会带两个参数,比如c# winform中的button点击事件的委托方法如下: private void button1_Click(object sender, EventArgs e) 带有两个参数,不熟悉事件参数的小伙伴肯定要问,这两个参数sender和e到底有什么用呢? 第二个参数 e,他的类型为EventArgs.EventArgs这个类没有实际的用途,只是作为一个基类让其他对象继承。很多对象不需要传递额外的信息,例如按钮事件,只是调用一个回调方法就够了。当我们定义的事件不需要传递额外的信息时,这时调用EventArgs.Empty就行了,不需要重新构建一个EventArgs对象。 我们可以看到在Button事件登记时,只传了一个参数sender 为了更好的理解带参数的事件,我们改写一下上面猫捉老鼠的示例: 先看UML图: 实现代码如下: 调用如下: 运行结果如下: 也可以使用前面学过的Lamda表达式来简洁的写以上的事件注册 调用后结果一样. 5. 事件应用实例 如果上面的简单实例不够过瘾,我下面列举几个日常开发过程中应用事件解决实际问题的例子,加深对事件的理解。 示例一:我们使用一个事件来监控一个文件夹下文件的变更情况 先看一下UML类图 代码如下: 调用如下: 运行结果如下: 可以看到当我们增加,修改,删除文件时,就会返回文件夹内文件更改的提示信息。 实际上对于文件更改的监控.NET提供了专门的类FileSystemWatcher来完成。上面的示例只是为了加深理解事件,在实际应用中对文件的变更还是有缺陷的,比如同一文件更名、通过时间判断文件变更也是不科学的。 下面我们就使用.net提供的FileSystemWatcher类来完成文件夹监控,代码非常简单 调用如下: 运行结果如下: 示例二:使用事件完成了一个文件下载进度条的示例,平时我们看到很多进度条程序员为了偷懒都是加载完成直接跳到100%,这个示例就是传说中的真进度条。 UML类图如下: 代码如下: 运行结果如下: 上面示例使用winform应用程序,实现了一个进度条即时计算进度的例子。在文件下载子类(DownLoad)中有两个事件,一个是进度条事件,一个是进度百分比显示事件,在初始化调用时,采用了线程。启用线程时,注册了两个事件。随着模拟进度的加载,触发了进度条事件和显示百分比事件。做到了即时显示。 关于线程相关知识,在后面有时间了会详细说明。 6 要点 6.1 事件:事件是对象发送的消息,发送信号通知客户发生了操作。这个操作可能是由鼠标单击引起的,也可能是由某些其他的程序逻辑触发的。事件的发送方不需要知道哪个对象或者方法接收它引发的事件,发送方只需知道它和接收方之间的中介(delegate)。 6.2 事件处理程序总是返回void,它不能有返回值。 6.3 只要使用EventHandler委托,参数就应是object和EventArgs。第一个参数是引发事件的对象。第二个参数EventArgs是包含有关事件的其他有用信息的对象;这个参数可以是任意类型,只要它派生自EventArgs即可。 6.4 方法的命名也应注意,按照约定,事件处理程序应遵循“object_event”的命名约定。 6.5 事件具有以下特点: (1)发行者确定何时引发事件,订户确定执行何种操作来响应该事件。 (2)一个事件可以有多个订户。 一个订户可处理来自多个发行者的多个事件。 (3)没有订户的事件永远也不会引发。 (4)事件通常用于通知用户操作,例如,图形用户界面中的按钮单击或菜单选择操作。 (5)如果一个事件有多个订户,当引发该事件时,会同步调用多个事件处理程序。 要异步调用事件,请参见使用异步方式调用同步方法。 (6)在 .NET Framework 类库中,事件是基于 EventHandler 委托和 EventArgs 基类的。 6.6 事件的创建步骤 (1)、定义delegate对象类型,它有两个参数,第一个参数是事件发送者对象,第二个参数是事件参数类对象。 [.net 面向对象编程基础] (21) 事件 标签:oid pen 会同 empty 类图 microsoft 代码实现 cat 动物 原文地址:https://www.cnblogs.com/hanguoshun/p/12728501.html 1 class Cat
2 {
3 string catName;
4 string catColor { get; set; }
5 public Cat(string name, string color)
6 {
7 this.catName = name;
8 catColor = color;
9 }
10
11 public void CatShout()
12 {
13 Console.WriteLine(catColor+" 的猫 "+catName+" 过来了,喵!喵!喵!\n");
14
15 //猫叫时触发事件
16 //猫叫时,如果CatShoutEvent中有登记事件,则执行该事件
17 if (CatShoutEvent != null)
18 CatShoutEvent();
19 }
20
21 public delegate void CatShoutEventHandler();
22
23 public event CatShoutEventHandler CatShoutEvent;
24
25 }
26 class Mouse
27 {
28 string mouseName;
29 string mouseColor { get; set; }
30 public Mouse(string name, string color)
31 {
32 this.mouseName = name;
33 this.mouseColor = color;
34 }
35
36 public void MouseRun()
37 {
38 Console.WriteLine(mouseColor + " 的老鼠 " + mouseName + " 说:\"老猫来了,快跑!\" \n我跑!!\n我使劲跑!!\n我加速使劲跑!!!\n");
39 }
40 }
1 Console.WriteLine("[场景说明]: 一个月明星稀的午夜,有两只老鼠在偷油吃\n");
2 Mouse Jerry = new Mouse("Jerry", "白色");
3 Mouse Jack = new Mouse("Jack", "黄色");
4
5
6 Console.WriteLine("[场景说明]: 一只黑猫蹑手蹑脚的走了过来\n");
7 Cat Tom = new Cat("Tom", "黑色");
8
9 Console.WriteLine("[场景说明]: 为了安全的偷油,登记了一个猫叫的事件\n");
10 Tom.CatShoutEvent += new Cat.CatShoutEventHandler(Jerry.MouseRun);
11 Tom.CatShoutEvent += new Cat.CatShoutEventHandler(Jack.MouseRun);
12
13 Console.WriteLine("[场景说明]: 猫叫了三声\n");
14 Tom.CatShout();
15
16
17 Console.ReadKey();
第一个参数 sender,其中object类型的参数 sender表示的是发送消息的对象,为什么要使用object类型呢,这是因为不同类型的对象调用时使用object能很好的兼容。 1 class Cat
2 {
3 string catName;
4 string catColor { get; set; }
5 public Cat(string name, string color)
6 {
7 this.catName = name;
8 catColor = color;
9 }
10
11 public void CatShout()
12 {
13 Console.WriteLine(catColor+" 的猫 "+catName+" 过来了,喵!喵!喵!\n");
14
15 //猫叫时触发事件
16 //猫叫时,如果CatShoutEvent中有登记事件,则执行该事件
17 if (CatShoutEvent != null)
18 CatShoutEvent(this, new CatShoutEventArgs() {catName=this.catName, catColor=this.catColor});
19 }
20
21 public delegate void CatShoutEventHandler(object sender,CatShoutEventArgs e);
22
23 public event CatShoutEventHandler CatShoutEvent;
24
25 }
26
27 ///
1 Console.WriteLine("[场景说明]: 一个月明星稀的午夜,有两只老鼠在偷油吃\n\n\n");
2 Mouse Jerry = new Mouse("Jerry", "白色");
3 Mouse Jack = new Mouse("Jack", "黄色");
4
5
6 Console.WriteLine("[场景说明]: 一只黑猫蹑手蹑脚的走了过来");
7 Cat Tom = new Cat("Tom", "黑色");
8 Console.WriteLine("[场景说明]: 为了安全的偷油,登记了一个猫叫的事件");
9 Tom.CatShoutEvent += new Cat.CatShoutEventHandler(Jerry.MouseRun);
10 Tom.CatShoutEvent += new Cat.CatShoutEventHandler(Jack.MouseRun);
11 Console.WriteLine("[场景说明]: 猫叫了三声\n");
12 Tom.CatShout();
13
14 Console.WriteLine("\n\n\n");
15
16 //当其他颜色的猫过来时
17 Console.WriteLine("[场景说明]: 一只蓝色的猫蹑手蹑脚的走了过来");
18 Cat BlueCat = new Cat("BlueCat", "蓝色");
19 Console.WriteLine("[场景说明]: 为了安全的偷油,登记了一个猫叫的事件");
20 BlueCat.CatShoutEvent += new Cat.CatShoutEventHandler(Jerry.MouseRun);
21 BlueCat.CatShoutEvent += new Cat.CatShoutEventHandler(Jack.MouseRun);
22 Console.WriteLine("[场景说明]: 猫叫了三声");
23 BlueCat.CatShout();
Cat Doraemon = new Cat("哆啦A梦", "彩色");
Doraemon.CatShoutEvent += (sender, e) => Jerry.MouseRun(sender, e);
Doraemon.CatShoutEvent += (sender, e) => Jack.MouseRun(sender, e);
Doraemon.CatShout();
1 ///
string MyFolder = "MyFolder";
FolderWatch folder = new FolderWatch(System.IO.Directory.GetCurrentDirectory() +"\\"+ MyFolder);
folder.FolderWatchEvent += new FolderWatchEventHandler(folder.MonitorFiles);
folder.OnFieldChange();
1 static void watcher_Renamed(object sender,System.IO.RenamedEventArgs e)
2 {
3 Console.WriteLine("文件\"" + e.OldName + "\"更名为:"+e.Name+";\n");
4 }
5 static void watcher_Deleted(object sender, System.IO.FileSystemEventArgs e)
6 {
7 Console.WriteLine("文件\"" + e.Name + "\"已被删除;\n");
8 }
9 static void watcher_Changed(object sender, System.IO.FileSystemEventArgs e)
10 {
11 Console.WriteLine("文件\"" + e.Name + "\"已被修改;\n");
12 }
13 static void watcher_Created(object sender, System.IO.FileSystemEventArgs e)
14 {
15 Console.WriteLine("新创建了文件\"" + e.Name + "\";\n");
16 }
string MyFolder = "MyFolder";
System.IO.FileSystemWatcher watcher = new System.IO.FileSystemWatcher(System.IO.Directory.GetCurrentDirectory() + "\\" + MyFolder);
watcher.Renamed+= watcher_Renamed;
watcher.Deleted+=watcher_Deleted;
watcher.Changed+=watcher_Changed;
watcher.Created +=watcher_Created;
watcher.EnableRaisingEvents = true;
1 public partial class Form1 : Form
2 {
3 System.Threading.Thread thread;
4 public Form1()
5 {
6 InitializeComponent();
7 }
8
9
10 private void downButton_Click(object sender, EventArgs e)
11 {
12
13 if(thread==null)
14 thread = new System.Threading.Thread(new System.Threading.ThreadStart(StartDown));
15
16 //使用子线程工作
17 if (this.downButton.Text == "开始下载文件")
18 {
19 this.downButton.Text = "停止下载文件";
20 if (thread.ThreadState.ToString() == "Unstarted")
21 {
22 thread.Start();
23 }
24 else if (thread.ThreadState.ToString() == "Suspended")
25 thread.Resume();
26 }
27 else
28 {
29 this.downButton.Text = "开始下载文件";
30 thread.Suspend();
31 }
32 }
33
34 //开始加载进度
35 public void StartDown()
36 {
37 //注册事件
38 DownLoad down = new DownLoad();
39 down.onDownLoadProgress+=down_onDownLoadProgress;
40 down.onDownLoadProgress += down_ShowResult;
41 down.Start();
42
43 }
44
45 public void down_onDownLoadProgress(long total,long current)
46 {
47
48
49 if (this.InvokeRequired)
50 {
51 this.Invoke(new DownLoad.DownLoadProgress(down_onDownLoadProgress), new object[] { total, current });
52 }
53 else
54 {
55 this.myProgressBar.Maximum = (int)total;
56 this.myProgressBar.Value = (int)current;
57 }
58
59 }
60
61 public void down_ShowResult(long total,long current)
62 {
63 Action
(2)、定义事件参数类,此类应当从System.EventArgs类派生。如果事件不带参数,这一步可以省略。
(3)、定义"事件处理方法,它应当与delegate对象具有相同的参数和返回值类型"。
(4)、用event关键字定义事件对象,它同时也是一个delegate对象。
(5)、用+=操作符添加事件到事件队列中(-=操作符能够将事件从队列中删除)。
(6)、在需要触发事件的地方用调用delegate的方式写事件触发方法。一般来说,此方法应为protected访问限制,既不能以public方式调用,但可以被子类继承。名字是OnEventName。
(7)、在适当的地方调用事件触发方法触发事件。
文章标题:[.net 面向对象编程基础] (21) 事件
文章链接:http://soscw.com/index.php/essay/67064.html