C#事件(Event)的理解

C#事件(Event)的理解

事件的定义:

C# 事件(Event): 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。

事件是委托的一个实例。

事件需要在类中声明。

事件使用 发布-订阅(publisher-subscriber) 模型。

发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。

订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。

事件的类型

事件一般分为两种:

  • 带参数传递的

  • 不带参数传递的

基于上述的理解,实现 .Net 框架中的事件需要三个步骤。

  • 实现事件的发布类

  • 实现事件的订阅类

  • 实现发布和订阅的关联(类似Qt中的信号关联)。

注意:

发布类里应当实现:
1、事件的触发(类似Qt中的发送信号emit signal));
2、事件的引发方法

订阅类中应当实现:
事件接收时的操作,(Qt 中信号槽Slot)

现在来看下面的两个例子,如下:

1、不带参数传递的事件

namespace SimpleEvent
{  
    /***********发布器类***********/
    public class EventTest
    {
        private int value;    //定义一个参数

        public delegate void NumManipulationHandler();


        public event NumManipulationHandler ChangeNum;
        protected virtual void OnNumChanged()
        {
            if (ChangeNum != null)
            {
                ChangeNum(); /* 事件被触发 */
            }
            else
            {
                Console.WriteLine("event  not triggered");
                Console.ReadKey(); /* 回车继续 */
            }
        }


        public EventTest()     //构造函数
        {
            int n = 5;
            SetValue(n);      //将值设置为5
        } 


        public void SetValue(int n)
        {
           // value = Console.ReadKey();
            if (value != n)
            {
                value = n;
                OnNumChanged();   //当前后的值放生变化的时候触发事件
            }
        }
    }


    /***********订阅器类***********/

    public class subscribEvent
    {
        public void printf()
        {
            Console.WriteLine("event has been triggered");
            Console.ReadKey(); /* 回车继续 */
        }
    }

    /***********触发***********/
    public class MainClass
    {
        public static void Main()
        {
            EventTest e = new EventTest();    /* 实例化发布者对象,第一次没有触发事件,屏幕上显示“event  not triggered" */
            subscribEvent v = new subscribEvent(); /* 实例化订阅者对象 */
            e.ChangeNum += new EventTest.NumManipulationHandler(v.printf); /* 注册 */
            e.SetValue(7);  //第二次触发事件,屏幕上显示event has been triggered
            e.SetValue(11); //第三次触发事件,屏幕上显示event has been triggered
        }
    }
}

2、带参数传递的

namespace EventDemo
{

    /// <summary>

    /// 发布事件的类

    /// </summary>

    public class TestEventSource
    {

        //定义事件参数类

        public class TestEventArgs : EventArgs
        {

            public readonly char KeyToRaiseEvent;  //键盘值; 

            public TestEventArgs(char keyToRaiseEvent)
            {

                KeyToRaiseEvent = keyToRaiseEvent;

            }

        }

        //定义delegate

        public delegate void TestEventHandler(object sender, TestEventArgs e);  //sender:事件发布者;e:传递事件的参数

        //用event 关键字声明事件对象

        public event TestEventHandler TestEvent;

        //事件触发方法

        protected virtual void OnTestEvent(TestEventArgs e)
        {

            if (TestEvent != null)

                TestEvent(this, e);    // 触发事件;发布者不为空,即触发事件

        }

        //引发事件

        public void RaiseEvent(char keyToRaiseEvent)
        {

            TestEventArgs e = new TestEventArgs(keyToRaiseEvent);   

            OnTestEvent(e);

        }

    }

}
namespace EventDemo
{

    /// <summary>

    /// 监听事件的类

    /// </summary>

    public class TestEventListener
    {

        //定义处理事件的方法,他与声明事件的delegate具有相同的参数和返回值类型

        public void KeyPressed(object sender, TestEventSource.TestEventArgs e)
        {

            Console.WriteLine("发送者:{0},所按得健为:{1}", sender, e.KeyToRaiseEvent);

        }

        //订阅事件

        public void Subscribe(TestEventSource evenSource)
        {

            evenSource.TestEvent += new TestEventSource.TestEventHandler(KeyPressed);  //将发布者的testEvent 方法与订阅者的KeyPressed方法关联

        }

        //取消订阅事件

        public void UnSubscribe(TestEventSource evenSource)
        {

            evenSource.TestEvent -= new TestEventSource.TestEventHandler(KeyPressed);

        }

    }

}
namespace EventDemo
{

    class Program
    {

        static void Main(string[] args)
        {

            //创建事件源对象

            TestEventSource es = new TestEventSource();

            //创建监听对象

            TestEventListener el = new TestEventListener();

            //订阅事件

            Console.WriteLine("订阅事件\n");

            el.Subscribe(es);

            //引发事件

            Console.WriteLine("输入一个字符,再按enter键");

            string s = Console.ReadLine();

            es.RaiseEvent(s.ToCharArray()[0]);

            //取消订阅事件

            Console.WriteLine("\n取消订阅事件\n");

            el.UnSubscribe(es);

            //引发事件

            Console.WriteLine("输入一个字符,再按enter健");

            s = Console.ReadLine();

            es.RaiseEvent(s.ToCharArray()[0]);

        }

    }

}

在上述例子中:

TestEventSource类。他就相当于windows控件类一样,是事件的源,里面包含有事件的声明,以及存储调用参数的事件参数类,以及事件的触发方法。

TestEventListener类。他提供了事件处理程序,并实现了事件处理程序和事件对象的邦定。

Test 类,实例化自定义事件的事件源对象,并调用 TestEventListener类中的Subscribe(es);方法进行事件对象和事件处理程序的邦定(订阅事件),调用 TestEventSource类中的RaiseEvent(char keyToRaiseEvent)引发对象,并有对象所指定的委托回调处理事件。完成整个自定义事件。

其中 RaiseEvent(char keyToRaiseEvent) 就相当于main()一样是自定义事件的执行入口, 从这个法开始—〉调用事件委托----〉查找订阅事件程序找到事件所封装的方法集----〉由委托回调事件处理程序并传递参数—〉执行事件处理程序。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值