事件

一、事件初印象

首先看个播放器的案例

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             MP3 m = new MP3();
 6 
 7             //启动前
 8             m.BeforeStartMP3 = () => { Console.WriteLine("初始化歌词!"); };
 9 
10             m.BeforeStopMP3 = () => { Console.WriteLine("保存当前进度!"); };
11 
12             m.Start();
13 
14             m.TurnOffPower();
15 
16             Console.ReadKey();
17         }
18     }
19 
20     public class MP3
21     {
22 
23         //在启动或者关闭mp3之前,每个人想进行的操作可能不同,这里用委托实现用户的自定义操作
24         public Action BeforeStartMP3;
25         public Action BeforeStopMP3;
26 
27         /// <summary>
28         /// 播放音乐
29         /// </summary>
30         public void PlayMusic()
31         {
32             Console.WriteLine("音乐播放中……");
33         }
34 
35 
36         /// <summary>
37         /// 启动mp3
38         /// </summary>
39         public void Start()
40         {
41             if (BeforeStartMP3!=null)
42             {
43                 //在启动播放的时候,触发了这个事件
44                 BeforeStartMP3();
45             }
46 
47             PlayMusic();
48         }
49 
50         public void TurnOffPower()
51         {
52             if (BeforeStopMP3 != null)
53             {
54                 //在停止播放之前触发了这个事件
55                 BeforeStopMP3();
56             }
57 
58             Stop();
59 
60         }
61 
62         /// <summary>
63         /// 关闭mp3
64         /// </summary>
65         public void Stop()
66         {
67             Console.WriteLine("停止播放音乐……");
68         }
69 
70 
71     }
View Code

上面的例子虽然是用委托实现的,但是达到了使用事件的效果。

二、事件进阶

先用委托来模拟实现三连击的效果

用户自定义控件中的代码:

 1 namespace 事件进阶
 2 {
 3     public partial class UCTripleButton : UserControl
 4     {
 5         public UCTripleButton()
 6         {
 7             InitializeComponent();
 8         }
 9 
10         public Action TripleClick;
11 
12         int count = 0;
13         private void btnTripleClick_Click(object sender, EventArgs e)
14         {
15             count++;
16             if (count>=3)
17             {
18                 //MessageBox.Show("点击了三次!");
19                 if (TripleClick!=null)
20                 {
21                     TripleClick();
22                 }
23                 count = 0;
24             }
25         }
26     }
27 }
View Code

Form1中的代码:

 1 public partial class Form1 : Form
 2     {
 3         public Form1()
 4         {
 5             InitializeComponent();
 6         }
 7 
 8         private void Form1_Load(object sender, EventArgs e)
 9         {
10             //将方法传给委托变量
11             ucTripleButton1.TripleClick = Form1TripleClick;
12         }
13 
14         private void Form1TripleClick()
15         {
16             MessageBox.Show("这是Form1");
17         }
18 
19         //在用户控件外面调用,点击一次就能弹出三连击的效果
20         private void button1_Click(object sender, EventArgs e)
21         {
22             if (ucTripleButton1.TripleClick!=null)
23             {
24                 ucTripleButton1.TripleClick();
25             }
26         }
27 
28         //委托变量是public,可以在外面调用
29         private void button2_Click(object sender, EventArgs e)
30         {
31             ucTripleButton1.TripleClick=null;
32         }
33     }
View Code

Form2中的代码:

 1 namespace 事件进阶
 2 {
 3     public partial class Form2 : Form
 4     {
 5         public Form2()
 6         {
 7             InitializeComponent();
 8         }
 9 
10         private void Form2_Load(object sender, EventArgs e)
11         {
12             ucTripleButton1.TripleClick = Form2TripleClick;
13         }
14 
15         private void Form2TripleClick()
16         {
17             MessageBox.Show("这是Form2");
18         }
19     }
20 }
View Code

这样能实现三连击事件的效果,但是我们在Form1窗口中增加其他按钮,由于委托是public,button2可以直接调用绑定的方法,button3可以清除委托绑定的方法,这样调用委托的权限容易被改变(在类的外部随意调用),如同别人可以操作你的银行卡,很显然,不合理。于是就有了事件。

事件只能在类的内部被触发,但是可以在外部绑定或者取消。

编写事件的代码:

 1 public partial class UCTripleButton : UserControl
 2     {
 3         public UCTripleButton()
 4         {
 5             InitializeComponent();
 6         }
 7 
 8 
 9         //Action前面加上event关键字,就变成了事件
10         public event Action TripleClick;
11 
12         int count = 0;
13         private void btnTripleClick_Click(object sender, EventArgs e)
14         {
15             count++;
16             if (count>=3)
17             {
18                 //MessageBox.Show("点击了三次!");
19                 if (TripleClick!=null)
20                 {
21                     TripleClick();
22                 }
23                 count = 0;
24             }
25         }
26     }
View Code

Form1触发事件:

 1 namespace 事件进阶
 2 {
 3     public partial class Form1 : Form
 4     {
 5         public Form1()
 6         {
 7             InitializeComponent();
 8         }
 9 
10         private void Form1_Load(object sender, EventArgs e)
11         {
12             //将方法传给委托变量
13             //ucTripleButton1.TripleClick = Form1TripleClick;
14 
15             //事件只能用+=,-=绑定,避免被随意调用和赋值的时候被全部清空
16             ucTripleButton1.TripleClick += UcTripleButton1_TripleClick;
17         }
18 
19         private void UcTripleButton1_TripleClick()
20         {
21             MessageBox.Show("这是Form1");
22         }
23 
24         private void Form1TripleClick()
25         {
26             MessageBox.Show("这是Form1");
27         }
28 
29         //在用户控件外面调用,点击一次就能弹出三连击的效果
30         private void button1_Click(object sender, EventArgs e)
31         {
32             //if (ucTripleButton1.TripleClick!=null)
33             //{
34             //    ucTripleButton1.TripleClick();
35             //}
36 
37             ucTripleButton1.TripleClick += UcTripleButton1_TripleClick;
38         }
39 
40         //委托变量是public,可以在外面调用
41         private void button2_Click(object sender, EventArgs e)
42         {
43             //ucTripleButton1.TripleClick=null;
44             ucTripleButton1.TripleClick += null;
45         }
46     }
47 }
View Code

三、补充

回到第一个案例,我们用委托实现了播放器在播放歌曲的时候实现了加载歌词,保存进度的功能 ,但是由于委托是public的,所以也可以直接调用加载歌词和保存进度的方法,根本不需要启动和关闭播放器,就能直接实现这个效果,很显然这不合理。这里可以用事件改造。

 四、事件和委托的区别

委托是一种数据类型,事件是一个对象,它是基于委托实现的,对委托进行了封装。二者没有可比性。

原文地址:https://www.cnblogs.com/wesley168/p/6797578.html