事件学习——1. 事件的认识

定义:能够发生什么的事情
事件担任的角色:使对象或者类具备通知能力的成员
        
对象A拥有一个事件B,表达的思想是:当事件B发生的时候,A有能力通知别的对象
使用:用于对象或类间的动作协调与信息传递(消息推送)
 

原理:事件模型(event model)的两个5
        发生->响应中的5个部分
——闹钟响了你起床、孩子饿了你做饭等等,隐含着“订阅”关系
闹钟,响了,我,做饭这是四个部分,第五个部分是订阅关系,指的是我只订阅着我闹钟响铃这个事件
        发生->响应中的5个动作——1. 我有一个事件;2. 一个人或者一群人关心我这个事件 3. 我这个事件发生了;4. 关心这个事件的人会被依次(先订阅先通知,后订阅后通知)通知;5. 被通知到的人根据拿到的事件信息(又称“事件数据”,“事件参数”,“通知”)对事件进行响应(又称“处理事件”)
 

提示:
 1. 事件多用于桌面、手机等开发的客户端编程,因为这些程序经常是用户通过事件来“驱动”的
 2. 各种编程语言对这个机制的实现方法不尽相同
 3. Java语言里没有事件这种成员,也没有委托这种数据类型。Java的“事件”是用接口来实现的
 4. MVC、MVP、MVVM等模式,是事件模式更高级、更有效地方法
 5. 日常开发的时候,使用已有事件的机会比较多,自己声明事件的机会比较少,所以先学使用

 事件的功能 = 通知 + 可选的事件参数(即详细信息)

名词解释:
事件的订阅者=事件消息的接收者=事件的响应者=事件的处理者=被事件所通知的对象
事件参数=事件信息=事件消息=时间数据

如果说某某对象拥有一个某某事件,解释如下:这个对象可以通过他的事件来通知别的对象,关心这个事件的对象纷纷做出响应

 事件模型的五个组成部分
①. 事件的拥有者(event source,一定是一个对象或者一个类)
②. 事件成员(event,成员)——事件不会主动发生
③. 事件的响应者(event subscriber,对象)
④. 事件处理器(event handler,成员)——本质上是一个回调方法
⑤. 事件订阅——把事件处理器与事件关联在一起,本质上是一种以委托类型为基础的“约定”

 注意事项:
①. 事件处理器是方法成员
②. 挂接事件处理器的时候,可以使用委托实例,也可以直接使用方法名,这是个“语法糖”
③. 事件处理器对事件的订阅不是随意的,匹配与否由声明事件时所使用的委托类型来检测
④. 事件可以同步调用也可以异步调用

 来个简单的例子:

using System;
using System.Timers;
//using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _6.事件的定义
{    

internal class Program
    {

        static void Main(string[] args)
        {
            //1. 创建Timer对象
            Timer timer = new Timer();//timer就是事件的拥有者,其拥有事件elapsed
            //timer.此时出现的候选词有三种符号,分别是扳手,方块,闪电,分别对应属性、方法、事件
            //对于一个类或者一个对象来说,最重要的三个功能就是属性、方法、事件
            //属性表示这个类当前处于的状态;方法表示他能做什么;事件表示它能在什么情况下通知谁

            timer.Interval = 1000;//每过一秒触发elapsed的事件
            //4. 创建事件响应者对象
            Boy boy = new Boy();//boy对象就是事件响应者

            Girl girl = new Girl();//同上


            //5. 订阅事件,此时Boy类中并没有方法,我们写一个Action方法,用Action方法订阅Elap事件
            //6. 这个时候Action下面会标红并出现提示,按下Alt+enter选择生成方法
            timer.Elapsed += boy.Action;//事件订阅的操作符为+=
            timer.Elapsed += girl.Action;//同上

            timer.Start();
            Console.ReadLine();
        }
    }

    //2. 创建事件响应者,其应该有一个方法叫事件处理器去订阅事件
    class Boy
    {
        //3. 注意,此时不需要手写方法,等会可以自动生成
        internal void Action(object sender, ElapsedEventArgs e)//7. VS就会按照“约定”自动生成这个方法(事件处理器)
        {
            //throw new NotImplementedException();默认生成的这行不要
            //8. 当Elapsed事件发生,boy就拿着Action去响应事件
            Console.WriteLine("Jump!");//每秒打印一个Jump
        }
    }

    //同上
    class Girl
    {
        internal void Action(object sender, ElapsedEventArgs e)
        {
            //throw new NotImplementedException();
            Console.WriteLine("Sing!");
        }
    }
}

 结果如下,每秒打印一次Jump!和Sing!:

 当事件的拥有者和响应者为不同的对象时



 

代码如下:
 

using System;
using System.Timers;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _6.事件的定义
{

//在这个例子程序中,事件的拥有者和事件的响应者是完全不同的两个对象,
    //响应者用自己的事件处理器订阅着事件,事件发生的时候事件处理器就执行了

    //本例子中在引用中增加了对Systemm.Windows.Forms的引用
    internal class Program
    {
        static void Main(string[] args)
        {
            Form form = new Form();//显示出来是一个窗体,form为事件拥有者
            Controller controller = new Controller(form);//事件的响应者controller
            form.ShowDialog();

        }
    }

    class Controller
    {
        private Form form;//添加字段
        public Controller(Form form)//添加构造器,可以接受一个Form 类型的参数
        {
            //判断为空是因为如果一个对象是空的,无法访问其事件
            if (form != null)
            {
                this.form = form;//字段的form等于我传进来的参数

                //当this.form获得了对form对象的引用之后,为form的Click添加一个事件处理器
                this.form.Click += this.FormClicked;//this代表Controller的实例
                //Click为form的事件
            }
        }

        //注意下面第二个参数是EventArgs,与例一的ElapsedEventArgs不一样,说明他们的约定不一样
        private void FormClicked(object sender, EventArgs e)//事件处理器
        {
            //throw new NotImplementedException();
            this.form.Text = DateTime.Now.ToString();//输出当前时间
        }
    }
}

