Event

      • 1.发布者和订阅者
      • 2.声明事件
      • 3.订阅事件
      • 4.触发事件
      • 5.标准事件用法
        • 5.1 通过扩展EventArgs来传递数据
        • 5.2 移除事件处理程序
      • 6.事件访问器

1.发布者和订阅者

  • 发布者(publisher) 发布某个事件的类或结构,其他类可以在该事件发生时得到通知
  • 订阅者(subscriber) 注册并在事件发生时得到通知的类或结构。
  • 事件处理程序(event handler) 由订阅者注册到事件的方法,在发布者触发事件后执行。
  • 触发(raise)事件 调用(invoke)或触发(fire)事件的术语,当事件触发时,所有注册到它的方法依次调用。 事件包含了一个私有的委托。
    image

2.声明事件

  • 事件声明在一个类中
  • 事件需要委托类型的名称,任何附加到事件(如注册)的处理程序都必须与委托类型的签名和返回类型匹配
  • 事件声明为public,这样其他类或结构才可以在上面注册
  • 不能使用new表达式创建事件对象
class Incrementer
{
    public event EventHandler publish; 
}

可以使用逗号分隔多个事件声明,

public event EventHandler MyEvent1, MyEvent1, MyEvent1;

还可以使用static关键字让事件变成静态的,

public static event EventHandler MyEvent;

事件是类或结构的成员,所以有以下几条特性:

  • 不能在一段可执行代码中声明事件
  • 必须声明在类或结构中
  • 事件成员隐式自动初始化为null

3.订阅事件

使用+=运算符来为事件增加事件处理程序

Incrementer i = new Incrementer();
Incrementer.EventHandler += i.Method1; //方法引用形式
Incrementer.EventHandler += StaticClass.Method2; //方法引用形式
i.EventHandler += new MyDel(i2.Method3); // 委托形式
Incrementer.EventHandler += () => count++; // Lambda表达式
Incrementer.EventHandler += delegate { count++ }; // 匿名方法

4.触发事件

  • 在触发事件前与null进行比较,查看是否包含事件处理程序
if(EventHandler != null)
{
    Eventhandler(param1, param2);
}

将事件声明和触发事件的代码放在一起就有了发布者类的声明。

delegate void Handler();
class Incrementer
{
    public event Handler CountedADozen;
    public void DoCount()
    {
        for(int i = 1;i < 100;i++)
        {
            if(i % 12 == 0 && CountedADozen != null)
            {
                CountedADozen();
            }
        }
    }
}
class Dozens
{
    public int DozensCount { get; set; }
    public Dozens(Incrementer incrementer)
    {
        DozensCount = 0;
        incrementer.CountedADozen += IncrementDozensCount;
    }
    void IncrementDozensCount()
    {
        DozensCount++;
    }
}
class Program
{
    static void Main()
    {
        Incrementer incrementer = new Incrementer();
        Dozens dozens = new Dozens(incrementer);
        incrementer.DoCount();
        Console.WriteLine($"Number of dozens = {dozens.DozensCount}");
        Console.ReadKey();
    }
}

output

Number of dozens = 8

5.标准事件用法

delegate void EventHandler(object sender, EventArgs e); //使用系统定义的Eventhandler委托
class Incrementer
{
    public event EventHandler CountedADozen;
    public void DoCount()
    {
        for(int i = 1;i < 100;i++)
        {
            if(i % 12 == 0 && CountedADozen != null)
            {
                CountedADozen(this, null); // 触发事件时使用EventHandler的参数
            }
        }
    }
}
class Dozens
{
    public int DozensCount { get; set; }
    public Dozens(Incrementer incrementer)
    {
        DozensCount = 0;
        incrementer.CountedADozen += IncrementDozensCount; // 添加事件处理程序
    }
    void IncrementDozensCount(object source, EventArgs e) // 事件处理程序的签名必须与委托的签名匹配
    {
        DozensCount++;
    }
}
class Program
{
    static void Main()
    {
        Incrementer incrementer = new Incrementer();
        Dozens dozens = new Dozens(incrementer);
        incrementer.DoCount();
        Console.WriteLine($"Number of dozens = {dozens.DozensCount}");
        Console.ReadKey();
    }
}

5.1 通过扩展EventArgs来传递数据

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

public class IncrementerEventArgs : EventArgs
{
    public int IterationCount { get; set; }
}

