委托模型和事件模型 [C#]

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(
thisnew 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>>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/407621.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javascript学习系列(3):数组中的foreach方法

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 1前言 在我们的日常开发中 不免会有很多需要处理数据的方法 本节主要说一说f…

stylus之变量(Variables)

变量(Variables)&#xff1a; 变量&#xff1a; 我们可以指定表达式为变量&#xff0c;然后在我们的样式中贯穿使用 编译为 变量甚至可以组成一个表达式列表 标识符&#xff08;变量名&#xff0c;函数等&#xff09;&#xff0c;也可能包括$字符 属性查找&#…

你还不会ant design中的拖拽table实现吗

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 微信公众号关注小歌谣 前言 首先刚开始知道要书写一个这样的功能我的内心是比…

Sharepoint的文档库用资源管理器方式浏览报错“Explorer View ”解决方案。

最近在安装Wss3.0时候&#xff0c;在拷贝已存在资料到客户电脑上时&#xff0c;打开客户的文档库的资源管理器的时候&#xff0c;提示Explorer view 错误&#xff0c;而且客户端访问的时候也报错。 在经过N多的查询和搜索之后终于找到的了解决方法。原来如此http://207.46.19.1…

stylus之插值(Interpolation)

插值(Interpolation)&#xff1a; 插值&#xff1a; Stylus支持通过使用{}字符包围表达式来插入值&#xff0c;其会变成标识符的一部分。例如&#xff0c;-webkit-{‘border’ ‘-radius’}等同于-webkit-border-radius 比较好的例子就是私有前缀属性扩展 变身 选择器…

iOS 两个tableview的 瀑布流

iOS 两个tableview的 瀑布流1. [代码]Objective-C //// DocViewController.m// getrightbutton//// Created by 隋文涛 on 12-12-9.// Copyright (c) 2012年 隋文涛. All rights reserved.//#import "DocViewController.h"#define heightofimage(image) imag…

javascript学习系列(4):数组中的some方法

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 1前言 在我们的日常开发中 不免会有很多需要处理数据的方法 本节主要说一说s…

stylus之运算符(Operators)

运算符(Operators): 运算符优先级: 下表运算符优先级&#xff0c;从最高到最低 一元运算符: 以下一元运算符可用”!”,”not”,”-“,””以及”~” 逻辑运算符not的优先级较低&#xff0c;因此&#xff0c;下面这个例子可以替换 用 二元运算符: 下标运算符[]允…

javascript学习系列(5):数组中的reduce方法

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 1前言 在我们的日常开发中 不免会有很多需要处理数据的方法 本节主要说一说f…

oracle数据导入sqlldr小例子

表结构&#xff1a;emp Sql代码 create table EMP ( empno NUMBER(4) not null, ename VARCHAR2(10), job VARCHAR2(9), mgr NUMBER(4), hiredate DATE, sal NUMBER(7,2), comm NUMBER(7,2), deptno NUMBER(2) …

stylus之混合书写(Mixins)

混合书写(Mixins) Mixins&#xff1a;Mixins是预处器中的函数。平时你在写样式时某段CSS样式要经常重复性的用到多个元素中&#xff0c;这样你就需要重复的写多次。在CSS预处器中&#xff0c;你可以为这些公用的CSS样式定义一个Mixin&#xff0c;然后在你CSS需要使用这些样式的…

javascript学习系列(6):数组中的pop等方法

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 1前言 在我们的日常开发中 不免会有很多需要处理数据的方法 本节主要说一说f…

Android -- 发送Broadcast、有序无序

普通广播 优缺点&#xff1a;和有序广播的优缺点相反&#xff01;发送广播的方法&#xff1a;sendBroadcast()有序广播 …

sqlldr导入数据到数据库

1. 建立一张测试表T_Test create table T_TEST (ID INTEGER,UNAME VARCHAR2(50),AGE INTEGER ) 2. 建立数据文件infile.data(文本文件), 内容如下&#xff1a; 1,张明,20 2,zhou ming, 22 3, 王华good, 25 3. 建立控制文件: T_Test.ctl&#xff0c;文件内容如下&am…

javascript学习系列(7):数组中的concat方法

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 1前言 在我们的日常开发中 不免会有很多需要处理数据的方法 本节主要说一说c…

stylus之方法(Functions)

方法(Functions): 函数:Stylus强大之处就在于其内置的语言函数定义。定义与混入(mixins)一致却可以返回值 返回值: 很简单的例子&#xff0c;两数值相加的方法 我们可以在特定条件下使用该方法&#xff0c;如在属性值中 渲染 默认参数: 可选参数往往有个默认的给定…

[leetcode] Combinations

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. For example,If n 4 and k 2, a solution is: [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ]https://oj.leetcode.com/problems/combinations/ 思路&#xff1a;递归&#xff0c;依次…

stylus之关键字参数(Keyword Arguments)

关键字参数(Keyword Arguments) 关键字参数&#xff1a; Stylus支持关键字参数&#xff0c;或”kwargs”. 允许你根据相关参数名引用参数 下面这些例子功能上都是一样的。但是&#xff0c;我们可以在列表中的任何地方放置关键字参数。其余不键入参数将适用于尚未得到满足的参…

javascript学习系列(8):数组中的splice方法

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 1前言 在我们的日常开发中 不免会有很多需要处理数据的方法 本节主要说一说s…