结果如下,点击窗体中间左上角标题显示时间:

 当事件拥有者和响应者为同一个对象


代码如下: 
 

using System;
using System.Timers;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _6.事件的定义
{


//一个对象拿着自己的方法订阅自己的事件
    internal class Program
    {
        static void Main(string[] args)
        {
            //如果使用Form类来自己订阅自己,在生成事件处理器的时候会报错,因为Form类已经被官方写死
            //Form form = new Form();
            //form.Click += form.Action;
            //如果自己定义一个Form类的话又无法使用Click等事件,故需要用派生类

            //事件拥有者同时也是事件响应者
            MyForm form = new MyForm();//子类可以使用父类的成员
            form.Click += form.FormClicked;//事件Click,订阅关系+=
            form.ShowDialog();
        }
    }


    class MyForm : Form
    {
        //事件处理器
        internal void FormClicked(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
            this.Text = DateTime.Now.ToString();
        }
    }
}

结果如下,效果同上一个:

 当事件拥有者是事件响应者的一个字段成员(使用最多!!!)

 

 代码如下:
 

using System;
using System.Timers;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _6.事件的定义
{
 
//事件响应者用自己的方法订阅自己字段成员的某个事件

    //做一个小页面,包括一个按钮一个文本框,按下按钮显示事件
    internal class Program
    {
        static void Main(string[] args)
        {
            MyForm myForm = new MyForm();
            myForm.ShowDialog();
        }
    }

    //事件响应者是MyForm对象
    class MyForm : Form
    {
        private TextBox _textBox;
        private Button _button;//事件拥有者,且为Form的一个字段成员

        public MyForm()
        {
            this._textBox = new TextBox();
            this._button = new Button();

            this.Controls.Add(this._textBox);//把textbox加入到显示页面
            this.Controls.Add(this._button);//同上
            this._button.Click += this.ButtonClicked;//事件,订阅
            this._button.Text = "Time";
            this._button.Top = 100;
            this._textBox.Width = 150;

        }

        //事件处理器
        private void ButtonClicked(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
            this._textBox.Text = DateTime.Now.ToString();
        }
    }
}

结果如下:

在WinForm 中的事件的挂接方式

 1. 在同一个事件处理器中响应三个事件

private void ButtonCliked(object sender, EventArgs e)//一个事件可以挂接多个事件处理器,一个事件处理器也可以被多个事件挂接
        {
            //我们可以根据事件Source的不同处理不同的事件
            if (sender == this.button1)
            {
                this.textBox1.Text = DateTime.Now.ToString();
            }
            if (sender == this.button2)
            {
                this.textBox1.Text = "Hello World!";
            }
            if (sender == this.button3)
            {
                this.textBox1.Text = "1234";
            }
        }

2. 普通的挂接事件

//this.button3.Click += this.ButtonCliked;//我们可以这样挂接事件处理器,也可以在界面上控件属性中选择ButtonCliked

3. 利用委托完成

 this.button3.Click += new EventHandler(this.ButtonCliked);

4. Lambda表达式

this.button3.Click += (sender, e) =>
            {
                this.textBox1.Text = "3333";
            };//参数类型object,EventArgs可以由委托的约束自行推断出来

完成代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace _7.事件详解_01
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            //this.button3.Click += this.ButtonCliked;//我们可以这样挂接事件处理器,也可以在界面上控件属性中选择ButtonCliked

            //当然也可以像这样挂接
            //this.button3.Click += new EventHandler(this.ButtonCliked);
            //当打出一个new再按下空格的时候,VS自动判断定义这个事件的时候用的委托是谁并变蓝,委托即EventHandler
            //当你创建委托实例的时候,构造器会问你要方法明,鼠标挪过去可以知道他需要一个object和一个EventArgs类型的参数

            //还有一种很少见的挂接事件方式(基本废弃了)
            //this.button3.Click += delegate (object sender, EventArgs e)
            //{
            //    this.textBox1.Text = "2222";
            //};
            //此时Button3.Click的事件处理器就不是下面的方法了,而是上面这个匿名方法

            //代替上面的是下面这种方式
            this.button3.Click += (sender, e) =>
            {
                this.textBox1.Text = "3333";
            };//参数类型object,EventArgs可以由委托的约束自行推断出来


        }

        //当事件处理器和被处理的事件保持约束关系上的一致时,这个事件处理器可以被重复使用
        //即Button2也可以用Button1的Click方法
        private void ButtonCliked(object sender, EventArgs e)//一个事件可以挂接多个事件处理器,一个事件处理器也可以被多个事件挂接
        {
            //我们可以根据事件Source的不同处理不同的事件
            if (sender == this.button1)
            {
                this.textBox1.Text = DateTime.Now.ToString();
            }
            if (sender == this.button2)
            {
                this.textBox1.Text = "Hello World!";
            }
            if (sender == this.button3)
            {
                this.textBox1.Text = "1234";
            }
        }
    }
}

结果如下:

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值