之后使用泛型委托EventHandler<>,

public event EventHandler<IncrementerEventArgs> CountedADozen;
public class IncrementerEventArgs : EventArgs
{
    public int IterationCount { get; set; }
}
delegate void EventHandler<T>(object sender, T e);
class Incrementer
{
    public event EventHandler<IncrementerEventArgs> CountedADozen;
    public void DoCount()
    {
        IncrementerEventArgs args = new IncrementerEventArgs();
        for (int i = 1;i < 100;i++)
        {
            if(i % 12 == 0 && CountedADozen != null)
            {
                args.IterationCount = i;
                CountedADozen(this, args);
            }
        }
    }
}
class Dozens
{
    public int DozensCount { get; set; }
    public Dozens(Incrementer incrementer)
    {
        DozensCount = 0;
        incrementer.CountedADozen += IncrementDozensCount;
    }
    void IncrementDozensCount(object source, IncrementerEventArgs e)
    {
        Console.WriteLine($"Incremented at iteration: {e.IterationCount} in {source.ToString()}");
        DozensCount++;
    }
}
class Program
{
    static void Main()
    {
        Incrementer incrementer = new Incrementer();
        Dozens dozens = new Dozens(incrementer);
        incrementer.DoCount();
        Console.WriteLine($"Number of dozens = {dozens.DozensCount}");
        Console.ReadKey();
    }
}

output

Incremented at iteration: 12 in Incrementer
Incremented at iteration: 24 in Incrementer
Incremented at iteration: 36 in Incrementer
Incremented at iteration: 48 in Incrementer
Incremented at iteration: 60 in Incrementer
Incremented at iteration: 72 in Incrementer
Incremented at iteration: 84 in Incrementer
Incremented at iteration: 96 in Incrementer
Number of dozens = 8

5.2 移除事件处理程序

class Publisher
{
    public event EventHandler SimpleEvent;
    public void RaiseTheEvent() { SimpleEvent(this, null); }
}
class Subscriber
{
    public void MethodA(object o, EventArgs e) { Console.WriteLine("AAA"); }
    public void MethodB(object o, EventArgs e) { Console.WriteLine("BBB"); }
}
class Program
{
    static void Main()
    {
        Publisher p = new Publisher();
        Subscriber s = new Subscriber();
        p.SimpleEvent += s.MethodA;
        p.SimpleEvent += s.MethodB;
        p.RaiseTheEvent();
        Console.WriteLine("Remove MethodB");
        p.SimpleEvent -= s.MethodB; // 移除事件处理程序
        p.RaiseTheEvent();
        Console.ReadKey();
    }
}

output

AAA
BBB
Remove MethodB
AAA

6.事件访问器

要改变两个运算符+=和-=的操作,可以为事件定义事件访问器。

    public event EventHandler CountedADozen
    {
        add {...}
        remove {...}
    }
class Program
{
    static void Main(string[] args)
    {
        Publishser p = new Publishser();
        p.NumberChanged -= Subscriber1.OnNumberChanged;
        p.NumberChanged += Subscriber2.OnNumberChanged;
        p.NumberChanged += Subscriber3.OnNumberChanged;
        p.DoSomething();
        Console.ReadKey();
    }
}
public delegate string GeneralEventHandler(); // 定义委托
public class Publishser // 定义事件发布者
{
    private GeneralEventHandler numberChanged; // 声明一个委托变量
    public event GeneralEventHandler NumberChanged // 定义事件访问器
    {
        add // 改变 += 运算符
        {
            numberChanged = value;
        }
        remove // 改变 -= 运算符
        {
            numberChanged = value;
        }
    }
    public void DoSomething()
    {
        if (numberChanged != null)
        {
            string rtn = numberChanged();
            Console.WriteLine(rtn);
        }
    }
}
public class Subscriber1 // 定义事件订阅者
{
    public static string OnNumberChanged()
    {
        return "Subscriber1";
    }
}
public class Subscriber2
{
    public static string OnNumberChanged()
    {
        return "Subscriber2";
    }
}
public class Subscriber3
{
    public static string OnNumberChanged()
    {
        return "Subscriber3";
    }
}

output

Subscriber3
posted @ 2019-04-03 15:27  Kyle0418  阅读(269)  评论(0编辑  收藏  举报