事件

SunnyFan大约 7 分钟约 2208 字

事件

事件和委托的区别

{
    Cat cat = new Cat(); 
    //cat.Miao();//不好的玩法--依赖太重; 
    //1.通过定义委托属性
    //2.给委托+=方法--Miao一声之后,要触发的动作
    //3.特点;把要执行的动作不放在猫的内部从外面去指定
    //4.多播委托+=来完成了一系列动作的转移,把猫Miao一声后的动作转移到上端
    //5.去掉了猫对于其他的依赖---提高了猫的稳定性
    //6.通过委托实现了观察者模式--观察者模式---把不属于我的动作转移出去---甩锅 
    Console.WriteLine("************************this is  delegate****************************");
    {
        cat.MiaoAction += new Dog().Wang; //狗叫了
        cat.MiaoAction += new Mouse().Run;//老鼠跑了
        cat.MiaoAction += new Mother().Wispher;
        cat.MiaoAction += new Baby().Cry; // 小孩哭了
        //cat.MiaoAction += new Mother().Wispher;
        cat.MiaoAction += new Father().Roar;
        cat.MiaoAction += new Neighbor().Awake;
        cat.MiaoAction += new Stealer().Hide;
        //cat.MiaoAction = null;
        cat.MiaoDelegate();
        cat.MiaoAction();//可以执行
    }
    //1.复制---粘贴---增加了一个Event关键字
    //2.事件--委托和事件有什么联系和区别?
    //事件是委托的实例--事件是特殊的委托;
    //都可以+=/-=;
    //3.既然有了多播委托,为什么又搞个事件呢?
    //  a.安全--事件是只能在类的内部执行;
    //  b.就算是你的子列也不能执行当前类中的事件,只能由自己来执行;--反射呢.---可以试试
    //  c.事件从外面操作,只能有一个+=/-=;
    Console.WriteLine("************************this is  MiaoEventHanlder****************************");
    {
        cat.MiaoEventHanlder += new Dog().Wang; //狗叫了
        cat.MiaoEventHanlder += new Mouse().Run;//老鼠跑了
        cat.MiaoEventHanlder += new Mother().Wispher;
        cat.MiaoEventHanlder += new Baby().Cry; // 小孩哭了 
        cat.MiaoEventHanlder += new Father().Roar;
        cat.MiaoEventHanlder += new Neighbor().Awake;
        cat.MiaoEventHanlder += new Stealer().Hide; 
        //cat.MiaoEventHanlde = null; 
        cat.MiaoEnvent(); 
        //cat.MiaoEventHanlder.Invoke(); //不能执行
    }
    //Console.Read();
    //区别:上面是通过多播委托来了支持---语法层面来支持   
    //两者从本质上来说是没有什么太大的区别; 
    //区别:下面是通过面向对象的方法会来完成观察者---程序设计层面来支持
    Console.WriteLine("************************this is  Obeserver****************************");
    {
        cat.observerlist.Add(new Dog()); //狗叫了
        cat.observerlist.Add(new Mouse());//老鼠跑了
        cat.observerlist.Add(new Baby()); // 小孩哭了
        cat.observerlist.Add(new Mother());
        cat.observerlist.Add(new Father());
        cat.observerlist.Add(new Neighbor());
        cat.observerlist.Add(new Stealer());
        cat.MiaoObsever();
    }
}
{
    /// <summary>
    ///猫:
    /// Miao:引发了一系列的动作; 
    /// 从代码层面来说:代码这样写好吗?
    /// 
    /// 不好:
    /// 1.职责不单一---一个类中包含的职责太多了,除了Miao 一声,依赖于其他的类太多;
    /// 2.依赖太重--依赖于Dog、Mouse、....---代码不稳定;Dog、Mouse、....任何一个类的修改,都有可能会影响到这只猫;
    /// 3.这完全是面向过程式编程--完全是翻译需求;
    /// 
    /// 
    /// 改造:
    /// 1.职责单一: 猫--职责:仅仅知识Miao一下;其他的动作,不是猫的动作;
    /// 2.猫Miao一声后会引发一些列的动作;应该放出去,不能属于这只猫
    /// 3.猫Miao一声后,触发一些列的动作---不能把这一些列的动作放在猫的内部
    /// </summary>
    public class Cat
    {
        /// <summary>
        ///
        /// </summary>
        //public void Miao()
        //{
        //    Console.WriteLine("{0} Miao", this.GetType().Name);
        //    new Dog().Wang(); //狗叫了
        //    new Mouse().Run();//老鼠跑了
        //    new Baby().Cry(); // 小孩哭了
        //    new Mother().Wispher();
        //    new Father().Roar();
        //    new Neighbor().Awake();
        //    new Stealer().Hide();
        //}

        public  Action MiaoAction = null; 
        /// <summary>
        /// 这个方法仅仅只是Miao一声
        /// 引发的动作---可以放到多播委托中去
        /// </summary>
        public void MiaoDelegate()
        {
            Console.WriteLine("{0} MiaoDelegate", this.GetType().Name);
            //if (MiaoAction != null)
            //{
            //    MiaoAction.Invoke();
            //}
            MiaoAction?.Invoke();//?. 如果不为null ,就执行后面的动作 
        }


        //static 常驻内存

        public   event Action MiaoEventHanlder = null;
        /// <summary>
        /// 这个方法仅仅只是Miao一声
        /// 引发的动作---可以放到多播委托中去
        /// </summary>
        public void MiaoEnvent()
        {
            Console.WriteLine("{0} MiaoEnvent", this.GetType().Name);
            MiaoEventHanlder?.Invoke();//?. 如果不为null ,就执行后面的动作 
        }
         
        public List<IObject> observerlist = new List<IObject>();

        public void MiaoObsever()
        {
            Console.WriteLine("{0} MiaoObsever", this.GetType().Name);
            if (observerlist.Count>0)
            {
                //observerlist.ForEach(item => item.DoAction());

                foreach (var item in observerlist)
                {
                    item.DoAction();
                }

            }
        }
    }

    public class ChildCat : Cat
    {
        public void Show()
        {
            base.MiaoAction(); //子类中执行父类中共的多播委托--可以执行
            //base.MiaoEventHanlder.Invoke();//子类中执行父类的时间--不能执行
        }
    }
}

