C#事件

C#事件

想起来这个月还没写博客,随便混更一下吧html

事件

事件(event)指的是一些可以发生的事情,它是一种使对象或者类可以提供通知的成员。举个例子,你打开了手机,点击了一下“信息”,而后就会弹出信息的窗口。“点击”这个动做就是一个事件,它向CPU传达了一个消息,打开信息的窗口,而后CPU处理这个信息,打开了“信息”的窗口。
通过这番解释,你应该大体知道事件这个模型的组成了:事件拥有者(event source)、事件自己(event)、事件响应者(event subscriber)、事件处理器(event handler)和事件订阅。事件拥有者,顾名思义,就是这个事件是谁的,事件自己同理;事件响应者是指接收信息的一方;事件处理器是对事件作出回应,通常是一个方法,并且是一个回调方法;事件订阅就是把事件处理器与事件关联在一块儿,若是订阅了这个事件,当它发生时就会调用事件处理器的方法。
其实事件在手机应用开发当中十分常见,不过Java里面没有事件这种成员,Java使用接口来实现事件。函数

使用事件

在放代码以前,先要添加一个引用,咱们要用到一个新的程序集。具体方法为:对着引用右键,点击添加引用,在程序集里面搜索System.Windows.Forms,勾选添加。
添加引用this

而后再来看例子:spa

using System;
using System.Windows.Forms;

namespace EventPractice
{
    class Program
    {
        static void Main(string[] args)
        {
            MyForm form = new MyForm();
            form.ShowDialog();
        }
    }

    class MyForm : Form                                 //继承,MyForm这个类可使用System.Windows.Forms.Form里面public和protected修饰的成员
    {
        private TextBox textBox;                        //TextBox和Button都是System.Windows.Forms里面的类
        private Button button;

        public MyForm()                                 //构造函数,初始化成员
        {
            this.textBox = new TextBox();
            this.button = new Button();

            this.Controls.Add(this.button);             //添加控件
            this.Controls.Add(this.textBox);

            this.button.Click += this.ButtonClicked;    //Click是一个在System.Windows.Forms里面定义的事件,button是事件的拥有者,MyForm的对象form是事件的响应者
                                                        //+=操做符订阅该事件,ButtonClicked是事件处理器,在下文定义,可是记得不要在ButtonClicked后面加括号
            this.button.Text = "Say Hello!";

            this.button.Top = 50;
        }

        private void ButtonClicked(object sender, EventArgs e)   //事件处理器,接收两个参数:sender是事件源,e是事件参数,这是C#自动生成的事件处理器
        {                                                        //至于为何这么写,是由于它隐藏了一个“约定”——委托(delegate)
            this.textBox.Text = "Hello World!";                  //点击按钮会出现这句话
        }
    }
}

先看看跑出来的结果吧:
事件结果1rest

这个例子用到了C#的WinForm,由于它比较容易解释事件。看MyForm这个类里面,有一个叫Click的事件,它也十分直观,就是在点击的时候作出一些反应,我把它挂在了button上,同时订阅ButtonClicked这个事件处理器。看下文对ButtonClicked的定义,当事件发生时,它会在文本框(textbox)里面打印这句话。而后再回到Main函数里面,new一个MyForm的对象,而后调用showDialog,弹出窗口。当咱们执行这个程序的时候,会出现控制台和这个Form,咱们点击Say Hello就会在文本框里面看见Hello World。
回过头来想一想,事件的五要素齐了吗?code

  • 事件拥有者——button
  • 事件——Click
  • 事件响应者——form
  • 事件处理器——ButtonClicked
  • 事件订阅——+=

很完整,五要素都齐全。这是事件的响应者用本身的方法订阅着本身的字段成员的某个事件的模型,固然你也能够写成其余的方式,留给读者本身钻研吧。
可是其实还有一个问题,为何事件处理器ButtonClicked要接收两个莫名其妙的参数?其实,旧版本的订阅事件是这样写的:orm

this.button.Click += new EventHandler(this.ButtonClicked);

把鼠标移到EventHandler上面,你会发现这居然是一个委托。这说明了什么,咱们用到的事件处理器,必须符合事件要求的一套规矩——符合EventHandler的规矩,接收两个参数,一个object类型的参数,一个EventArgs的参数。因此看回ButtonClicked,它要接收那两个参数,是由于委托的要求。可是如今基本不会用旧版本的订阅写法了,尽可能都用上面例子的写法。
回忆一下我在C#方法Extra中提到的lambda表达式,在这里能用吗?固然能够,特别是ButtonClicked这种简单的函数,lambda表达式是最喜欢的,使用方法为:htm

