委托事件

. 什么是委托

通俗的讲,就是一个能存放符合某种格式(方法签名)的方法的指针的容器。

二.委托入门

程序示例:

 1 //声明委托类(必须指定返回值类型和方法参数列表)

 2     public delegate void DGSayHi(string str);

 3 

 4     public partial class Form1 : Form

 5     {

 6         public Form1()

 7         {

 8             InitializeComponent();

 9         }

10 

11         private void button1_Click(object sender, EventArgs e)

12         {

13             //创建委托对象,并为委托对象添加一个方法指针(方法对象地址)

14             DGSayHi dgSayHi = new DGSayHi(SayHiSomeWhere);

15             //调用委托(委托内部的方法就会被调用)

16             //注意:不能存放 签名 和 委托签名 不一致的方法

17             dgSayHi("霍啊啊");

18         }

19 

20         void SayHiInChina()

21         {

22             MessageBox.Show("你好");

23         }

24 

25         void SayHiSomeWhere(string location)

26         {

27             MessageBox.Show(location+"你好");

28         }

29 

30     }
View Code

三.委托源码

1. 语法糖:在C#中有很多简洁语法,实质是由编译器在编译时转成完整语法,那么这种简洁语法叫做语法糖。

2. 委托的两个目的:

       能将方法作为参数和返回值;

       调用一个委托,执行N个方法(多播委托);

3. 代码示例:

 1 //1. 声明委托的本质:

 2     //委托编译后生成一个同名类(DGTest)

 3     //继承关系:DGTest->MulticastDelegate->Delegate

 4     public delegate void DGTest();

 5     public partial class Form1 : Form

 6     {        

 7         public Form1()

 8         {

 9             InitializeComponent();

10         }

11     }

12 private void btnTest_Click(object sender, EventArgs e)

13         {

14             //语法糖:在C#中有很多 简洁语法,实质是由编译器 在编译时 转成 完整语法,那么这种 简洁语法叫做语法糖

15             //2.创建委托对象

16             DGTest dg = Test;//new DGTest(this.Test);

17             /*3.为委托追加方法的本质:

18              *    是为 被追加的方法创建一个新的委托对象,并将 方法 指针存入对象的 父类的父类(Delegate)的 IntPtr 变量中

19              *    然后再将 新创建的委托 添加到 当前委托对象(dg)的 数组中

20              */

21             dg += Test2;//编译后:(DGTest) Delegate.Combine(dg, new DGTest(this.Test2));

22             dg += Test3;//编译后:(DGTest) Delegate.Combine(dg, new DGTest(this.Test3));

23             dg -= Test3;//编译后:(DGTest) Delegate.Remove(dg, new DGTest(this.Test3));

24             /*4.调用委托,其实就是通过调用委托对象里的Invoke方法 遍历 委托内部的数组,然后依次调用 数组中的 方法

25              */

26             dg();//编译后:dg.Invoke();

27             

28             /* 委托的作用:

29              *   1.将方法做为参数

30              *   2.将方法作为返回值

31              */

32         }
View Code

.委托当参数用

代码示例:

 1 void Test1()

 2         { }

 3         void Test2()

 4         { }

 5         void Test3()

 6         { }

 7         public void InvokeTest(DGTest dgTest)

 8         {

 9             dgTest();

10         }

11         //委托当参数用

12         private void btnPara_Click(object sender, EventArgs e)

13         {

14             InvokeTest(Test1);

15             InvokeTest(Test2);

16             InvokeTest(Test3);

17         }
View Code

.委托当返回值

代码示例:

 1 public DGTest InvokeTest(string strType)

 2         {

 3             switch (strType)

 4             {

 5                 case "1":

 6                     return Test1;

 7                 case "2":

 8                     return Test2;

 9                 default:

10                     return Test3;

11             }

12         }

13         //委托当返回值

14         private void btnReturn_Click(object sender, EventArgs e)

15         {

16             DGTest dg = InvokeTest("1");

17             dg();

18         }
View Code

六.自定义Each方法

程序示例:

 1 //自定义Each方法

 2         private void btnEach_Click(object sender, EventArgs e)

 3         {

 4             ArrayList list = new ArrayList();

 5             list.Add("");

 6             list.Add("");

 7             list.Add("");

 8             list.Add("");

 9             Each(list,ShowName);

10         }

11         void ShowName(int index, object item)

12         {

13             MessageBox.Show(index + "item=" + item);

14         }

15         delegate void DGEachFunc(int index,object item);

16         public void Each(ArrayList list,DGEachFunc func)

17         {

18             for (int i = 0; i < list.Count; i++)

19             {

20                 func(i, list[i]);

21             }

22         }
View Code

