C#委托五(自定义事件)

事件:

"在发生其他类或对象关注的事情时,类或对象可以通过事件通知他们。发送(或引发)事件的类称为"发行者",接受(或处理)事件的类称为"订户"。"

上面这句话描述了事件的最本质功能,用于底层通知上层。正常的架构设计都是分层结构,而分层结构有一点很重要的就是底层对于上层的无知,当初这样设计是为了解耦,为了更好的面向对象,但是带来的问题是如何解决自下而上的信息流。因为自上而下的调用,我们通过接口就可以搞定一切了,上层可以看到下层提供的服务接口,那么正常的调用可以保证一路向下,底层调用中层提供的服务接口,中层的服务接口的实现中调用了底层的服务接口,这样感觉很是完美的设计模式。每一层都不再依赖彼此,隐藏了实现细节。但是现在遇到一个最简单的问题:如果需要底层来触发上层的行为,如何实现。很多程序员告诉我这个简单,轮询啊,底层不断轮询这一个事情的发生状况,如果发生了则启动一个线程专门去处理这个事情。这种解决方案只需要在底层多开出一个服务接口,该服务接口就是表示目前发生了什么事情,然后上层定时查看该接口,如果发生则采取相应操作。当然该种解决方案也是一种解决途径,但是估计你也觉得不好,第一无法实时,因为轮询,那么必定存在一个时差问题,也就是常说的响应时间问题。还有就是单独的轮询线程需要空间与时间的消耗。最让人郁闷还在于这个对于时空的消耗竟然与响应时间是反相关的,总之你想响应时间短,那么就意味着你不得不浪费大量时空,反之亦然。当然此种方法还要解决多线程冲突的问题,涉及到多线程冲突,锁解锁的问题,那么我觉得就不怕你的逻辑能力有多强,耐心有多大,随着项目规模的变大,线程的变多,你大脑崩溃那是早晚的事情。   此处我们引入事件模式。

先来看看事件的特征: ?发行者确定何时引发事件,订户确定执行何种操作来响应该事件 ?一个事件可以有多个订户。一个订户可处理来自多个发行者的多个事件 ?没有订户的事件永远不会被调用 ?事件通常用于通知用户操作 ?如果一个事件有多个订户,当引发该事件时,会同步调用多个事件处理程序 ?支持异步调用 ?可以利用事件同步线程 ?在 .NET Framework 类库中,事件是基于 EventHandler 委托和 EventArgs 基类的

C#类库中自带了一大堆事件,尤其那些控件。而对于我说到的这个底层触发上层的问题,那么绝大多数是需要自定义事件的。(库中自带事件的使用我就不讲了,如果这个你不会的话,未免对不起观众了。)所以下面就开始着重讲讲自定义事件的问题:

事件是类和对象向外界发出的消息,事件的执行是通过事件委托的方式,调用我们所准备好的处理方法。要响应某些事件并针对某些事件执行我们指定的方法,需要做到以下几步:

  • 声明委托、事件

?

///定义一个委托

public delegate void TestEventHandler(object sender, TestEventArgs e);

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

public event TestEventHandler TestEvent;

  • 添加事件的触发方法,也就是通知接受者方法

?

//事件触发的方法

protected  void OnTestEvent(TestEventArgs e)

{

    if (TestEvent != null)

    {

        TestEvent(this, e);

    }

}

  

  • 添加事件引发方法

?

//引发事件的方法

public void RaiseEvent(char keyToRaiseEvent)

{

    TestEventArgs e = new TestEventArgs(keyToRaiseEvent);

    OnTestEvent(e);

}

  

  • 接受者处本地化响应方法

?

//定义本地处理事件的方法,他与声明事件的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);

}

//取消订阅事件

public void UnSubscribe(TestEventSource evenSource)

{

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

}

  最终全部代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    /// <summary>
    /// 发布事件类
    /// </summary>
    public class TestEventSource
    {
        /// <summary>
        /// 定义事件参数类
        /// </summary>
        public class TestEventArgs : EventArgs
        {
            public readonly char KeyToRaiseEvent;
            public TestEventArgs(char keyToRaiseEvent)
            {
                KeyToRaiseEvent = keyToRaiseEvent;
            }
        }

        ///定义一个委托
        public delegate void TestEventHandler(object sender, TestEventArgs e);
        ///用event关键字声明事件对象
        public event TestEventHandler TestEvent;

        //事件触发的方法
        protected  void OnTestEvent(TestEventArgs e)
        {
            if (TestEvent != null)
            {
                TestEvent(this, e);
            }
        }

        //引发事件的方法
        public void RaiseEvent(char keyToRaiseEvent)
        {
            TestEventArgs e = new TestEventArgs(keyToRaiseEvent);
            OnTestEvent(e);
        }
    }

    //监听事件类
    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);
        }

        //取消订阅事件
        public void UnSubscribe(TestEventSource evenSource)
        {
            evenSource.TestEvent -= new TestEventSource.TestEventHandler(KeyPressed);
        } 

    }

    class Program
    {
        static void Main(string[] args)
        {
            ///创建事件源对象
            TestEventSource es = new TestEventSource();

            ///创建监听对象
            TestEventListener el = new TestEventListener();

            ///订阅事件
            Console.WriteLine("订阅事件\t");
            el.Subscribe(es);

            ///引发事件
            Console.WriteLine("输入一个字符,再按enter键");
            string str = Console.ReadLine();
            es.RaiseEvent(str.ToCharArray()[0]);

            //取消订阅事件
            Console.WriteLine("\n取消订阅事件\n");
            el.UnSubscribe(es);

            //引发事件
            Console.WriteLine("输入一个字符,再按enter健");
            str = Console.ReadLine();
            es.RaiseEvent(str.ToCharArray()[0]);
            Console.ReadLine();

        }
    }
}

