C#学习记录(八)事件

目录

1、定义:单词Event译为事件

2、实例:派生(继承)与扩展(extends)

3、注意:

4、事件的声明

5、事件的命名约定

6、事件与委托的关系

1、定义:单词Event译为事件

  • 通顺的解释就是能够发生什么事

角色:使对象或类具备通知能力的成员

  • 事件是一种使对象或类能够提供通知的成员
  • 对象O拥有一个事件E,想表达的思想是:当事件E发生时,O有能力通知别的对象

使用:用于对象或类间动作协调与信息传递(消息推送)

原理:事件模型(event model)中的两个5

  1. 发生->响应中的5个部分——这里隐含订阅的关系
  2. 发生->响应中的5个动作——1.我有一个事件2.一个人或一群人关心我的事件3.我的事件发生了4.关心这个事的人依次被通知到,5.被通知的人根据事件拿到的消息(又称事件数据、事件参数、通知)对事件进行响应(又称处理事件)

提示:事件多用于桌面、手机登开发的客户端编程,因为是通过事件来驱动的。MVC、MVP、MVVM等模式,是事件模式更高级,更有效的玩法。日常开发的时候,使用已有事件的机会比较多,自己声明事件的机会比较少,所以先学使用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;
namespace 事件
{
    class Program
    {
        static void Main(string[] args)
        {
            #region 简单的事件
            /*
            //1、事件的拥有者timer
            System.Timers.Timer timer = new System.Timers.Timer();
            timer.Interval = 1000;
            //声明一个Boy变量
            //3、事件的响应者
            Boy boy = new Boy();
            Girl girl = new Girl();
            //事件处理器
            //事件订阅  事件+=事件处理器
            timer.Elapsed += boy.Aciton;
            timer.Elapsed += girl.Action;
            //打开
            timer.Start();
            */
            #endregion
            #region  点击窗体出现当前时间
            /*
            //事件的拥有者
            Form form = new Form();
            //事件的响应者
            Controller controller = new Controller(form);
            form.ShowDialog();
            */
            #endregion  
            #region 派生Form自己的类MyForm
            /*
            //事件的拥有者、事件的响应者
            MyForm myForm = new MyForm();
            //Click事件
            //事件订阅 事件+=事件处理器
            myForm.Click += myForm.FormClicked;
            //运行
            myForm.ShowDialog();
            */
            #endregion
            #region 点击显示Helloworld
            MyForm1 myForm1 = new MyForm1();
            myForm1.ShowDialog();
            #endregion
            Console.ReadKey();
        }
    }
    #region 简单的事件处理器
    /// <summary>
    /// 跳针处理器
    /// </summary>
    class Boy
    {
        //事件处理器
        internal void Aciton(object sender, ElapsedEventArgs e)
        {
            Console.WriteLine("Jump!");       
        }
    }
    /// <summary>
    /// 另一个处理器
    /// </summary>
    class Girl
    {
        internal void Action(object sender, ElapsedEventArgs e)
        {
            Console.WriteLine("Sing!");
        }
    }
    #endregion
    #region 点击出现当前时间
    class Controller
    {
        private Form form;
        public Controller(Form form)
        {
            if (form!=null)
            {
                this.form = form;
                //为form挂接一个事件处理器
                //事件订阅
                this.form.Click += this.FormCliched;
            }
        }
        //事件处理器
        private void FormCliched(object sender, EventArgs e)
        {
            this.form.Text = DateTime.Now.ToString();
        }   
    }
    #endregion
    #region 派生创建自己的类
    class MyForm : Form
    {
        //事件处理器
        internal void FormClicked(object sender, EventArgs e)
        {
            this.Text = DateTime.Now.ToString();
        }
    }
    #endregion
    #region 点击显示Helloworld
    #endregion
    class MyForm1:Form
    {
        private TextBox textBox;
        private Button button;
        public MyForm1()
        {
            this.textBox = new TextBox();
            this.button = new Button();
            this.Controls.Add(this.button);
            this.Controls.Add(this.textBox);
            this.button.Click += this.ButtonClicked;
            this.button.Text = "Say Hello!";
            this.button.Top=100;
        }
        private void ButtonClicked(object sender, EventArgs e)
        {
            this.textBox.Text = "Hello World!!!!!!!!!!!!!!!!";
        }
    }
}