七.排序使用委托

代码示例:

 1 #region 4.0 使用接口排序

 2         /// <summary>

 3         /// 使用接口排序

 4         /// </summary>

 5         /// <param name="sender"></param>

 6         /// <param name="e"></param>

 7         private void btnSort_Click(object sender, EventArgs e)

 8         {

 9             List<Dog> list = new List<Dog>();

10             list.Add(new Dog() { name = "小白", age = 12 });

11             list.Add(new Dog() { name = "小黑", age = 1 });

12             list.Add(new Dog() { name = "小黄", age = 2 });

13 

14             for (int i = 0; i < list.Count; i++)

15             {

16                 Console.WriteLine(i + "" + list[i].name + ",age=" + list[i].age);

17             }

18 

19             //此处 传递一个 IComparer接口的实现类 对象进去 ,目的 是 为 Sort 排序方法里的 比较过程 提供一个 比大小的方法。

20             list.Sort(new CompareDog());

21 

22             Console.WriteLine("排序后:");

23             for (int i = 0; i < list.Count; i++)

24             {

25                 Console.WriteLine(i + "" + list[i].name + ",age=" + list[i].age);

26             }

27         } 

28         #endregion

29 

30         #region 5.0 使用委托排序

31         /// <summary>

32         /// 使用委托排序

33         /// </summary>

34         /// <param name="sender"></param>

35         /// <param name="e"></param>

36         private void btnSortDelegate_Click(object sender, EventArgs e)

37         {

38             List<Dog> list = new List<Dog>();

39             list.Add(new Dog() { name = "小白", age = 12 });

40             list.Add(new Dog() { name = "小黑", age = 1 });

41             list.Add(new Dog() { name = "小黄", age = 2 });

42 

43             for (int i = 0; i < list.Count; i++)

44             {

45                 Console.WriteLine(i + "" + list[i].name + ",age=" + list[i].age);

46             }

47 

48             //传入 的参数 为 一个 符合 Comparison 委托签名的方法

49             list.Sort(ComparisonDog);

50 

51             //list.Sort((x, y) => x.age - y.age);

52             //int d = list.Max(x => x.age);

53 

54             Console.WriteLine("排序后:");

55             for (int i = 0; i < list.Count; i++)

56             {

57                 Console.WriteLine(i + "" + list[i].name + ",age=" + list[i].age);

58             }

59         }

60 

61         int ComparisonDog(Dog x, Dog y)

62         {

63             return x.age - y.age;

64         } 

65         #endregion
View Code

八.委托泛型案例-找最大值

代码示例:

 1 #region 6.0 使用泛型方法 加 泛型委托 完成 通用版的 Max方法

 2         /// <summary>

 3         /// 使用泛型方法 加 泛型委托 完成 通用版的 Max方法

 4         /// </summary>

 5         /// <param name="sender"></param>

 6         /// <param name="e"></param>

 7         private void btnFindMax_Click(object sender, EventArgs e)

 8         {

 9             int[] arrInt = new int[5] { 1, 2, 5, 6, 3 };

10             //int Max = MaxInt(arrInt);

11             int max = MaxValue<int>(arrInt, (x, y) => x - y);

12 

13 

14             string[] arrStr = new string[] { "a", "c", "b" };

15             string maxLengthStr = MaxValue<string>(arrStr, (x, y) => x.Length - y.Length);

16 

17             Dog[] dogs = new Dog[] { new Dog() { age = 1, name = "小白" }, new Dog() { age = 0, name = "小白2" }, new Dog() { age = 5, name = "小白3" } };

18             Dog maxAgeDog = MaxValue<Dog>(dogs, (x, y) => x.age - y.age);

19 

20         }

21 

22         int MaxInt(int[] arr)

23         {

24             int maxInt = arr[0];

25             for (int i = 1; i < arr.Length; i++)

26             {

27                 if (maxInt < arr[i])

28                 {

29                     maxInt = arr[i];

30                 }

31             }

32             return maxInt;

33         }

34 

35 

36         T MaxValue<T>(T[] arr, Comparison<T> func)

37         {

38             T maxInt = arr[0];

39             for (int i = 1; i < arr.Length; i++)

40             {

41                 //使用委托来 完成元素 大小的比较过程!

42                 if (func(maxInt, arr[i]) < 0)

43                 {

44                     maxInt = arr[i];

45                 }

46             }

47             return maxInt;

48         } 

49         #endregion
View Code

九.委托加工字符串(案例)

