C#基础---事件的使用
一:什么是事件
事件是可以被控件识别的操作,如按下确定按钮,选择某个单选按钮或者复选框。每一种控件有自己可以识别的事件,如窗体的加载、单击、双击等事件,编辑框(文本框)的文本改变事件,等等。事件在桌面应用程序里面无处可见,比如winform,WPF。。。,其次事件是基于委托而产生的。
二:事件的基本使用
1.事件的声明: 其实和委托一样只是多了一个Event而已。ShowMsg 就具备了ShowMsgHandler的功能。
Notes: 1. 委托可以依赖于一个类或者一个域名空间(C#基础---委托的使用,里面我有提到过), 而event必须依赖于一个类。否者无法声明。
2. 委托可以用【=号】,而事件中只能用【+】或者【-】实现对方法的添加和删除。当事件为空的时候调用【-】方法不会报错。
public delegate void ShowMsgHandler(string str);
public event ShowMsgHandler ShowMsg;
2.事件基本使用: 其实基本用法和委托差不多。这里有一点要说明,其实可以通过判断是否为Null,来确定是否已经注册了方法到事件或者委托。这个有时候勇于判断事件是否该触发。其次也发现事件第一次添加方法的时候是直接使用【+】号的,而不用像委托那样第一次使用【=】号,后面的才使用【+】号。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace SpongeBobCoder.EventTest
{
public delegate void ShowMsgHandler(string str);
public class Program
{
public static event ShowMsgHandler ShowMsg; public static void ShowName(string str)
{
Console.WriteLine("My Name is {0}", str);
} public static void Main(string[] args)
{
Console.WriteLine(ShowMsg == null);
ShowMsg += ShowName;
ShowMsg("SopongeBob");
Console.WriteLine(ShowMsg == null);
Console.ReadKey();
}
}
}
3. 为何使用事件:
其实从上面来看事件和委托差不多。用法没啥区别,但是为何还要使用委托呢? 在Codeplex看到的一篇文档感觉挺不错的。http://www.codeproject.com/Articles/7316/Events-and-Delegates ;小弟英语不好,英语好的就去看看原文,我的大概理解是: 好比一个App由一个项目组在开发,必定有一个项目经理,而这个项目经理的下面会有很多帮他做事的员工,其实经理就好比是一个委托,而每一位工作的员工就好比委托注册的方法。项目开发完成了,拿给了用户,用户安装好了。可是用户发现软件有缺陷,需要改进,而往往这个时候用户是不会直接跟开发组的项目经理接触的。往往会把意见给 维护部门,而由维护部门来告知相应开发组的项目经理。而通知这段过程就叫做事件。事件可以用来更好的封装,和管理委托的。个人理解,这就是事件为何基于特定类的。不同类的 事件可以绑定同一个委托,从而注册不同的方法。
3.1 先什么一个Publisher类:类中有一个事件CalculatorEvent 和一个方法DoSomething,若事件被添加方法后,那么将执行
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace SpongeBobCoder.EventTest
{
public class Publisher
{
public event CalculatorHandler CalculatorEvent; public void DoSomething(double num1,double num2)
{
if (CalculatorEvent != null)
{
CalculatorEvent(num1, num2);
}
}
}
}
3.2 然后看Program类,Main方法里面声明了两个Publisher对象,分别是A,B。分别添加了AddNum和SumNum,运行结果是 3 和 -1。通过一个Publisher类可以对委托进行管理。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace SpongeBobCoder.EventTest
{
public delegate void CalculatorHandler(double num1,double num2); public class Program
{
public static void AddNum(double num1, double num2)
{
Console.WriteLine("两数之和为:{0}", num1 + num2);
} public static void SubNum(double num1, double num2)
{
Console.WriteLine("两数之差为:{0}", num1-num2);
} public static void Main(string[] args)
{
Publisher pubA = new Publisher();
Publisher pubB = new Publisher();
pubA.CalculatorEvent += AddNum;
pubB.CalculatorEvent += SubNum; pubA.DoSomething(, );
pubB.DoSomething(, ); Console.ReadKey();
}
}
}
三:事件的使用
1.异常处理: 事件可以注册多个方法,可是要是其中有一个方法抛出异常了怎么办,一旦抛出异常了。那么当前执行程序被中断,那么后面注册的方法就没法执行了。问题来了,那些方法可以解决这个问题呢? 方法一,保证所注册的方法不会出现异常,这一块我们是无法预知。 方法二。将注册的方法的异常都吃掉,其中微软提供了两个方法GetInvocationList和DynamicInvoke方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace SpongeBobCoder.EventTest
{
public class Publisher
{
public event CalculatorHandler CalculatorEvent; public void DoSomething(double num1, double num2)
{
if (CalculatorEvent != null)
{
Delegate[] delArray = CalculatorEvent.GetInvocationList(); //获取到所有的委托方法.
foreach (Delegate del in delArray)
{
try
{
object obj = del.DynamicInvoke(num1, num2); //obj是获取每个方法的返回值,如果声明的是无返回值的委托,那么obj==null
Console.WriteLine(obj == null);
}
catch (Exception e) // 把异常吃掉
{
Console.WriteLine(e.InnerException.Message);
}
}
}
}
}
}
2.异步调用:对于前面的注册的时间,都是顺序执行,那如何实现异步执行呢,各个注册之间不相互干扰,其实微软提供了一个BeginInvoke方法可以解决这个问题.
Public IAsyncResult BeginInvoke (
InvokeArgs invokeArgs, // 这一部分对于的是委托
AsyncCallback callback,// 回调方法,注册方法执行完后,将会执行回调方法
Object userState // 传递的参数
)
上面理解起来可能有点困难下面来看看代码吧:
Program类: AddNum 方法有5秒的延时。SubNum没有添加延时,注册顺序是 AddNum,SubNum
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading; namespace SpongeBobCoder.EventTest
{
public delegate double CalculatorHandler(double num1, double num2); public class Program
{
public static double AddNum(double num1, double num2)
{
Thread.Sleep(TimeSpan.FromSeconds());
Console.WriteLine("两数之和为:{0}", num1 + num2);
return num1 + num2;
} public static double SubNum(double num1, double num2)
{
Console.WriteLine("两数之差为:{0}", num1 - num2);
return num1 - num2;
} public static void Main(string[] args)
{
Publisher pubA = new Publisher();
pubA.CalculatorEvent += AddNum;
pubA.CalculatorEvent += SubNum;
pubA.DoSomething(, );
Console.ReadKey();
}
}
}
publisher类: 注意看红色方法,前面两个参数是与委托对应的。后面的MyCallBack是回调的方法,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks; namespace SpongeBobCoder.EventTest
{
public class Publisher
{
public event CalculatorHandler CalculatorEvent; public void DoSomething(double num1, double num2)
{
if (CalculatorEvent != null)
{
Delegate[] delArray = CalculatorEvent.GetInvocationList(); //获取到所有的委托方法.
foreach (Delegate del in delArray)
{
try
{
CalculatorHandler handler = del as CalculatorHandler;
IAsyncResult myResult = handler.BeginInvoke(num1, num2, MyCallback, "方法执行完毕,回调成功" + handler.Method.Name);
// Console.WriteLine("SpongeBob"); 这块代码不注释的话是先执行这段代码的输出,然后才会输出其他的。这一块我不知道为什么
}
catch (Exception e) // 把异常吃掉
{
Console.WriteLine(e.InnerException.Message);
}
}
}
} public void MyCallback(IAsyncResult asyncResult)
{
AsyncResult result = (AsyncResult)asyncResult;
CalculatorHandler handler = (CalculatorHandler)result.AsyncDelegate;
Console.WriteLine(asyncResult.AsyncState);
Console.WriteLine("获取到执行结果为:{0} \n", handler.EndInvoke(asyncResult));
}
}
}
运行结果: 其实先执行的是 SubNum,已经达到了异步的效果,其中通过EndInvoke也在回调函数中获取到了委托的返回值。
codezip:http://files.cnblogs.com/FourLeafCloverZc/CSharp.zip
总结: 以前最开始的对事件理解不清楚,记得当时在winform的时候跨线程获取数据就要用Invoke来获取,不然老是提示线程不安全。本次博客中我发现了两个问题需要个各位博友帮忙解答
1. 在异步调用的代码中有一段代码被我注解了。其实我发现了一个问题, 如果 Console.WriteLine("SpongeBob"); 不注解,运行的情况是,先输出两行(“SpongeBob”) 然后再输出 上图的运行结果。不清楚是什么原因,求大神指点。
2. 对于下面代码如果调用的传入的参数是1,0 ; 是不会报错的。运行结果是两数相除无穷大。应该会报除数不能为0的异常呀。
public static void DivNum(double num1, double num2)
{
Console.WriteLine("两数相除为:{0}", num1 / num2);
}
C#基础---事件的使用的更多相关文章
- 【深入浅出Linux网络编程】 “基础 -- 事件触发机制”
回顾一下“"开篇 -- 知其然,知其所以然"”中的两段代码,第一段虽然只使用1个线程但却也只能处理一个socket,第二段虽然能处理成百上千个socket但却需要创建同等数量的线程 ...
- 第一百六十九节,jQuery,基础事件
jQuery,基础事件 学习要点: 1.绑定事件 2.简写事件 3.复合事件 JavaScript 有一个非常重要的功能,就是事件驱动.当页面完全加载后,用户通过鼠标 或键盘触发页面中绑定事件的元素即 ...
- 9、网页制作Dreamweaver(jQuery基础:事件)
事件 定义 即当HTML中发生某些事(点击.鼠标移过等)的时候调用的方法 $(selector).action() 触发 事件的触发有两种方法: 1.直接将事件click写在<javascrip ...
- JS基础——事件绑定
上一篇博客JS事件对象中,老师问JS事件处理和VB中的事件处理有什么联系?先来解决一下这个问题.举个VB.net中事件处理的样例(JS敲久了,VB习惯的都不熟悉了,看来得常常回想了): 1.事件处理V ...
- javascript基础-事件1
原理 事件分两种.第一种浏览器事件,由浏览器抛出事件,它是人机交互的基础:第二种自定义事件,由程序员抛出事件,它是模拟事件流程.两者都是为了完成数据的传递. 浏览器事件 机制 冒泡和捕获两种机制.因I ...
- javascript基础-事件2
DOM0,DOM2,DOM3事件类型 图解: 范畴 响应顺序(标:标准浏览器.IE9+) 注意点 MouseEvent 标: mousedown-mouseup-click-mousedown-mou ...
- jQuery事件篇---基础事件
写在前面: 有一段时间未更新博客了,利用这段时间,重新看了<jQuery基础教程 第四版>和<锋利的jQuery 第二版>,这两本书绝对是jQuery入门非常好的书,值得多读几 ...
- C#基础-事件 继承类无法直接引发基类的事件
An event can be raised only from the declaration space in which it is declared. Therefore, a class c ...
- jquery基础事件
一.常用的事件有:click.dblclick. mousedown.mouseup.mousemove.mouseover.mouseout.change.select.submit.keydown ...
随机推荐
- 开发apple pay碰到的问题总结
本来想简单总结一下Apple Pay 开发过程中的几个问题, 结果被下面这篇文章全碰上了, 干脆全文转载, 作者对相关资源整理得比较详细, 比较有参考价值 总的来说, 我们做过 APNs 推送的话, ...
- ALV中处理过滤掉的行
有时候我们在ALV的时候,客户会对输出的数据进行二次筛选,这时候如果我们做全选(checkbox)系统会把我们过滤掉得数据也选择: 用下面的method就可避免此问题: DATA:it_rows TY ...
- Oracle12C相关
1.jar包安装到MVN本地库 mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.1 ...
- Day Tips:Remote 服务器黑屏
如果是台式机:CTRL+ALT+End 笔记本一般情况下End建和其他的键混合使用,所以是Fn+CTRL+ALT+End
- Excel里生成GUID
Private Declare Function CoCreateGuid Lib "ole32" (id As Any) As Long Private Function ...
- iOS 三方库fmdb 的使用
使用fmdb 做本地数据的存储非常方便, 1. github 上搜索fmdb 下载压缩包 导入到工程中 (如果你的mac 有cocoapod 也可以直接通过cocoapod 添加) 2. 以下代码是通 ...
- UINavigationController和UIScrollView一起使用时导致UIScrollView位置偏移
iOS7之后,当UIViewController成为UINavigationController的控制视图,UIViewController的控制视图上的第一个子视图是UIScrollView,UIS ...
- Android中的Interpolator
Android中的Interpolator Interpolator用于动画中的时间插值,其作用就是把0到1的浮点值变化映射到另一个浮点值变化. 本文列出Android API提供的Interpola ...
- Android之滑屏动画和自定义控件
滑屏动画 在Android系统中,通过手势识别切换界面时,通常会在界面切换时加入动画,以提高用户的体验效果,这种动画一般都采用平移动画,下一个界面进入时,上一个界面移除屏幕. 图中标识的均为左上角坐标 ...
- XCode模拟器上下黑边、显示不完整、适配问题
其实出现上下黑边是因为iOS默认将启动时的LaunchImage的宽高当成程序的宽高,所以启动图片如果只有小屏的图片,那么就会出现大屏状态下屏幕不能满屏的错误. 解决方法: 添加所有尺寸屏幕的Laun ...