C#基础---事件的使用

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

一:什么是事件

事件是可以被控件识别的操作,如按下确定按钮,选择某个单选按钮或者复选框。每一种控件有自己可以识别的事件,如窗体的加载、单击、双击等事件,编辑框(文本框)的文本改变事件,等等。事件在桌面应用程序里面无处可见,比如winform,WPF。。。,其次事件是基于委托而产生的。

二:事件的基本使用

1.事件的声明: 其实和委托一样只是多了一个Event而已。ShowMsg 就具备了ShowMsgHandler的功能。

Notes:1. 委托可以依赖于一个类或者一个域名空间(C#基础---委托的使用,里面我有提到过), 而event必须依赖于一个类。否者无法声明。

2. 委托可以用【=号】,而事件中只能用【+】或者【-】实现对方法的添加和删除。当事件为空的时候调用【-】方法不会报错。

publicdelegatevoidShowMsgHandler(stringstr);publiceventShowMsgHandler ShowMsg;

2.事件基本使用: 其实基本用法和委托差不多。这里有一点要说明,其实可以通过判断是否为Null,来确定是否已经注册了方法到事件或者委托。这个有时候勇于判断事件是否该触发。其次也发现事件第一次添加方法的时候是直接使用【+】号的,而不用像委托那样第一次使用【=】号,后面的才使用【+】号。

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceSpongeBobCoder.EventTest

{publicdelegatevoidShowMsgHandler(stringstr);publicclassPRogram

{publicstaticeventShowMsgHandler ShowMsg;publicstaticvoidShowName(stringstr)

{

Console.WriteLine("My Name is {0}", str);

}publicstaticvoidMain(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,若事件被添加方法后,那么将执行

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceSpongeBobCoder.EventTest

{publicclassPublisher

{publiceventCalculatorHandler CalculatorEvent;publicvoidDoSomething(doublenum1,doublenum2)

{if(CalculatorEvent !=null)

{

CalculatorEvent(num1, num2);

}

}

}

}

3.2 然后看Program类,Main方法里面声明了两个Publisher对象,分别是A,B。分别添加了AddNum和SumNum,运行结果是 3 和 -1。通过一个Publisher类可以对委托进行管理。

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceSpongeBobCoder.EventTest

{publicdelegatevoidCalculatorHandler(doublenum1,doublenum2);publicclassProgram

{publicstaticvoidAddNum(doublenum1,doublenum2)

{

Console.WriteLine("两数之和为:{0}", num1 +num2);

}publicstaticvoidSubNum(doublenum1,doublenum2)

{

Console.WriteLine("两数之差为:{0}", num1-num2);

}publicstaticvoidMain(string[] args)

{

Publisher pubA=newPublisher();

Publisher pubB=newPublisher();

pubA.CalculatorEvent+=AddNum;

pubB.CalculatorEvent+=SubNum;

pubA.DoSomething(1,2);

pubB.DoSomething(1,2);

Console.ReadKey();

}

}

}

三:事件的使用

1.异常处理:事件可以注册多个方法,可是要是其中有一个方法抛出异常了怎么办,一旦抛出异常了。那么当前执行程序被中断,那么后面注册的方法就没法执行了。问题来了,那些方法可以解决这个问题呢? 方法一,保证所注册的方法不会出现异常,这一块我们是无法预知。 方法二。将注册的方法的异常都吃掉,其中微软提供了两个方法GetInvocationList和DynamicInvoke方法:

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceSpongeBobCoder.EventTest

{publicclassPublisher

{publiceventCalculatorHandler CalculatorEvent;publicvoidDoSomething(doublenum1,doublenum2)

{if(CalculatorEvent !=null)

{

Delegate[] delArray= CalculatorEvent.GetInvocationList();//获取到所有的委托方法.foreach(Delegate delindelArray)

{try{objectobj =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

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Threading;namespaceSpongeBobCoder.EventTest

{publicdelegatedoubleCalculatorHandler(doublenum1,doublenum2);publicclassProgram

{publicstaticdoubleAddNum(doublenum1,doublenum2)

{

Thread.Sleep(TimeSpan.FromSeconds(5));

Console.WriteLine("两数之和为:{0}", num1 +num2);returnnum1 +num2;

}publicstaticdoubleSubNum(doublenum1,doublenum2)

{

Console.WriteLine("两数之差为:{0}", num1 -num2);returnnum1 -num2;

}publicstaticvoidMain(string[] args)

{

Publisher pubA=newPublisher();

pubA.CalculatorEvent+=AddNum;

pubA.CalculatorEvent+=SubNum;

pubA.DoSomething(1,5);

Console.ReadKey();

}

}

}

publisher类: 注意看红色方法,前面两个参数是与委托对应的。后面的MyCallBack是回调的方法,

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Runtime.Remoting.Messaging;usingSystem.Text;usingSystem.Threading.Tasks;namespaceSpongeBobCoder.EventTest

{publicclassPublisher

{publiceventCalculatorHandler CalculatorEvent;publicvoidDoSomething(doublenum1,doublenum2)

{if(CalculatorEvent !=null)

{

Delegate[] delArray= CalculatorEvent.GetInvocationList();//获取到所有的委托方法.foreach(Delegate delindelArray)

{try{

CalculatorHandler handler= delasCalculatorHandler;IAsyncResult myResult= handler.BeginInvoke(num1, num2, MyCallback, "方法执行完毕,回调成功" + handler.Method.Name);//Console.WriteLine("SpongeBob"); 这块代码不注释的话是先执行这段代码的输出,然后才会输出其他的。这一块我不知道为什么}catch(Exception e)//把异常吃掉{

Console.WriteLine(e.InnerException.Message);

}

}

}

}publicvoidMyCallback(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的异常呀。

publicstaticvoidDivNum(doublenum1,doublenum2)

{

Console.WriteLine("两数相除为:{0}", num1 /num2);

}

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航