代码示例:

 1 #region 9.0 调用 委托 加工 数组里的 每个字符串

 2         /// <summary>

 3         /// 调用 委托 加工 数组里的 每个字符串

 4         /// </summary>

 5         private void btnMakeUpStr_Click(object sender, EventArgs e)

 6         {

 7             //创建数组

 8             string[] strArr = new string[] { "bb", "小李", "飞到" };

 9             //加工后产生新的数组,并将 方法 作为 第二个参数 传入

10             string[] strArrNew = MakeUpStrArr(strArr, MakeUpStr);

11             //遍历新数组 检查结果

12             for (int i = 0; i < strArrNew.Length; i++)

13             {

14                 Console.WriteLine(strArrNew[i]);

15             }

16         }

17 

18         //为传入字符串加一个 新的字符串

19         string MakeUpStr(string str)

20         {

21             return str += "- : )";

22         }

23 

24         //为传入的字符串数组 里的每个字符串 追加一个 新的字符串,并作为新字符串数组返回

25         string[] MakeUpStrArr(string[] arrStr, DGMakeUpStr dgMakeUpStr)

26         {

27             //创建新数组

28             string[] arrstrNew = new string[arrStr.Length];

29             //遍历字符串数组

30             for (int i = 0; i < arrStr.Length; i++)

31             {

32                 arrstrNew[i] = dgMakeUpStr(arrStr[i]);//此处调用 传入的委托对象里的方法 为 字符串加工

33             }

34             //返回新数组

35             return arrstrNew;

36         } 

37         #endregion
View Code

十.委托找最大值(更加清晰的案例)

 1 private void btnFindMaxByDel_Click(object sender, EventArgs e)

 2         {

 3             DGCompare dg = new DGCompare(IntCompare);

 4 

 5             //找最大数值

 6             object[] arrInt = {5, 4, 1, 9, 8};

 7             int maxInt = Convert.ToInt32(GetMax(arrInt, new DGCompare(IntCompare)));

 8 

 9             //找最长字符串

10             object[] arrStr = { "ui", "xiaomi", "lei", "h" };

11             string maxLenStr = GetMax(arrStr, StringCompare).ToString();

12 

13             //找年龄最大的狗

14             object[] arrDog = { new Dog { name = "小白", age = 21 }, new Dog { name = "小黑", age = 11 }, new Dog { name = "小花", age = 5 } };

15             Dog oldestDog = GetMax(arrDog, DogCompare) as Dog;

16         }

17 

18         /// <summary>

19         /// 根据 比较方法找最大值

20         /// </summary>

21         /// <returns></returns>

22         object GetMax(object[] values, DGCompare comparor)

23         {

24             object max = values[0];

25             foreach (object obj in values)

26             {

27                 if (comparor.Invoke(obj, max) > 0)

28                 {

29                     max = obj;

30                 }

31             }

32             return max;

33         }

34 

35         //--------------------------------- 三个不同的比较方法 ----------------------------

36         public int IntCompare(object value1, object value2)

37         {

38             int i1 = (int)value1;

39             int i2 = (int)value2;

40             return i1 - i2;

41         }

42 

43         public int StringCompare(object value1, object value2)

44         {

45             string i1 = (string)value1;

46             string i2 = (string)value2;

47             return i1.Length - i2.Length;

48         }

49 

50         public int DogCompare(object value1, object value2)

51         {

52             Dog i1 = (Dog)value1;

53             Dog i2 = (Dog)value2;

54             return i1.age - i2.age;

55         }
View Code

十一.委托的封装(事件)

