1. 多播委托

    与委托有关的语法:

定义委托:<modifiers> delegate <return_type> <delegate_name> (<argument_list>)
                    public delegate void Message() ;

创建委托实例:<delegate_type> <name> = new <delegate_type> (<method>)
                    Message msg = new Message(Messages.Greeting);

调用委托:<delegate_name> (<argument_list>)
                    msg();

多播委托是指引用多个方法的委托。当调用委托时,它连续调用每个方法。为了把委托的单个实例合并为一个多播委托,委托必须是同类型的,返回类型必须是void,不能带输出参数选择(但可以带引用参数)。多播委托用于C#的事件模型中。

示例:多播委托

using System;

public delegate void Message(); //定义一个无参数的委托

public class Messages //Messages类定义了三个方法打印不同的消息。返回类型为void,不带参数
{
    public static void Greeting()
    {
        Console.WriteLine("Welcome to Mandolin Co.");
    }

    public static void DateAndTime()
    {
        Console.WriteLine(DateTime.Now.ToLongDateString());
    }

    public static void Maintenance()
    {
        Console.WriteLine("System maintenance will be done tonight");
    }
}
using System;

class MultiDemo
{
    public static void Main()
    {
        Message msg; 
        //Create a multi-cast delegate that will print out a number of messages

        msg = new Message(Messages.Greeting); //创建委托实例
        msg += new Message(Messages.DateAndTime);

        Message msg2 = new Message(Messages.Maintenance); //创建委托实例
        msg += msg2;//三个Message委托串在一起形成了多播委托
        msg(); //调用委托

        //A delegate is removed from the multi-cast

        Console.WriteLine();

        msg -= msg2;//从多播委托msg中删除了一个委托msg2
        msg(); //调用委托

        Console.ReadKey();
    }    
}

运行结果:
Welcome to Mandolin Co.
2008年3月1日
System maintenance will be done tonight

Welcome to Mandolin Co.
2008年3月1日

2. 事    件

    2.1 C#事件模型

    C#使用一种委托模型来实现事件。事件处理方法不必在将生成事件的类中定义。设想应用程序中有两个按钮,但这两个按钮的作用不同。如果事件处理程序被绑定到事件源,我们可能必须写两个派生的按钮类,每个派生类有自己的事件处理程序。而在委托模型下,按钮类仍是通用的,只是事件处理程序必须分别定义。事件处理程序可以(通常)放在不同的类中。
    在委托模型下需要的是把事件源和事件处理程序连接起来的一种机制。这是委托发挥作用的地方。委托提供对指定了返回类型和参数列表的方法的一般引用。方法做什么对委托并不重要。事件委托可以定义为生成事件的类的一个成员。将用来处理事件的方法和事件处理委托关联起来。当事件发生时,调用委托,然后调用事件处理方法。
    事件处理委托是多播的。
    事件的基本生命周期过程为:事件生成者把事件委托的一个实例定义为它的成员。事件消费者是那些希望在事件发生时得到通知的对象。它们定义将和事件委托关联的事件处理方法。当生成事件时,事件生成者通过调用事件委托“触发”事件。然后委托调用和它关联的事件处理方法。
    事件委托把两个对象发送给每个事件处理方法。第一个是对生成事件的对象的引用,称为事件源。第二个对象将是System.EventArgs类的一个实例,或者EventArgs的一个派生类的实例。该对象包含了关于事件的额外信息。

2.2 事件委托

    事件委托的一般形式:

    <modifiers> delegate void <delegate_name>(object source, EventArgs e);

其参数列表中总是有两个参数。第一个参数代表事件源。第二个参数是EventArgs类的一个实例,或者它的派生类的一个实例,它包含事件的另外的信息。例如:MouseEventArgs类定义下列属性:
    public MouseButtons Button { get; }
    public int Clicks { get; }
    public int Delta { get; }
    public int X { get;}
    public int Y { get;} 
    这些属性告诉事件处理程序哪个按钮引发了事件,事件中有几次单击,和事件发生的地方。

.NET Framework类库中的事件委托

这些内建的委托都派自System.Delegate类。下面是System.Windows.Forms命名空间中包含的几个事件处理委托:
    public delegate void ColumnClickEventHandler(object source, ColumnClickEventArgs args)
    public delegate void DragEventHandler(object source, DragEventArgs args)
    public delegate void KeyEventHandler(object source, KeyEventArgs args)
    public delegate void MouseEventHandler(object source, MouseEventArgs args)

可知,所有这些内建的委托都遵循标准的事件委托格式:返回类型为void,参数列表中有两个参数。