赋值粘贴即可以执行,且看下面截图执行效果:

时间: 2024-10-10 13:47:36

C#委托五(自定义事件)的相关文章

C# 窗体间传值(使用委托与自定义事件)

using System; using System.Drawing; using System.Windows.Forms; namespace 跨窗体调用控件 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Form2 f = new Form2(); f.Change

[02]WPF异步响应,自定义事件、委托——多线程处理

题记 在编写有GUI的程序时,会遇到这样一种情形:用户点击了一个按钮,程序处理这个事件,然而这个处理过程耗时间较长.我们不想让软件卡在这里,而是让用户可以继续使用其他的软件功能.这种问题可以用多线程的事件响应来解决.这里,我就WPF的多线程事件响应做一个简单的归纳. 一.简单的异步的事件响应 在WPF中,针对简单的多线程处理过程,我们可以使用.NET自带的BackgroundWork完成.BackgroundWork的处理过程就是异步的,不会让用户界面停止响应. using System.Com

利用委托自定义事件

事件,这个大家都非常熟悉的名词,代码里几乎离不开它.但是我们平时都是用现成的事件,如果满足不了我们的需求怎么办?那就只能咱自己写了,那么问题就来了,如何自定义事件呢? 在这之前,我们就必须先了解事件与委托的干系是什么,只有弄清楚事物的本质,我们才能掌握住事物的灵魂. 我们先看看最常用的一个事件:Form_Load() public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs

C#自定义事件模拟风吹草摇摆

这是一个自定义事件的例子.C#.WinForm.Visual Studio 2017.在HoverTreeForm中画一块草地,上面有许多草(模拟).HewenqiTianyi类模拟天气,会引发“风”事件(HoverTreeWindEvent),风有东风或西风,或静止.当吹东风,草往西边倒,吹西风则往东边到.静止则草不会东歪西倒.草地上每一颗草都监听HoverTreeWindEvent事件,根据风向(WindDdirection)调整姿态.HewenqiTianyi中有定时器,每隔一段时间触发调

jQuery基础(鼠标事件,表单事件,键盘事件,自定义事件 篇)

1.jQuery鼠标事件之click与dbclick事件 方法一:$ele.click()(不带参数) <div id="test">点击触发<div> $("ele").click(function(){ alert('触发指定事件') }) $("#test").click(function(){ $("ele").click() //手动指定触发事件 });   方法二:$ele.click( h

C#事件的理解以及自定义事件的方法

事件的理解: 在skyline项目的开发中,遇到了一个新的知识:事件. 在程序中,我希望实现一个功能,当视点坐标移动的时候可以实时的得到视点的坐标.这里就需要使用事件这个概念:当坐标发生移动,则触发了一个特定的事件,他可以发出一个信号,而用户可以自定义一个函数(参数必须与事件委托的参数相同,这个后面解释),当他发出一个信号,我就可以执行这个函数. 比方说:甲和乙是朋友,上午见面了,乙和甲说,今天中午吃完饭叫我一声,我带你去网吧玩. 在这个情景中,甲吃饭这件事情是乙没有办法控制的.他只可以等甲吃完

c#自定义事件

今天重温了一下事件的概念,对事件的理解也更加深刻一点.说到底事件就是一个特殊的委托.当我们去定义一个事件时,我们一旦触发了这个事件,意味着我们同时调用了背后的一系列方法.我们知道委托或者匿名函数(匿名方法和Lambda表达式)都是通过委托去传递一个方法参数,来达到我们的要求.如果说,我们要处理一个功能,需要一些列的动作才能完成,意味着我们需要传递多种方法,并且还要以一定的顺序来执行,我们就可以使用事件这个东东.换句话说,一旦我们绑定好了一个事件的一系列方法,当触发这个事件时,一些的方法,就会被顺

漫谈js自定义事件、DOM/伪DOM自定义事件

一.说明.引言 我JS还是比较薄弱的,本文的内容属于边学边想边折腾的碎碎念,可能没什么条理,可能有表述不准确的地方,可能内容比较拗口生僻.如果您时间紧迫,或者JS造诣已深,至此您就可以点击右侧广告(木有?则RSS或盗版)然后撤了. 事件是个大课题,真要从断奶开始讲起的话,可以写个12期的连载.关于JS事件的文章(类似DOM/BOM事件模型,IE与其他浏览器事件差异,DOM1/DOM2事件定义等)落叶般随处可见.熟豆子反复炒一点意思都没有,因此,这里谈谈自己感兴趣的自定义事件以及周边. 所谓自定义

js自定义事件、DOM/伪DOM自定义事件

一.说明.引言 我JS还是比较薄弱的,本文的内容属于边学边想边折腾的碎碎念,可能没什么条理,可能有表述不准确的地方,可能内容比较拗口生僻.如果您时间紧迫,或者JS造诣已深,至此您就可以点击右侧广告(木有?则RSS或盗版)然后撤了. 事件是个大课题,真要从断奶开始讲起的话,可以写个12期的连载.关于JS事件的文章(类似DOM/BOM事件模型,IE与其他浏览器事件差异,DOM1/DOM2事件定义等)落叶般随处可见.熟豆子反复炒一点意思都没有,因此,这里谈谈自己感兴趣的自定义事件以及周边. 所谓自定义