C#学习笔记(二)(委托与事件专题 )

63 阅读3分钟

事件概述

什么是事件

  • 事件就是.NET对委托的封装;
namespace DelegateDemo1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            MusicPlayer mp3 = new MusicPlayer();
            mp3.AfterStartedPlay = () =>
            {
                Console.WriteLine("加载歌词...");
                Console.WriteLine("加载背景...");
            };
            mp3.StartPlay();
            mp3.BeforeStopedPlay = () =>
            {
                Console.WriteLine("删除歌词...");
                Console.WriteLine("删除背景...");
            };
            mp3.StopPlay();
        }  
    }
    public class MusicPlayer
    {
        //做几个事件
        //1. 音乐开始播放后触发某个事件
        public Action AfterStartedPlay;

        //2. 音乐停止播放之前触发某个事件
        public Action BeforeStopedPlay;

        private void PlayMusic()
        {
            Console.WriteLine($"开始播放...");
        }
        /// <summary>
        /// 按下【播放】开始播放音乐
        /// </summary>
        public void StartPlay()
        {
            PlayMusic();
            if (AfterStartedPlay != null)
            {
                AfterStartedPlay();
            }
        }
        /// <summary>
        /// 按下【停止】停止播放音乐
        /// </summary>
        public void StopPlay()
        {
            if(BeforeStopedPlay != null)
            {
                BeforeStopedPlay();
            }
            Console.WriteLine($"播放结束...");
        }
    }
}
  • 使用委托实现控件点击事件
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 WinFormDelegate
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            userControl_Button1.TripleClick = () =>
            {
                MessageBox.Show("1");
            };
        }
    }
}
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 WinFormDelegate
{
    public partial class UserControl_Button : UserControl
    {
        public UserControl_Button()
        {
            InitializeComponent();
        }
        public Action TripleClick;

        int count = 0;
        private void button1_Click(object sender, EventArgs e)
        {
            count++;
            if(count >= 3)
            {
                if(TripleClick != null)
                {
                    TripleClick();
                }
                count = 0;
            }
        }
    }
}

  • 使用事件实现控件点击事件
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 WinFormDelegate
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 事件只能用 += 或 -= 赋值
            userControl_Button1.TripleClick += () =>
            {
                MessageBox.Show("1");
            };
        }
    }
}
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 WinFormDelegate
{
    public partial class UserControl_Button : UserControl
    {
        public UserControl_Button()
        {
            InitializeComponent();
        }
        // 当加了event之后,委托变量就变成了一个事件
        public event Action TripleClick;

        int count = 0;
        private void button1_Click(object sender, EventArgs e)
        {
            count++;
            if(count >= 3)
            {
                if(TripleClick != null)
                {
                    // 事件在触发或调用的时候,与委托一样
                    TripleClick();
                }
                count = 0;
            }
        }
    }
}

事件与委托的区别

  • 因为委托是public的,它可以在外界随意调用,而不是只有当事件发生之后才调用;
  • 若将委托改为private的,那么它就不可以在外界调用了,但是它也不能在外界给它绑定方法了。
  • 委托可以直接使用=赋值,可以将以前注册的方法都覆盖掉 (= null)。
  • 因此需要事件。
  • 事件是.NET对委托的封装。
  • 事件只能使用 += -= 来赋值,而 += -= 不能赋null值
  • 事件在外部不能直接调用,事件只能在定义事件的类的内部触发。
  • 使用ILSPY看到事件就是一个私有的委托和两个公有的方法。
namespace DelegateDemo1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            MusicPlayer mp3 = new MusicPlayer();
            mp3.AfterStartedPlay = () =>
            {
                Console.WriteLine("加载歌词...");
                Console.WriteLine("加载背景...");
            };
            mp3.StartPlay();
            mp3.BeforeStopedPlay = () =>
            {
                Console.WriteLine("删除歌词...");
                Console.WriteLine("删除背景...");
            };
            mp3.StopPlay();
        }  
    }
    public class MusicPlayer
    {
        //做几个事件
        //1. 音乐开始播放后触发某个事件
        public Action AfterStartedPlay;

        //2. 音乐停止播放之前触发某个事件
        public Action BeforeStopedPlay;

        private void PlayMusic()
        {
            Console.WriteLine($"开始播放...");
        }
        /// <summary>
        /// 按下【播放】开始播放音乐
        /// </summary>
        public void StartPlay()
        {
            PlayMusic();
            if (AfterStartedPlay != null)
            {
                AfterStartedPlay();
            }
        }
        /// <summary>
        /// 按下【停止】停止播放音乐
        /// </summary>
        public void StopPlay()
        {
            if(BeforeStopedPlay != null)
            {
                BeforeStopedPlay();
            }
            Console.WriteLine($"播放结束...");
        }
    }
}
  • 事件可以写在接口里面,类实现这个接口之后,就会编译成一个委托加两个方法。
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 WinFormDelegate
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.ucLogin1.Login += (object arg1,UserEventArgs eventArgs) =>
            {
                if(eventArgs.UserName == "admin" && eventArgs.Password == "123")
                {
                    eventArgs.IsLoggedIn = true;
                }
            };
        }
    }
}
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 WinFormDelegate
{
    public partial class UCLogin : UserControl
    {
        public UCLogin()
        {
            InitializeComponent();
        }
        public event Action<object,UserEventArgs> Login;
        private void Btn_Login_Click(object sender, EventArgs e)
        {
            if (Login != null)
            {
                UserEventArgs eventArgs = new UserEventArgs();
                eventArgs.UserName = this.Uid.Text;
                eventArgs.Password = this.Pwd.Text;
                eventArgs.IsLoggedIn = false;
                Login(this,eventArgs);
                if (eventArgs.IsLoggedIn)
                {
                    this.BackColor = Color.Green;
                }
                else
                {
                    this.BackColor = Color.Red;
                }
            }
        }
    }
    public class UserEventArgs : EventArgs
    {
        public string UserName;
        public string Password;
        public bool IsLoggedIn;
    }
}

观察者模式

  • Subject 被观察者:包含其他对象感兴趣的内容;
  • Observer 观察者:当Subject中的某件事发生的时候,会告知Observer,Observer会采取相应的行动。
  • 观察者模式
namespace ObserveMode
{
    public class Program
    {
        static void Main(string[] args)
        {
            HeaterSubject heaterSubject = new HeaterSubject();
            heaterSubject.OnBoil += new DisplayObserver().ShowTemperature;
            heaterSubject.OnBoil += new AlertObserver().MakeAlert;

            heaterSubject.BoilWater();
        }
    }
    /// <summary>
    /// 烧水壶
    /// </summary>
    public class HeaterSubject
    {
        // 【水温】
        private int temperature;

        public event Action<int> OnBoil;

        /// <summary>
        /// 【烧水】
        /// </summary>
        public void BoilWater()
        {
            for(int i = 0; i < 100; i++)
            {
                temperature = i;
                if(temperature > 95)
                {
                    if(OnBoil != null)
                    {
                        OnBoil(temperature);
                    }
                }
            }
        }
    }
    public class DisplayObserver
    {
        public void ShowTemperature(int param)
        {
            Console.WriteLine($"水温 {param} 度");
        }
    }
    public class AlertObserver
    {
        public void MakeAlert(int param)
        {
            Console.WriteLine($"水开了,已经{param}度了。");
        }
    }
}