用户定义的事件委托

    您也可以按照事件委托的一般形式定义自己的事件委托。也可以定义自己的从EventArgs类派生的类,包含和委托有关的信息。例如:如果想定义一个委托响应某个对象名称的变化,可以这样定义:
    public delegate void NameEventHandler(object source, NameEventArgs args);
    您还必须定义NameEventArgs类。

创建事件委托实例

事件委托实例的创建和标准委托的创建的不同之处是不使用new关键字,而是使用event关键字。创建上面的委托的实例的语法是:
    public event NameEventHandler handler;
    event关键字告诉编译器这个委托实例是一个事件。编译器将保证该委托拥有一个事件委托的正确签名。编译器也将事件委托能进行的操作限制为+=和-=运算符。上面的语句创建一个空引用,指向一个名为handler的事件委托。空状态表明还没有事件处理程序和这个委托关联起来。

    2.3 事件处理程序

事件处理程序是事件生成时事件委托调用的一个方法。事件处理方法可以在一个不同于事件源的类中定义。因为和事件委托关联在一起,事件处理程序总是和事件委托有相同的参数列表和返回类型。
    要把事件处理程序和事件关联起来,事件必须在它维护的委托的列表中添加和方法相关联的委托。例如:如果想把一个名为NameChange()的事件处理程序和一个名为handler的NameEventHandler实例关联起来,使用的语法为:
    handler += new NameEventHandler(NameChange);

    2.4 触发事件

要让类能够触发事件,应该把事件委托的一个实例定义为类的成员。生成事件的类应该定义确定什么时候生成事件的代码,还应该定义生成提供事件的EventArgs对象的代码。
    要触发事件,只需要调用事件委托实例。

3. 用户定义的事件

    这个例子中我们创建并应用一个用户定义的事件。NameList类代表在列表中添加一个字符串时生成事件的ArrayList。ArrayList被定义为一个字段。NameList类还把一个NameListEventHandler实例声明为字段。除了构造函数,Add()方法是NameList类包含的唯一的一个函数成员。
    Add()方法把指定的字符串添加到ArrayList。它接着查看是否有事件处理委托已经添加到了NameListEventHandler实例。如果有的话,则调用该事件委托,委托又调用这些方法,把对事件源的引用和NameListEventArgs类的一个实例传递给方法。
    NameListEventHandler委托的第二个参数是一个NameListEventArgs对象。NameListEventArgs类封装了有关NameList类生成的事件的信息。它定义了两个字段,String表示添加到列表中的名称,和一个整型值为列表中名称的当前数量。NameListEventArgs类定义了一个公有的构造函数和两个属性返回字段的值。

using System;
using System.Collections;

public delegate void NameListEventHandler(object source, NameListEventArgs args);

public class NameList
{
    ArrayList list;

    public event NameListEventHandler nameListEvent;

    public NameList()
    {
        list = new ArrayList();
    }

    public void Add(string Name)
    {
        list.Add(Name);
        if (nameListEvent != null)
        {
            nameListEvent(this, new NameListEventArgs(Name, list.Count));
        }
    }
}

public class NameListEventArgs : EventArgs
{
    string name;
    int count;

    public NameListEventArgs(string str, int i)
    {
        name = str;
        count = i;
    }

    public string Name
    {
        get
        {
            return name;
        }
    }

    public int Count
    {
        get
        {
            return count;
        }
    }
}

EventDemo类创建一个NameList对象。NameList对象的事件委托在它的列表中添加两个事件处理委托。第一个引用NewName()方法。第二个引用CurrentCount()方法。这两个方法都在EventDemo类中定义。
     然后在NameList中添加两个名称。每添加一个名称,就触发一个事件,NewName()和CurrentCount()方法都被调用。这些方法输出被添加的名称和列表中名称的个数:

using System;

public class EventDemo
{
    public static void Main()
    {
        NameList names = new NameList();

        names.nameListEvent += new NameListEventHandler(NewName);
        names.nameListEvent += new NameListEventHandler(CurrentCount);

        names.Add("Flowfield");
        names.Add("Bosworth");

        Console.ReadKey();
    }

    public static void NewName(object source, NameListEventArgs args)
    {
        Console.WriteLine(args.Name + " was added to the list");
    }

    public static void CurrentCount(object source, NameListEventArgs args)
    {
        Console.WriteLine("list currently has " + args.Count + " items");
    }
}

运行结果:
Flowfield was added to the list
list currently has 1 items
Bosworth was added to the list
list currently has 2 items

这个例子一个要注意的要点是,事件处理代码和事件源是完全分开的。您可以在完全不改变NameList类本身的情况下,改变在NameList中添加一个元素时调用的方法。

摘自<<C# Programmer's Reference>>

