委托模型和事件模型 [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>>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值