事件-观察者模式(发布订阅者模式)的—的几大要素

//关于事件的在Winform中的应用
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        
        /// <summary>
        ///  如果点击按钮,就会触发这个方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param> 
        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void button1_ClickTest(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// 注册
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click_1(object sender, EventArgs e)
        {

        }

        private void btnLogin_Click(object sender, EventArgs e)
        {

        }

        //Winform:
        //登录按钮:双击--生成了一个方法:运行起来,点击按钮---触发这个方法;
        //怎么完成的? 
        //1.按钮其实是一个Button对象实例:继承Control---Control有一个Click事件---事件( EventHandler(object? sender, EventArgs e)) 
        //2.Form1构造函数函数中有一个InitializeComponent方法;在InitializeComponent方法中初始化Button按钮实例,个Button的实例中的Click事件+=一个动作(button1_Click方法) 
        //3.点击按钮---触发事件---触发事件就是执行注册事件的方法

        //其实是鼠标点击左键,就可以触发;为什么要这样设计呢,为什么一定要使用事件呢?
        //1.程序运行----句柄被监听---监听鼠标的点击的动作---触发操作系统---操作系统就要去找这个句柄是在哪个应用程序中---控件---执行这个控件中的事件---触发了方法


        //2.在按钮点击触发方法的设计中---有很多相同的逻辑(指向按钮,按钮会变色)+很多不同的业务逻辑;就把不变的业务逻辑封装---代码重用,可变的业务逻辑对外发布一个事件,由外部给事件注册动作;需要执行动作的时候;就把不变的,封装在内部的业务逻辑执行;还执行事件(把外部注册到事件上的动作给执行了);注册事件什么动作,就执行什么动作----可以让不同的场景共用相同的业务逻辑,分贝指定各自不同的业务逻辑;

        //3.框架设计的时候,是非常需要这种设计的;----ASP.NET MVC5管道处理模型;---就是通过19大事件来完成的;

    }
}

标准事件的定义