this.button.Click += (sender, e) =>
                {
                    this.textBox.Text = "Hello World!";
                };

但愿你还记得lambda表达式的语法,这几行代码直接省去了声明和定义ButtonClicked的功夫,省时省力。对象

自定义一个事件

若是C#提供给你的事件不适合当前的场景,那么咱们能够本身定义一个事件,具体以下:blog

using System;
using System.Threading;

namespace EventDevelop
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer();                                     //事件拥有者
            Waiter waiter = new Waiter();                                           //事件响应者

            customer.Order += Waiter.WaiterAction;                                  //订阅事件

            customer.CustomerAction();
            customer.PayTheBill();

            Console.ReadLine();
        }
    }

    public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);   //先声明一个委托,做为事件订阅的规定

    public class OrderEventArgs : EventArgs                                        //事件参数,继承自EventArgs,有两个属性
    {
        public string DishName { get; set; }
        public string Size { get; set; }
    }

    public class Customer                                                          //事件源,发送信息的一方
    {
        private OrderEventHandler eventHandler;
         
        public event OrderEventHandler Order                                       //声明事件,用OrderEventHandler约束
        {
            add                                                                    //添加事件处理器
            {
                this.eventHandler += value;                                        //value是传进来的处理器
            }

            remove                                                                 //移除事件处理器
            {
                this.eventHandler -= value;                                        //移除用-=
            }
        }

        public double Bill { get; set; }

        public void PayTheBill()
        {
            Console.WriteLine("I will pay ${0}.", this.Bill);
        }

        public void WalkIn()
        {
            Console.WriteLine("Walk into the restaurant.");
            Thread.Sleep(1000);                                                   //Sleep是让控制台等你一段时间,括号里面是毫秒数,1000毫秒就是1秒
        }

        public void SitDown()
        {
            Console.WriteLine("Sit down.");
            Thread.Sleep(1000);
        }

        public void Think()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Let me think...");
                Thread.Sleep(1000);
            }

            if (this.eventHandler != null)                                       //调用以前判空,防止抛出异常
            {                                                                    //有事件订阅eventHandler就不为空
                OrderEventArgs e = new OrderEventArgs();
                e.DishName = "Kongpao Chiken";
                e.Size = "large";

                this.eventHandler.Invoke(this, e);
            }
        }

        public void CustomerAction()
        {
            Console.ReadLine();

            this.WalkIn();
            this.SitDown();
            this.Think();
        }
    }

    public class Waiter
    {
        public static void WaiterAction(Customer sender, OrderEventArgs e)        //事件处理器,根据委托规定,输入两个参数
        {

            Console.WriteLine("I will serve you the dish {0}.", e.DishName);
            Thread.Sleep(1000);

            double price = 10;

            switch (e.Size)
            {
                case "small":
                    price = price * 0.5;
                    break;
                case "large":
                    price = price * 1.5;
                    break;
                default:
                    break;
            }

            sender.Bill += price;
        }
    }
}

这是完整的事件声明。在声明事件以前,你须要准备一个“规矩”,也就是先声明一个委托,约束事件处理器,同时委托的声明伴随事件源和事件参数的声明,本身声明的OrderEventArgs通常要继承Microsoft给你的EventArgs
应该有人留意到我上次写委托的时候,没有给出声明委托的语法,由于我想事件必定用获得(真不是忘了)。声明委托就在第22行,格式为:访问修饰符+delegate+返回值+名字标识符+参数表,很简单的。
最终输出结果:
事件结果2

总结

事件通常不用本身声明,Microsoft给你的通常都够用了。事件的应用范围真的很广,就像你双击文件夹就会打开,这就是一个事件。事件本事创建在委托的基础上,实现一系列的功能,没有委托就没有事件。我当初说事件处理器是一个回调方法,如今留给读者本身细品一下吧。

后记

没想到事件要写这么复杂= =,有点出乎意料,不过它自己确实挺综合的。接下来复习考试了,1月有空再想一想水些别的吧。社团那边好起来了,工做室能拿到是没想到的,再接再砺吧。我月底才更博,就是2077的问题!

相关文章
相关标签/搜索