• 委托事件


    . 什么是委托

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

    二.委托入门

    程序示例:

     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
  • 相关阅读:
    OpenLayer学习之图文标注
    HTML5制作时钟(canvas)
    ADO,NET中简单三层SQLHelper封装介绍
    OpenLayer学习之加载天地图
    ArcGIS Server manger管理页面无法打开问题解决
    Java EE (14) -- SSH配置
    R语言实战读书笔记(一)R语言介绍
    Machine Learning for hackers读书笔记_一句很重要的话
    Machine Learning for hackers读书笔记(十二)模型比较
    Machine Learning for hackers读书笔记(十)KNN:推荐系统
  • 原文地址:https://www.cnblogs.com/HuoAA/p/4069404.html
Copyright © 2020-2023  润新知