2、实例:派生(继承)与扩展(extends)

事件模型的五个组成部分

  • 1、事件的拥有者(event source,对象)
  • 2、事件成员(event,成员)
  • 3、事件响应者(event subscriber,对象)
  • 4、事件处理器(event handler ,成员)——本质是一个回调方式
  • 5、事件订阅——把事件处理器与事件关联在一起,本质是一种以委托类型为基础的约定

3、注意:

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

4、事件的声明

完整声明、简略声明(字段式声明、field-like)

有了委托字段属性为什么还需要事件

所以事件的本质是委托字段的一个包装器

  • 这个包装器对委托字段的访问起限制作用,相当于一个蒙版
  • 封装(encapsulation)的重要功能就是隐藏
  • 事件对外界隐藏了委托实例的大部分功能,仅暴露添加/移除事件处理器的功能
  • 添加/移除事件处理器的时候可以直接使用方法名,这是委托所不具备的功能

用于声明事件的委托类型的命名约定

用于声明Foo事件的委托,一般命名为FooEventHandler(除非是一个非常通用的事件约束)

FooEventHandler委托的参数一般有两个

  1. 第一个是object类型,名字为sender,实际上就是事件的拥有者、事件的source
  2. 第二个是EventArgs类的派生类类名一般为FooEventArgs,参数名为e也就是事件参数
  • 触发Foo事件的方法一般命名为OnFoo即因何而发、事出有因
  • 访问级别为protected、不能为public