{
    EventStandard1.Show();
    EventStandard2.Show();
    //1.初始化发布者和订阅者之间的关系
    EventStandard1.Init();
    EventStandard1.Show();
}
{

    /// <summary>
    /// 
    /// 
    /// 
    /// </summary>
    public class EventStandard1
    {
        ///发布者的实例---公众号的实例已存在
        private static PublicNumber publicNumber = new PublicNumber()
        {
            Id = 123,
            Name = "NET社区"
        };

        public static void Show()
        {
            publicNumber.PublishShow();//再公众号发布了一片文章
        }

        //订阅:关联发布者和订阅者之间的关系 (初始化发布者和订阅者之间的关系)
        public static void Init()
        {
            {
                ///订阅者的实例
                Teacher teacher = new Teacher()
                {
                    Id = 234,
                    Name = "Richard老师"
                };

                //订阅者的实例
                NETer nETer = new NETer()
                {
                    Id = 345,
                    Name = "小菜同学"
                };
                //建立发布者和订阅者之间的关系
                publicNumber.Push += teacher.Read;
                publicNumber.Push += nETer.AddTeache;
            }
        }
    }

    /// <summary>
    /// 
    /// 发布者:对完发布事件;当触发一个动作后,触发这个事件
    /// </summary>
    public class PublicNumber
    { 
        public int Id { get; set; }
        public string Name { get; set; }

        public void PublishShow()
        {
            Console.WriteLine("发布了一片关于.NET5的文章。。。包含了环境安装的文档。。。");
            Push.Invoke(this, new MessageInfo()
            {
                Id = 567,
                Title = ".NET5的文章。。",
                Description = "发布了一片关于.NET5的文章。。。包含了环境安装的文档。。。",
                TeacherWechatNum = "MrRichard2020"
            });
        }
        public event EventHandler Push;
    }


    /// <summary>
    /// 订阅者:对发布者发布的事情关注
    /// </summary>
    public class Teacher
    {

        //public Teacher(PublicNumber publicNumber)
        //{
        //    publicNumber.Push += this.Read;
        //}

        public int Id { get; set; }
        public string Name { get; set; }

        public void Read(object? sender, EventArgs e)
        {
            MessageInfo info = (MessageInfo)e;
            Console.WriteLine("内容干货满满。。。。。");
        }
    }

    /// <summary>
    /// 订阅者:对发布者发布的事情关注
    /// </summary>
    public class NETer
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public void AddTeache(object? sender, EventArgs e)
        {
            MessageInfo info = (MessageInfo)e;
            Console.WriteLine("内容很多干货。。。");
            Console.WriteLine($"添加了助教老师的微信{info.TeacherWechatNum}。。。去获取更多");
        }
    }

    public class MessageInfo : EventArgs
    {
        public int Id { get; set; }

        public string Title { get; set; }

        public string Description { get; set; }

        public string TeacherWechatNum { get; set; }
    }
}
{
    public class EventStandard2
    {
        public static void Show()
        {
            AdvancedClass frameworkClass = new AdvancedClass()
            {
                Id = 1,
                Name = "高级班VIP课程",
                Price = 4299
            };
            //订阅:就是个订户和事件发布者关联起来
            frameworkClass.PriceIncrease += new StudentInfo().Buy;
            frameworkClass.PriceIncrease += new Tencent().Extension;
            frameworkClass.Price = 6299;
        }

        /// <summary>
        /// 订户: 关注事件,事件触发后,自己做出相应的动作
        /// </summary>
        public class StudentInfo
        {
            public void Buy(object sender, EventArgs e)
            {
                AdvancedClass frameworkClass = (AdvancedClass)sender;
                AdvancedClassEventArge eventArge = (AdvancedClassEventArge)e;
                Console.WriteLine($"this is {frameworkClass.Name}");
                Console.WriteLine($"{frameworkClass.Name}之前的价格是{eventArge.OldPrice}");
                Console.WriteLine($"{frameworkClass.Name}现在要马上更新的价格是{eventArge.NewPrice}");
                Console.WriteLine("果断买了。。。"); 
                Console.WriteLine($"{frameworkClass.Name}现在要马上更新的价格是{eventArge.NewPrice}");
            }
        }

        /// <summary>
        /// 订户,关注事件,事件触发之前,做出点动作
        /// </summary>
        public class Tencent
        {
            public void Extension(object sender, EventArgs e)
            {
                AdvancedClass frameworkClass = (AdvancedClass)sender;
                AdvancedClassEventArge eventArge = (AdvancedClassEventArge)e;
                Console.WriteLine($"this is {frameworkClass.Name}");
                Console.WriteLine($"{frameworkClass.Name}之前的价格是{eventArge.OldPrice}");
                Console.WriteLine($"{frameworkClass.Name}现在要马上更新的价格是{eventArge.NewPrice}");
                Console.WriteLine("马上推广一波。。"); 
            }
        }


        public class AdvancedClassEventArge : EventArgs
        {
            public int OldPrice { get; set; }
            public int NewPrice { get; set; }
        }

        /// <summary>
        /// 事件的发布者,发布是按并且在满足条件的情况下,触发事件
        /// </summary>
        public class AdvancedClass
        {
            public int Id { get; set; }
            public string Name { get; set; }

            private int _price = 5299;

            public int Price
            {
                get
                {
                    return _price;
                }
                set
                {
                    if (value > _price)
                    {
                        ///触发一部分动作 
                        PriceIncrease.Invoke(this, new AdvancedClassEventArge()
                        {
                            OldPrice = _price,
                            NewPrice = value
                        });
                    }

                    _price = value;
                }
            }
            public event EventHandler PriceIncrease;
        }
    }
}