事件是C#的基础之一,学好事件对于了解.NET框架大有好处。

事件最常见的比喻就是订阅,即,如果你订阅了我的博客,那么,当我发布新博客的时候,你就会得到通知。

而这个过程就是事件,或者说是事件运行的轨迹。

事件是发散,以我的博客为核心,向所有订阅者发送消息。我们把这种发散称之为[多播]。

最常见的事件用途是窗体编程,在Windows窗体应用程序和WPF应用程序中。

当在窗体中点击按钮,移动鼠标等事件时,相应的后台程序会收到通知,再执行代码。

事件的定义

官方对事件的说明是这样的:类或对象可以通过事件向其他类或对象通知发生的相关事情。

换成正常语言就是,事件可以定义成静态的或普通的,所以事件就可以由声明的对象调用,也可以直接通过类调用静态事件。

事件是C#中的一种类型,除了框架为我们定义好的事件外,我们还可以自定义事件,用event关键字来声明。

下面我们来看最基础的事件定义。

public delegate void TestDelegate(string message);
public event TestDelegate testEvent;

我们首先定义了一个委托,然后利用event关键字,定义一个事件。

整体上看,好像就是在定义一个委托,只是在委托的定义之前,加了个event关键字。

没错,事件的定义就是这样,因为要声明一个事件,需要两个元素:

一,标识提供对事件的响应的方法的委托。

二,一个类,用存储事件的数据。即,事件要定义在类中。

下面我们来为这个事件赋值。

public void Init()
{   
testEvent += new TestDelegate(EventSyntax_testEvent);
testEvent += EventSyntax_testEvent;
}
private void EventSyntax_testEvent(string message)
{
Console.WriteLine(message);
}

如代码所示,我们使用了+=这个符号来为事件赋值,赋值的内容是一个委托和一个函数。

其中+=我们将他理解为【添加】。

代码中,我们使用两种赋值模式,但实际上都是为事件testEvent添加一个委。

第二种将函数直接【添加】到事件中,编译时也会把函数转换成委托【添加】到事件中。

系统提供事件

C#的框架都很经典,而每个经典框架都为我们提供了一些经典事件。

由于事件必须[标识响应方法的委托],所以这些事件所使用的委托都有一个共同的特点,命名中包含Event。

比如EventHandler,CancelEventHandler,RoutedEventHandler,ContextMenuEventHandler等。

其中最经典的就是EventHandler和RoutedEventHandler。

EventHandler:

EventHandler定义如下

[SerializableAttribute]
[ComVisibleAttribute(true)]
public delegate void EventHandler(
object sender,
EventArgs e
)

他包含了两个参数,即当我们为事件添加EventHandler委托后,再去触发该事件;被触发的委托将得到object sender和EventArgs e两个参数。

sender:代表源,即触发该事件的控件。

e:代表事件参数,即触发该事件后,事件为被触发的委托,传递了一些参数,以方便委托在处理数据时,更便捷。

根据这个原理,我们可以分析出很多东西。

比如,当控件DataGrid的事件被触发时,只要查看一下sender的真实类型,就可以知道,到底是DataGrid触发的事件,还是DataGridRow或DataGridCell触发的了。

RoutedEventHandler:

RoutedEventHandler即路由事件,他的定义如下

public delegate void RoutedEventHandler(
Object sender,
RoutedEventArgs e
)

RoutedEventHandler也为我们提供了sender和e两个参数。

但RoutedEventHandler特别之处是,他的sender并不一定是真实的源,因为他是一个冒泡路由事件,即上升事件。

这里如果大家有好奇心去看官方文档,那么会在相关的介绍中看到两个单词sender和source。

通过这两个单词,我们会清晰的了解路由事件。简单描述一下sender和source,它们一个是发送者,一个是源。

在EventHandler中,sender即source,因为它是直接事件。而在冒泡事件中,sender不一定等于source。即发送者不一定是源。

下面我们用WPF来看看路由事件。

我们首先在XAML页面定义一个RadioButton按钮,然后设置他的模板是Button。然后分别定义各自的Click方法。

Xaml页面如下:

 <RadioButton Click="btnParent_Click">
<RadioButton.Template>
<ControlTemplate>
<StackPanel>
<TextBlock Text="我的名字" ></TextBlock>
<Button Content="Kiba518" Click="btnClild_Click" ></Button>
</StackPanel>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>

