C#学习笔记 事件

28 篇文章 0 订阅

事件为委托提供了一种发布/订阅机制。声明事件的类被称为发行者类,其他类可以订阅发行者类中的事件。当发行者类触发其中的事件时,所有订阅该事件的类都会收到这个变化。在图形界面框架中,这种情况非常常见。

事件发布者

首先需要创建一个事件发布者类。该类包含一个委托,并有一个基于该委托的事件,还应该有一个可以触发事件的函数,以便订阅者可以在其他地方接收到这个事件。事件常常定义为一个包含事件发布者和事件消息传递的委托。

//事件发布者
class NewsPublisher
{
    //定义事件的委托
    public delegate void NewsEventHandler(NewsPublisher sender, NewsEventArgs args);
    //用委托定义的事件
    public event NewsEventHandler NewsEvent;
    //构造函数,初始化一个发布者的名称
    public NewsPublisher(string name)
    {
        Name = name;
    }
    //发布事件的函数
    public void PublishNews(string News)
    {
        //当事件有订阅者的时候
        if (NewsEvent != null)
        {
            NewsEvent(this, new NewsEventArgs(News));
        }
    }
    public string Name { set; get; }
}

事件传递的消息

跟随事件传递的消息类,既可以是一个包含很多信息的复杂类,也可以是一个仅仅包含一个字符串的简单类。在这里简单的定义一个只包含一条字符串信息的类来传递消息。

//定义需要随事件传递的信息
class NewsEventArgs
{
    public NewsEventArgs(string News)
    {
        this.News = News;
    }
    public string News
    {
        get; set;
    }
}

事件订阅者

有了事件发布者和事件消息之后,就可以定义事件订阅者了。订阅者需要有一个和发布者事件匹配的方法,用来接收事件响应。

//订阅事件的类
class NewsReader
{
    //在构造函数中订阅一个事件
    public NewsReader(string name, NewsPublisher publisher)
    {
        Name = name;
        publisher.NewsEvent += HandleNewsEvent;
    }

    public string Name { get; set; }
    //订阅的方法需要和事件类型匹配
    public void HandleNewsEvent(NewsPublisher sender, NewsEventArgs args)
    {
        Console.WriteLine($"{Name} 收到 {sender.Name} 发来的消息:{args.News}");
    }
}

事件的使用

有了事件发布者和事件订阅者,就可以来看看事件是怎么运作的了。

NewsPublisher publisher = new NewsPublisher("新闻发布者");

NewsReader reader1 = new NewsReader("读者1", publisher);
NewsReader reader2 = new NewsReader("读者2", publisher);
NewsReader reader3 = new NewsReader("读者3", publisher);

Console.WriteLine($"{publisher.Name}发布了一则新闻。");
publisher.PublishNews("早间新闻");

Console.WriteLine($"{publisher.Name}发布了一则新闻。");
publisher.PublishNews("晚间新闻");

这段程序的运行结果如下。从结果可以看出,事件其实就是一个多播委托。同样的,事件订阅者收到事件的顺序和它们订阅的顺序不一定相同,所以不要编写依赖于它们之间顺序的代码。

新闻发布者发布了一则新闻。
读者1 收到 新闻发布者 发来的消息:早间新闻
读者2 收到 新闻发布者 发来的消息:早间新闻
读者3 收到 新闻发布者 发来的消息:早间新闻
新闻发布者发布了一则新闻。
读者1 收到 新闻发布者 发来的消息:晚间新闻
读者2 收到 新闻发布者 发来的消息:晚间新闻
读者3 收到 新闻发布者 发来的消息:晚间新闻

预定义的事件

事件非常地常用,因此微软也为我们预定义了一个泛型委托EventHandler。它的形式如下:

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs: EventArgs;

从这个委托的定义可以看出,这里需要的事件消息类需要继承EventArgs。由于这个委托已经定义在System命名空间了,所以不需要再自己手动定义委托了。上面的例子也可以改写一下了。

首先,事件消息类需要继承EventArgs,除此之外不需要做其他的变动。

class NewsEventArgs : EventArgs
{
    public NewsEventArgs(string News)
    {
        this.News = News;
    }
    public string News
    {
        get; set;
    }
}

然后,事件发布者类需要删掉自定义的委托,并把事件类型改为泛型委托EventHandler。

class NewsPublisher
{
    //使用泛型委托EventHandler
    public event EventHandler<NewsEventArgs> NewsEvent;
    //构造函数,初始化一个发布者的名称
    public NewsPublisher(string name)
    {
        Name = name;
    }
    //发布事件的函数
    public void PublishNews(string News)
    {
        //当事件有订阅者的时候
        if (NewsEvent != null)
        {
            NewsEvent(this, new NewsEventArgs(News));
        }
    }
    public string Name { set; get; }
}

事件订阅者里面也要做一些改动,让方法匹配EventHandler的定义。

class NewsReader
{
    //在构造函数中订阅一个事件
    public NewsReader(string name, NewsPublisher publisher)
    {
        Name = name;
        publisher.NewsEvent += HandleNewsEvent;
    }

    public string Name { get; set; }
    //订阅的方法需要和事件类型匹配
    public void HandleNewsEvent(object sender, NewsEventArgs args)
    {
        Console.WriteLine($"{Name} 收到 {((NewsPublisher)sender).Name} 发来的消息:{args.News}");
    }
}

这样,就可以和原来一样的使用事件了。EventHandler非常常用,在Windows图形界面编程里,会经常看到这样的方式。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值