美文网首页
第十四章 事件

第十四章 事件

作者: 向着远方奔跑 | 来源:发表于2019-03-22 18:00 被阅读0次

    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++;
                }
            }
        }
    

    相关文章

      网友评论

          本文标题:第十四章 事件

          本文链接:https://www.haomeiwen.com/subject/nazlvqtx.html