cs文件事件如下:

 private void btnParent_Click(object sender, RoutedEventArgs e)
{
string type = sender.GetType().ToString();//RadioButton
} private void btnClild_Click(object sender, RoutedEventArgs e)
{
string type = sender.GetType().ToString();//Button
}

运行起来,我们点击按钮,通过断点我们可以看到,我们点击的按钮触发了btnClild_Click和btnParent_Click事件。

顺序是先btnClild_Click后btnParent_Click。

通过获取sender的类型,我也可以看到,btnClild_Click的sender类型是Button,而btnParent_Click的sernder类型是RadioButton。

事件驱动编程

事件驱动编程这个概念给我的感觉很怪,因为一直用C#,而C#的很多框架都是事件驱动的,所以一直觉得事件驱动是理所当然。

而当事件驱动设计这个词经常出现后,反而感觉怪怪的。

就好像,天天吃大米饭,突然有一天,所有人都说大米饭好香的感觉一样,你一听就感觉怪怪的。

因为事件驱动对于C#开发而言,实在太普通了。当然,这也得益于微软框架做的实在是太好了。

所以,我也不知道如何在C#里讲事件驱动编程。因为使用C#的框架就是使用事件驱动编程。

事件和委托到底是什么关系?

事件是用来多播的,并且用委托来为事件赋值,可以说,事件是基于委托来实现的。

但委托中也有多播,那为什么要单独弄出来一个事件呢?

首先,存在即合理,事件一定有他存在的意义。

事件存在的意义

我对事件存在的意义是这样理解的。我们在C#编写框架时,几乎不用委托的多播,因为委托的多播和事件存在严重的二义性。虽然编写框架的人学会了使用委托的多播,但使用框架的同事可能并还不太熟练,而且C#框架中,大多是使用事件来进行多播的。

所以委托的多播和事件一起使用的框架,会造成使用这个框架的初级开发者很多困惑,而这种困惑,会产生很多不必要的问题。

比如, 你定义了一个委托,另一个开发者用这个委托做了个多播,当第三个开发者来维护这段代码时,如果他是新手,不了解委托的多播,那就很有可能只修改了委托调用的代码。而没有去同步多播这个委托的代码。那系统就产生了隐藏的bug。

那么,事件和委托到底是什么关系呢?

事件与委托的确存在千丝万缕的关系,怎么讲都是正确的。但,C#开发者只需要记住,他们俩没关系即可。在C#事件是事件,委托是委托。两者就如同int和string一样,没有任何关系。

原因很简单,学习的过程中尽量降低概念混淆。而且,在C#开发中,好的架构者也通常会将事件和委托分离,所以,就认为事件和委托没有关系即可。

结语

其实事件很好理解,一点不复杂。我在写这篇文章的过程中,也没想到什么特别的或者说比较高级的用法。

但真实的应用场景中,我的感觉是,随着MVVM的成长,事件其实在被逐渐抛弃。虽然微软做了很多经典的事件驱动框架。但那都是过去了。

比如WPF虽然支持事件驱动,但MVVM在WPF下的表现堪称完美,所以WPF下的事件几乎没有人用了。

再比如前端的Angularjs等框架,提供了优质的MVVM使用效果,也让新的前端设计师逐渐放弃了事件。

所以,事件在未来的编程中,很可能将不在有那么重要的地位了。但学好事件,对于我们理解微软框架,还是有很大帮助的。

C#语法——元组类型

C#语法——泛型的多种应用

C#语法——await与async的正确打开方式

C#语法——委托,架构的血液

我对C#的认知。

----------------------------------------------------------------------------------------------------

注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!