委托模型和事件模型 [C#]相关推荐

  1. 朴素贝叶斯模型 多元伯努利事件模型+多项式事件模型 Multi-Variate Bernoulli Event Model and Multinomial Event Model

    朴素贝叶斯模型(Naïve Bayes Models): 适用于离散分布的朴素贝叶斯模型是个概率模型.生成式模型.广泛用于文本分类,自然语言处理和模式识别. 生成式和判别式模型区别: 贝叶斯公式如下: ...

  2. nginx进程模型,事件模型

    众所周知,nginx性能高,而nginx的高性能与其架构是分不开的.那么nginx究竟是怎么样的呢?这一节我们先来初识一下nginx框架吧. nginx在启动后,在unix系统中会以daemon的方式 ...

  3. .net 事件委托 java_仿net事件委托的java事件模型实现(转csdn)

    作为对比,我们来看看Java Swing的事件处理和委托就要复杂很多:代码如下:(您若还不是很了解Swing事件驱动的话,可以参考我的另外一篇文章:事件驱动模型实例详解(Java篇))://为btnS ...

  4. JS基础-事件模型(事件事件流自定义事件事件冒泡/代理)

    文章目录 一.事件与事件流 二.事件模型 1.DOM0级模型 2.IE事件模型 3.DOM2级模型 4.DOM3级事件处理方式 三.事件对象 四.事件绑定与解除 1.事件绑定 1.1对象.on事件名字 ...

  5. 12.在JavaScript中的事件模型如何理解?

    一.事件与事件流 javascript中的事件,可以理解就是在HTML文档或者浏览器中发生的一种交互操作,使得网页具备互动性, 常见的有加载事件.鼠标事件.自定义事件等 由于DOM是一个树结构,如果在 ...

  6. 设计模式---观察者模式(Observer)和委托事件模型(DEM)

    1 引言 观察者模式,又名发布订阅模式,是一个一对多的关系,当被观察者发生某种变化,对应其观察者做出相应的改变.比如说,某学校研究生实验室有2个学生,2个学生某个上午在实验室,A在玩游戏,B在看电影, ...

  7. java委托事件模型_JAVA授权事件模型讲解(原创)

    JAVA的授权事件模型包含三个概念:事件源,事件,事件监听器. 一,事件源:一个产生事件的对象.当这个对象的内部状态改变时,事件就会产生.一个事件源必须注册一个事件监听器已使监听器能够可以接受一个特定 ...

  8. 事件模型、事件流(冒泡与捕获)、事件代理

    本文原链接:https://www.cnblogs.com/hngdlxy143/p/9068282.html https://www.jb51.net/article/139997.htm 事件模型 ...

  9. .NET 事件模型教程(一)

    .NET 事件模型教程(一) .code { padding: 10px 10px 10px 10px; font-family: 宋体; background-color: #ececec } 目录 ...

最新文章

  1. Sublime Text 3 插件的安装、升级和卸载
  2. 图像金字塔(pyramid)与 SIFT 图像特征提取(feature extractor)
  3. 在Android中使用OpenGL ES开发第(五)节:GLSL基础语法
  4. Rancher搭建NFS服务器
  5. Mybatis用#{}从传递过来的参数中取值
  6. 前端学习(2364):图片的上传
  7. 设计模式状态模式uml_UML的完整形式是什么?
  8. tarball_如何在墙上扔一个tarball
  9. Select prototyping tools
  10. 使用AD14创建异形PCB板
  11. Word怎么撤销到上一步操作
  12. 不是所有国产软件都像360一样流氓!这些良心国产软件不该被埋没
  13. 基于layui的开源项目LAYUI MINI后台模板
  14. 小程序开通直播的思路总结
  15. MySQL之库表设计篇:一到五范式、BC范式与反范式详解
  16. Ameya360代理 | 兆易创新发布GD32A503系列首款车规级MCU
  17. catia草图里写字_请问CATIA如何在曲面上写字,麻烦高手解答详细步骤?
  18. Bzoj4627 [BeiJing2016]回转寿司
  19. 基于C6748+FPGA的高精度北斗接收机设计与实现
  20. 龙珠斗士z服务器位置,龙珠斗士Z配置要求介绍

热门文章

  1. 微型计算机主存可以分为,计算机基础试题 (含答案)
  2. MySQL提高插入数据的效率(结合JDBC)
  3. 1021 个位数统计 (15 分
  4. iptables详解和练习
  5. 函数read、write、lseek
  6. Wireshark(1):Wireshark基本用法
  7. java招聘职位描述,附学习笔记+面试整理+进阶书籍
  8. 你知道如何用面向对象思想写好并发编程吗?
  9. 学习笔记整理之StringBuffer与StringBulider的线程安全与线程不安全
  10. Github 简明教程 - 添加远程库