第十四章 事件

14.1 发布者/订阅者

  • 发布者(publisher):发布某个事件的类或结构,其他类可以在该事件发生时得到通知。
  • 订阅者(subscriber):注册并在事件发生时得到通知的类或结构
  • 事件处理程序(event handler) :由订阅者注册到事件的方法,在发布者触发事件时执行。事件处理程序方法可以定义在事件所在的类或结构中,也可以定义在不同的类或结构中。
  • 触发(raise)事件 调用(invoke)或触发(fire)事件的术语:当事件触发时,所有注册到它的方法都会被依次调用。

有关事件的私有委托

  • 事件提供了对它的私有控制委托的结构化访问。即你无法直接访问委托。
  • 事件中可用的操作比委托少,对于事件我们只可以添加、删除或调用事件处理程序。
  • 事件被触发时,它调用委托来依次调用调用列表中的方法。

14.2 源代码组件概览

一个完整的组件由5部分组成:

  • 委托类型声明:事件和事件处理程序必须有共同的签名和返回类型,他们通过委托类型进行描述。
  • 事件处理程序声明:订阅者类中会在事件触发时执行的方法声明。可以是显式命名的方法,也可以是匿名方法或Lambda表达式。
  • 事件声明:发布者类必须声明一个订阅者类可以注册的事件成员。当声明的事件为public时,称为发布了事件。
  • 事件注册:订阅者必须订阅事件才能在它被触发时得到通知。
  • 触发事件的代码:发布者类中“触发”事件并导致调用注册的所有事件处理程序的代码。
    使用事件时的5个源代码组件
static class Program
    {
        static void Main()
        {
            Incrementer incrementer = new Incrementer();
            Dozens dozensCounter = new Dozens(incrementer);
            incrementer.DoCount();
            Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
            Console.ReadKey();
        }
//发布者类
        class Incrementer
        {
            public delegate void Handler();//委托类型声明
            public event Handler CountADozen;//事件声明

            public void DoCount()
            {
                for (int i = 1; i < 100; i++)
                {
                    if (i % 12 == 0 && CountADozen != null)
                    {
                        CountADozen();//触发事件代码
                    }
                }
            }
        }
//订阅者类
        class Dozens
        {
            public int DozensCount { get; private set; }

            public Dozens(Incrementer incrementer)
            {
                DozensCount = 0;
                incrementer.CountADozen += IncrementerDozensCount;//事件注册
            }

            void IncrementerDozensCount()//事件处理程序声明
            {
                DozensCount++;
            }
        }
    }

14.6 标准事件的用法

程序事件的异步处理是使用C#事件的绝佳场景。WindowsGUI编程广泛地使用了事件,.NET框架提供了一个标准模式。事件使用的标准模式的根本是System命名空间声明的EventHandler委托类型。
public delegate void EventHandler(object sender, EventArgs e);

  • 第一个参数用来保存触发事件的对象的引用。由于是object类型,可以匹配任何类型的实例。
  • 第二个参数用来保存状态信息,指明什么类型适用于该应用程序;
  • 返回类型是 void
  • EventArgs设计为不能传递任何数据。它用于不需要传递数据的事件处理程序——通常会被忽略。
  • 如果要传递数据,必须声明一个派生自EventArgs的类,使用合适的字段来保存需要传递的数据。

修改上述程序使之使用标准EventHandler委托:

static class Program
    {
        static void Main()
        {
            Incrementer incrementer = new Incrementer();
            Dozens dozensCounter = new Dozens(incrementer);
            incrementer.DoCount();
            Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
            Console.ReadKey();
        }

        class Incrementer
        {
            public event EventHandler CountADozen;//使用系统定义的EventHandler委托

            public void DoCount()
            {
                for (int i = 1; i < 100; i++)
                {
                    if (i % 12 == 0 && CountADozen != null)
                    {
                        CountADozen(this, null);//触发事件时使用EventHandler的参数
                    }
                }
            }
        }

        class Dozens
        {
            public int DozensCount { get; private set; }

            public Dozens(Incrementer incrementer)
            {
                DozensCount = 0;
                incrementer.CountADozen += IncrementerDozensCount;
            }

            void IncrementerDozensCount(object sender, EventArgs e)//事件处理程序的签名必须与委托的签名匹配
            {
                DozensCount++;
            }
        }
    }
14.6.1 通过扩展EventArgs来传递参数

要向事件处理程序的第二个参数传入数据,需要声明一个派生自EventArgs的自定义类,可以保存要传的数据。

static class Program
    {
        static void Main()
        {
            Incrementer incrementer = new Incrementer();
            Dozens dozensCounter = new Dozens(incrementer);

            incrementer.DoCount();
            Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
            Console.ReadKey();
        }

        public class IncrementerEventArgs : EventArgs//自定义类派生自EventArgs
        {
            public int IterationCount { get; set; }//存储一个整数
        }

        class Incrementer
        {
            public event EventHandler<IncrementerEventArgs> CountADozen;//使用、自定义类的泛型委托

            public void DoCount()
            {
                IncrementerEventArgs args = new IncrementerEventArgs();//自定义类对象
                for (int i = 1; i < 100; i++)
                {
                    if (i % 12 == 0 && CountADozen != null)
                    {
                        CountADozen(this, args);//触发事件时传递参数
                    }
                }
            }
        }

        class Dozens
        {
            public int DozensCount { get; private set; }

            public Dozens(Incrementer incrementer)
            {
                DozensCount = 0;
                incrementer.CountADozen += IncrementerDozensCount;
            }

            void IncrementerDozensCount(object sender, IncrementerEventArgs e)//事件处理程序的签名必须与委托的签名匹配
            {
                Console.WriteLine("Incremented at iteration: {0} in {1}", e.IterationCount, sender.ToString());

                DozensCount++;
            }
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • #1. 委托1.1 声明委托1.2 使用委托1.3 简单委托示例1.4 Action<T>和Func<T>委托1....
    MrDecoder阅读 3,911评论 0 2
  • 一、理解事件事件采用发布/订阅模型,其中发行者决定在什么情况下引发事件,而订户决定为响应事件而执行的操作。事件可以...
    CarlDonitz阅读 2,444评论 0 0
  • 网上讲C#委托和事件的博文已经非常多了,其中也不乏一些深入浅出、条理清晰的文章。我之所以还是继续写,主要是借机整理...
    丑小丫大笨蛋阅读 4,813评论 0 5
  • 定义:委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。 在实例化委托时,你可以将其实例与任何具有...
    52718阅读 12,244评论 3 14
  • 事件 事件含义 事件由对象引发,通过我们提供的代码来处理。一个事件我们必须订阅(Subscribe)他们,订阅一个...
    天堂迈舞阅读 8,199评论 1 7

友情链接更多精彩内容