如果类型定义了事件成员,那么类型(或类型实例)就可以通知其他对象发生了特定的事情。例如Button类提供了一个名为Click的事件,应用程序中的一个或多个对象可能想接收关于这个事件的通知,以便在Button被点击之后采取某些操作。事件是实现这种交互的类型成员。具体的说,如果定义一个事件成员,意味着类型要提供以下能力:

1. 方法可登记它对该事件的关注;

2. 方法可注销它对该事件的关注;

3. 该事件发生时,登记了的方法会受到通知。

观察者模式非常类似。。。

  类型之所以能提供事件的通知功能,是因为类型维护了一个已登记方法的列表,事件发生后,类型将通知列表中所有已登记的方法。

事件创建代码示例:

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

namespace CreateEvent
{
    // NO.1 定义一个类型 作用:容纳 所有 需要发送给 事件 通知 接收者 的附加信息
    internal class NewMailEventArgs: EventArgs
    {
        private readonly string m_From, m_To, m_Subject;
        public NewMailEventArgs(string From, string To, string Subject)
        {
            m_From = From;
            m_To = To;
            m_Subject = Subject;
        }
        public string From { get { return m_From; } }
        public string To { get { return m_To; } }
        public string Subject { get { return m_Subject; } }
    }

    /// <summary>
    /// 扩展方法的应用(this 关键字)
    /// </summary>
    public static class EventArgExtensions
    {
        // where关键字用于约束:TEventArgs 必须是 EventArgs 类型的
        public static void Raise<TEventArgs>(this TEventArgs e, object sender,
            ref EventHandler<TEventArgs> eventDelegate)
            where TEventArgs : EventArgs
        {
            // 出于线程安全的考虑,现在将对委托字段的引用复制到一个临时字段中
            EventHandler<TEventArgs> temp = Interlocked.CompareExchange(ref eventDelegate, null, null);

            // 任何方法登记了对事件的关注,就通知他们
            if (temp != null)
            {
                temp(sender, e);
            }
        }
    }

    /// <summary>
    /// 包含 事件的 类
    /// </summary>
    internal class MailManager 
    {
        // NO.2 定义事件成员
        public event EventHandler<NewMailEventArgs> NewMail;

        // NO.3 定义一个负责引发事件的方法,它通知已登记的对象 事件已经发生。
        // 如果类是密封的,这个方法要声明为私有和非虚
        protected virtual void OnNewMail(NewMailEventArgs e)
        {
            // 调用扩展方法(Raise是一个静态方法,但e是一个实例)
            e.Raise(this, ref NewMail);
        }

        // No.4 定义一个方法,将输入转化为期望事件
        public void SimulateNewMail(string From, string To, string Subject)
        {
            // 构造一个对象来容纳 想传给通知接收者的信息
            NewMailEventArgs e = new NewMailEventArgs(From, To, Subject);

            // 调用虚方法通知对象 事件已发生,如果没有重写虚方法,该对象将通知事件的所有登记对象
            OnNewMail(e);
        }
    }
}

事件发生时,被通知的类型:

internal sealed class Fax
{
    /// <summary>
    /// 将MailManage对象传给构造器
    /// </summary>
    /// <param name="mm"></param>
    public Fax(MailManager mm)
    {
        // 构造 EventHandler<NewMailEventArgs> 委托的一个实例,
        // 使它引用我们的FaxMsg回调方法。
        // 向 MailManage 的NewMail事件 登记我们的回调方法
        // 类似观察者模式(观察者向被观察者注册)
        mm.NewMail += FaxMsg;
    }

    /// <summary>
    /// 向MailManage对象的NewMail事件 注销自己对它的关注
    /// </summary>
    /// <param name="mm"></param>
    public void Unregister(MailManager mm)
    {
        mm.NewMail -= FaxMsg;
    }

    /// <summary>
    /// 新电子邮件到达时,MailManage将调用这个方法 
    /// </summary>
    /// <param name="sender">表示MailManage对象,便于将信息传给它</param>
    /// <param name="e">表示MailManage对象想传给我们的附加事件信息</param>
    private void FaxMsg(object sender, NewMailEventArgs e)
    {
        System.Windows.Forms.MessageBox.Show("Fax Mail message:From:" + e.From + "," +
                                                              "To:" +  e.To + "," +
                                                              "Subject:" + e.Subject);
    }        
}

测试代码:

private void button1_Click(object sender, EventArgs e)
{
      // mm:被观察者
      MailManager mm = new MailManager();

      // pFax,pPhone,pPlayer:观察者
      Fax pFax = new Fax(mm);

      // 触发事件
      mm.SimulateNewMail("大花", "小花", "Happy New Year!");

      // 取消关注
      pFax.Unregister(mm);

      pFax = null;
      mm = null;
}

代码执行效果:弹出提示框 “Fax Mail message:From:大花,To:小花,Subject:Happy New Year!”。

posted on 2015-06-08 16:40  花爱春  阅读(246)  评论(0编辑  收藏  举报