C#语法——事件,逐渐边缘化的大哥。
事件是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#语法——消息,MVVM的核心技术。
在C#中消息有两个指向,一个指向Message,一个指向INotify.这里主要讲INotify. INotify也有人称之为[通知],不管叫消息还是通知,都是一个意思,就是传递信息. 消息的定义 I ...
- jQuery_第五章_事件和动画
Jquery中的事件与动画 一.window.onload和$(document).read()的细微差别 (1)执行时机 window.onload:所有元素(包括元素的所有关联文件)完全加载到浏览 ...
- XAML实例教程系列 - 事件(Event) 五
Kevin Fan分享开发经验,记录开发点滴 XAML实例教程系列 - 事件(Event) 2012-06-19 01:36 by jv9, 1727 阅读, 7 评论, 收藏, 编辑 Events, ...
- vue的事件绑定
vue事件有两方面内容:DOM事件 和 自定义事件. DOM事件 vue中采用DOM2级事件的处理方式,为IE9以上的浏览器服务.下面我们先来讲解一下什么是DOM2级事件吧! JS中DOM0级事件有两 ...
- PB数据管道
数据管道提供了一种不同数据库之间传递数据和(或)表结构的方法. 数据管道对象 要完毕数据管道的功能须要提供例如以下内容: 须要数据源和目标数据库,并可以和这两个数据库正常联接 须要源数据库中的哪些表: ...
- vue2.0父子组件之间通信
父组件是通过props属性给子组件通信的来看下代码: 父组件: <parent> <child :child-com="content"></chil ...
- vue2.0组件通信小总结
1.父组件->子组件 父组件 <parent> <child :child-msg="msg"></child>//这里必须要用 - 代替 ...
- Vue针对性笔记
Github原文阅读 MVVM(Model-View-ViewModel)模型 MVVM分为Model.View.ViewModel三部分. Model代表数据模型,定义数据和业务逻辑,访问数据层 V ...
随机推荐
- 【功耗测试环境预置自动化脚本开发】【切换wifi模式为siso模式】【用到方法*args】
import os,reimport logginglogging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[ ...
- 【爆料】-《伯明翰大学学院毕业证书》UCB一模一样原件
☞伯明翰大学学院毕业证书[微/Q:865121257◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归 ...
- python脚本对 mysql数据库进行增删改查操作
# -*- coding: utf-8 -*-import pymysqlimport xlrd# import codecsconn = pymysql.connect(host='127.0.0. ...
- C++ set用法以及迭代器用法
有关set的一些常用函数 1.begin() / end() 返回首/尾元素迭代器 2.rbegin() / rend() 返回尾/首元素反向迭代器,反向迭代器可以反向遍历容器的迭代器,从下面的程序已 ...
- 基于SpringBoot从零构建博客网站 - 技术选型和整合开发环境
技术选型和整合开发环境 1.技术选型 博客网站是基于SpringBoot整合其它模块而开发的,那么每个模块选择的技术如下: SpringBoot版本选择目前较新的2.1.1.RELEASE版本 持久化 ...
- 基于Raft深度优化,腾讯云金融级消息队列CMQ高可靠算法详解
背景介绍 分布式系统是指一组独立的计算机,通过网络协同工作的系统,客户端看来就如同单台机器在工作.随着互联网时代数据规模的爆发式增长,传统的单机系统在性能和可用性上已经无法胜任,分布式系统具有扩展性强 ...
- @GeneratedValue源码解析
JPA要求每一个实体必须有且只有一个主键,而@GeneratedValue提供了主键的生成策略,这就是@GeneratedValue注解存在的意义.本文将浅析@GeneratedValue的源码. @ ...
- myeclipse附加源码进行查看的方法
在编程过程中,有可能需要用到看源码的情况,那么怎么进行添加源码呢,这里做下记录 首先,先下载javaEE源码(可在网上自由下载) 1.在HttpServlet上右键-->Open Declara ...
- 我学Java我傲娇
今天,终于把学习了一年多的<Java核心技术36讲>第一遍完结了,历时一年多,花出去的钱终于感觉有了第一笔回报. 这是我在极客时间的第一门付费课程,刚出来的时候,正巧自己转到全职Java开 ...
- easyui表格自动换行
表格内容自动换行可以通过设计表格属性 nowrap:false来实现,默认值为true: 但是easyui并未提供,表头自动换行的解决方案,因为一般我们的数据表格列名都是固定的,想换行的话可以通过& ...