5、事件的命名约定

  • 带有时态的动词或动词短语
  • 事件拥有者正在做什么事情,用进行时;事件拥有者做完了什么事情,用完成时
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 事件2
{
    class Program
    {
        static void Main(string[] args)
        {
            #region 完整声明方式调用          
            Customer customer = new Customer();
            Watier watier = new Watier();
            //事件订阅
            customer.Order += watier.Action;
            //触发事件
            customer.Aciton();
            customer.PayTheBill();
            #endregion
            #region 简略声明格式调用
            /*
            Customer customer = new Customer();
            Watier watier = new Watier();
            //事件订阅
            customer.Order += watier.Action;
            //触发事件
            //customer.Aciton();
            customer.PayTheBill();
            //之外随便访问字段
            OrderEventArgs e = new OrderEventArgs();
            e.DisName = "manhanquanxi";
            e.Size = "large";
            OrderEventArgs e2 = new OrderEventArgs();
            e2.DisName = "Beer";
            e2.Size = "large";
            Customer badGuy = new Customer();
            badGuy.Order += watier.Action;
            badGuy.Order.Invoke(customer, e);
            badGuy.Order.Invoke(customer, e2);
            customer.PayTheBill();
            */
            #endregion
            //实例化一个事件发送器
            KeyInputMonitor monitor = new KeyInputMonitor();
            //实例化一个事件接收器
            EventReceiver eventReceiver = new EventReceiver(monitor);
            //运行
            monitor.Run();
        }
    }
    #region 完整声明方式
    /// 声明数据类型
    public class OrderEventArgs :EventArgs
    {
        public string DisName { get; set; }
        public string Size { get; set; }
    }
    /// 声明委托类型
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
    /// 声明事件类
    public class Customer
    {
        //声明委托类型的字段
        private OrderEventHandler orderEventHandler;
        //声明事件
        public event OrderEventHandler Order
        {
            //事件处理器添加器
            add
            {
                this.orderEventHandler += value;
            }
            //事件处理器移除器
            remove
            {
                this.orderEventHandler -= 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.");
        }
        public void SitDown()
        {
            Console.WriteLine("Sit Down.");
        }
        public void Think()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Let me think...");
                Thread.Sleep(1000);
            }
            //判断是否为空
            if (this.orderEventHandler!=null)
            {
                OrderEventArgs e = new OrderEventArgs();
                e.DisName = "Kongpao Chicken";
                e.Size = "large";
                this.orderEventHandler.Invoke(this,e);
            }
        }
        //进行操作
        public void Aciton()
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown();
            this.Think();
        }
    }
    //事件的响应者
    public class Watier
    {
        public  void Action(Customer customer, OrderEventArgs e)
        {
            Console.WriteLine("I Will serve you the dish -{0}",e.DisName);
            double price = 10;
            switch (e.Size)
            {
                case "small":
                    price = price * 0.5;
                    break;
                case "large":
                    price = price * 1.5;
                    break;
                default:
                    break;
            }
            customer.Bill += price;
        }
    }
    #endregion
    #region 简略声明格式
    /*
/// 声明数据类型
public class OrderEventArgs : EventArgs
{
    public string DisName { get; set; }
    public string Size { get; set; }
}
/// 声明委托类型
public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
/// 声明事件类
public class Customer
{
    //声明委托类型的字段
    public OrderEventHandler Order;
    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.");
    }
    public void SitDown()
    {
        Console.WriteLine("Sit Down.");
    }
    public void Think()
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("Let me think...");
            Thread.Sleep(1000);
        }
        //判断是否为空
        //直接使用事件的名字来进行调用
        if (this.Order != null)
        {
            OrderEventArgs e = new OrderEventArgs();
            e.DisName = "Kongpao Chicken";
            e.Size = "large";
            this.Order.Invoke(this, e);
        }
    }
    //进行操作
    public void Aciton()
    {
        Console.ReadLine();
        this.WalkIn();
        this.SitDown();
        this.Think();
    }
}
//事件的响应者
public class Watier
{
    public void Action(Customer customer, OrderEventArgs e)
    {
        Console.WriteLine("I Will serve you the dish -{0}", e.DisName);
        double price = 10;
        switch (e.Size)
        {
            case "small":
                price = price * 0.5;
                break;
            case "large":
                price = price * 1.5;
                break;
            default:
                break;
        }
        customer.Bill += price;
    }
}
*/
    #endregion
    #region 简单练习
    internal class KeyEventArgs:EventArgs
    {
        private char keyChar;
        public KeyEventArgs(char keyChar):base()
        {
            this.keyChar = keyChar;
        }
        public char KeyChar
        {
            get
            {
                return keyChar;
            }
        }
    }
    internal class KeyInputMonitor
    {
        //创建一个委托,类型为void
        public delegate void KeyDownEventHandler(object sender, KeyEventArgs e);
        //将创建的委托和特定事件关联,这里特定事件为KeyDown
        public event KeyDownEventHandler KeyDown;
        public void Run()
        {
            bool finished = false;
            do
            {
                Console.WriteLine("Input  a Char !");
                string response = Console.ReadLine();
                char resposeChar = (response == "") ? ' ' : char.ToUpper(response[0]);
                //得到的按键信息的参数
                KeyEventArgs keyEventArgs = new KeyEventArgs(resposeChar);
                //触发事件
                KeyDown(this, keyEventArgs);
            } while (!finished);
        }
    }
    internal class EventReceiver
    {
        public EventReceiver(KeyInputMonitor monitor)
        {
            //产生一个委托实例并添加到产生的事件列表中
            monitor.KeyDown += new KeyInputMonitor.KeyDownEventHandler(this.OnKeyDown);
        }
        private void OnKeyDown(object sender, KeyEventArgs e)
        {
            //真正的事件处理函数
            Console.WriteLine("Capture key:{0}",e.KeyChar);
        }
    }
    #endregion  
}

6、事件与委托的关系

事件真的是以特殊方式声明的委托字段/实例吗?

不是!只是看起来像对比委托字段与事件的简化声明

事件声明的时候使用了委托类型,简化声明造成事件看上去像一个委托的字段(实例)

而event关键字更像一个修饰符——这就是错觉的来源之一

订阅事件看起来像个委托字段——这是错觉的又一来源

重申:事件的本质是加装在委托字段上的一个蒙版(mask),是个起掩蔽作用的包装器,这个用于阻挡非法操作的蒙版绝不是委托字段本身

为什么要使用委托类型来声明事件

  • 站在source的角度来看,是为了表明source能对外传递那些消息
  • 站在subscriber的角度来看,它是一种约束,是为了约束能够使用什么样签名的方法来处理(响应)事件

委托类型的实例将用于存储(引用)事件处理器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值