C#语法——事件,逐渐边缘化的大哥。的更多相关文章

  1. C#语法——反射,架构师的入门基础。

    前言 编程其实就是写代码,而写代码目的就是实现业务,所以,语法和框架也是为了实现业务而存在的.因此,不管多么高大上的目标,实质上都是业务. 所以,我认为不要把写代码上升到科学的高度.上升到艺术就可以了 ...

  2. C#语法——消息,MVVM的核心技术。

    在C#中消息有两个指向,一个指向Message,一个指向INotify.这里主要讲INotify. INotify也有人称之为[通知],不管叫消息还是通知,都是一个意思,就是传递信息. 消息的定义 I ...

  3. jQuery_第五章_事件和动画

    Jquery中的事件与动画 一.window.onload和$(document).read()的细微差别 (1)执行时机 window.onload:所有元素(包括元素的所有关联文件)完全加载到浏览 ...

  4. XAML实例教程系列 - 事件(Event) 五

    Kevin Fan分享开发经验,记录开发点滴 XAML实例教程系列 - 事件(Event) 2012-06-19 01:36 by jv9, 1727 阅读, 7 评论, 收藏, 编辑 Events, ...

  5. vue的事件绑定

    vue事件有两方面内容:DOM事件 和 自定义事件. DOM事件 vue中采用DOM2级事件的处理方式,为IE9以上的浏览器服务.下面我们先来讲解一下什么是DOM2级事件吧! JS中DOM0级事件有两 ...

  6. PB数据管道

    数据管道提供了一种不同数据库之间传递数据和(或)表结构的方法. 数据管道对象 要完毕数据管道的功能须要提供例如以下内容: 须要数据源和目标数据库,并可以和这两个数据库正常联接 须要源数据库中的哪些表: ...

  7. vue2.0父子组件之间通信

    父组件是通过props属性给子组件通信的来看下代码: 父组件: <parent> <child :child-com="content"></chil ...

  8. vue2.0组件通信小总结

    1.父组件->子组件 父组件 <parent> <child :child-msg="msg"></child>//这里必须要用 - 代替 ...

  9. Vue针对性笔记

    Github原文阅读 MVVM(Model-View-ViewModel)模型 MVVM分为Model.View.ViewModel三部分. Model代表数据模型,定义数据和业务逻辑,访问数据层 V ...

随机推荐

  1. 51nod 1135 原根 就是原根...

    %%% dalao Orz ,筛素数到sqrt(n),分解ϕ(p),依次枚举判断就好了 #include<cstdio> #include<cstring> #include& ...

  2. Linux文件系统选择

    通过综合使用多种标准文件系统Benchmarks对Ext3, Ext4, Reiserfs, XFS, JFS, Reiser4的性能测试对比,对不同应用选择合适的文件系统给出以下方案,供大家参考.文 ...

  3. Java 11 新功能来了!

    关键时刻,第一时间送达! 目前 Oracle 已经发布了 Java Development Kit 10,下个版本 JDK 11 也即将发布.本文介绍 Java 11 的新功能. 根据Oracle新出 ...

  4. OSI七层协议与TCP连接

    概述 为了追求效率,我们写代码,不可能去关注底层知识,但往往到出了问题,或者性能调优.我们就会速手无策,仔细为自己查缺补漏,总结知识点. 网络协议 互联网的本质就是一系列的网络协议,让不同计算机能够互 ...

  5. FOFA爬虫大法——API的简单利用

    FOFA是一款网络空间搜索引擎,它通过进行网络空间测绘,帮助研究人员或者企业迅速进行网络资产匹配,例如进行漏洞影响范围分析.应用分布统计.应用流行度等. 何为API?如果你在百度百科上搜索,你会得到如 ...

  6. 【开源】OSharpNS,轻量级.net core快速开发框架发布

    OSharpNS简介 OSharp Framework with .NetStandard2.0(OSharpNS)是OSharp的以.NetStandard2.0为目标框架,在AspNetCore的 ...

  7. mysql报错mmap(137428992 bytes) failed; errno 12,Cannot allocate memory for the buffer pool

    mysql以`systemctl start mysqld.service`的方式启动一段时间后发现突然无法启动,尝试重新启动也不能解决问题,排查问题时,先后通过`systemctl status m ...

  8. 【重学计算机】操作系统D5章:文件系统

    1. 文件系统 文件系统概述 文件的组织: 逻辑结构:流式.记录式 物理结构:顺序.连接.直接.索引 文件的存取:顺序.直接.索引 文件的控制:逻辑控制.物理控制 文件的使用:打开.关闭.读.写.控制 ...

  9. Python爬虫入门教程 62-100 30岁了,想找点文献提高自己,还被反爬了,Python搞起,反爬第2篇

    学术搜索 学习理论的知识少不了去检索文献,好多文献为你的实操提供了合理的支撑,我所在的大学内网默认是有知网账户的,非常NICE 今天要完成的网站是 http://ac.scmor.com/ Googl ...

  10. C#处理json实战

    昨天看到技术群中发了一个查询天气的api,http://www.sojson.com/open/api/weather/json.shtml?city=南昌 点进去看,发现服务器传回来一个天气信息的j ...