代码示例:

 1 public partial class C03事件 : Form

 2     {

 3         //1.手动 创建 按钮对象

 4         MyTripleButton btnMyTriple = new MyTripleButton();

 5 

 6         //2.手动 创建 改进型 按钮对象

 7         MyTripleButtonSelf btnMyTriSelf = new MyTripleButtonSelf();

 8 

 9         //3.手动 创建 事件 按钮对象

10         MyTripleButtonSelfEvent btnMyTriSelfEvent = new MyTripleButtonSelfEvent();

11 

12         public C03事件()

13         {

14             InitializeComponent();

15 

16             //1.2.设置 按钮的 文本 和位置

17             btnMyTriple.Text = "自定义按钮";

18             btnMyTriple.Location = new Point(100, 100);

19             //1.3.将按钮 显示到 窗体上

20             this.Controls.Add(btnMyTriple);

21             //1.4.为按钮 的 委托 设置一个 方法(按钮被点击的时候 会被 执行)

22             btnMyTriple.dgMyClick = MyTripleClick;

23 

24 

25             //2.2.设置 按钮的 文本 和位置

26             btnMyTriSelf.Text = "改进型 自定义按钮";

27             btnMyTriSelf.Location = new Point(100, 150);

28             btnMyTriSelf.Size = new Size(150, 50);

29             //2.3.将按钮 显示到 窗体上

30             this.Controls.Add(btnMyTriSelf);

31             //2.4.为按钮 的 委托 设置一个 方法(按钮被点击的时候 会被 执行)

32             btnMyTriSelf.AddClickMethod(MyTripleClick);

33 

34 

35             //3.2.设置 按钮的 文本 和位置

36             btnMyTriSelfEvent.Text = "事件 自定义按钮";

37             btnMyTriSelfEvent.Location = new Point(100, 200);

38             btnMyTriSelfEvent.Size = new Size(150, 50);

39             //3.3.将按钮 显示到 窗体上

40             this.Controls.Add(btnMyTriSelfEvent);

41             //3.4.为按钮 的 委托 设置一个 方法(按钮被点击的时候 会被 执行)

42             btnMyTriSelfEvent.dgMyClick += MyTripleClick;

43             btnMyTriSelfEvent.dgMyClick -= MyTripleClick;

44         }

45 

46         void MyTripleClick(DateTime clickTime)

47         {

48             MessageBox.Show("Test" + clickTime);

49         }

50 

51         private void btnTrick_Click(object sender, EventArgs e)

52         {

53             //直接 把 按钮对象 里的委托 设置为空,从而 导致委托中原来保存的方法指针都丢失,有可能破坏了 业务的完整性,不安全!!!

54             btnMyTriple.dgMyClick = null;

55             //新式 按钮,没有把按钮里的 委托对象 暴露给 外部直接操作,所以相对来说 比较安全!!!

56             //btnMyTriSelf.RemoveClickMethod(

57             //事件 按钮,事件机制 会自动的将 修饰的 委托变量改为私有,并同时提供一个 add 和 remove方法

58             //btnMyTriSelfEvent.dgMyClick = null;

59         }

60     }
View Code

十二. 事件

       当我们使用event关键字修饰一个类里的委托对象时,编译器会自动把这个委托对象私有化,并且声称一个与委托对象同名的事件语法,其中就包含了add和remove方法。在类的外部调用这个委托名的时候,实际上就是调用了同名的事件语法,+=就是调用了语法里的add方法,-=就是调用了事件语法里的remove方法,而add和remove方法内部,都是实际操作的私有化的委托对象。

十三. 事件案例(三击按钮)

代码示例:

 1 /// <summary>

 2     /// 三击按钮类 - 用户点击三次后 执行用户的 方法

 3     /// </summary>

 4     public class MyTripleButton:System.Windows.Forms.Button

 5     {

 6         Timer time = new Timer();

 7 

 8         public MyTripleButton()

 9         {

10             base.Click += MyTripleButton_Click;

11             time.Interval = 1000;

12             time.Tick += time_Tick;

13         }

14 

15         int clickTimes = 0;

16         //定义一个 用来保存 用户方法的委托对象

17         public event DGMyClick dgMyClick;

18 

19         void time_Tick(object sender, EventArgs e)

20         {

21             clickTimes = 0;

22         }

23 

24         //每当被点击的时候,此方法会被调用

25         void MyTripleButton_Click(object sender, EventArgs e)

26         {

27             //如果点击次数没达到3次

28             if (clickTimes < 2)

29             {

30                 //如果是第一次点击 则启动计时器

31                 if (clickTimes == 0)

32                 {

33                     time.Start();

34                 }

35                 //点击次数++

36                 clickTimes++;

37             }

38             else//点击三次后

39             {

40                 //1.执行用户的 方法

41                 if (dgMyClick != null)

42                     dgMyClick(DateTime.Now);

43                 //2.清空点击次数

44                 clickTimes = 0;

45                 //3.重启计时器

46                 time.Stop();

47             }

48         }

49 }

50 

51 public partial class Form1 : Form

52     {

53         public Form1()

54         {

55             InitializeComponent();

56             //1.创建三击按钮对象

57             MyTripleButton myBtn = new MyTripleButton();

58             //2.利用一个事件机制 为 按钮里的委托对象 注册一个 方法(或 移除一个方法)

59             myBtn.dgMyClick += ClickSelf;

60             //3.注意:因为使用了事件机制 封装了 按钮里的委托对象,所以不能 直接 赋值 和 调用委托了

61             //myBtn.dgMyClick = null;

62             //myBtn.dgMyClick();

63             this.Controls.Add(myBtn);

64         }

65 

66         void ClickSelf(DateTime time)

67         {

68             MessageBox.Show("三击了~~~~~~~~~~~~~!加分!");

69         }

70     }
View Code

 

你可能感兴趣的:(事件)