一:什么是事件

       事件是可以被控件识别的操作,如按下确定按钮,选择某个单选按钮或者复选框。每一种控件有自己可以识别的事件,如窗体的加载、单击、双击等事件,编辑框(文本框)的文本改变事件,等等。事件在桌面应用程序里面无处可见,比如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#基础---事件的使用的更多相关文章

  1. 【深入浅出Linux网络编程】 “基础 -- 事件触发机制”

    回顾一下“"开篇 -- 知其然,知其所以然"”中的两段代码,第一段虽然只使用1个线程但却也只能处理一个socket,第二段虽然能处理成百上千个socket但却需要创建同等数量的线程 ...

  2. 第一百六十九节,jQuery,基础事件

    jQuery,基础事件 学习要点: 1.绑定事件 2.简写事件 3.复合事件 JavaScript 有一个非常重要的功能,就是事件驱动.当页面完全加载后,用户通过鼠标 或键盘触发页面中绑定事件的元素即 ...

  3. 9、网页制作Dreamweaver(jQuery基础:事件)

    事件 定义 即当HTML中发生某些事(点击.鼠标移过等)的时候调用的方法 $(selector).action() 触发 事件的触发有两种方法: 1.直接将事件click写在<javascrip ...

  4. JS基础——事件绑定

    上一篇博客JS事件对象中,老师问JS事件处理和VB中的事件处理有什么联系?先来解决一下这个问题.举个VB.net中事件处理的样例(JS敲久了,VB习惯的都不熟悉了,看来得常常回想了): 1.事件处理V ...

  5. javascript基础-事件1

    原理 事件分两种.第一种浏览器事件,由浏览器抛出事件,它是人机交互的基础:第二种自定义事件,由程序员抛出事件,它是模拟事件流程.两者都是为了完成数据的传递. 浏览器事件 机制 冒泡和捕获两种机制.因I ...

  6. javascript基础-事件2

    DOM0,DOM2,DOM3事件类型 图解: 范畴 响应顺序(标:标准浏览器.IE9+) 注意点 MouseEvent 标: mousedown-mouseup-click-mousedown-mou ...

  7. jQuery事件篇---基础事件

    写在前面: 有一段时间未更新博客了,利用这段时间,重新看了<jQuery基础教程 第四版>和<锋利的jQuery 第二版>,这两本书绝对是jQuery入门非常好的书,值得多读几 ...

  8. C#基础-事件 继承类无法直接引发基类的事件

    An event can be raised only from the declaration space in which it is declared. Therefore, a class c ...

  9. jquery基础事件

    一.常用的事件有:click.dblclick. mousedown.mouseup.mousemove.mouseover.mouseout.change.select.submit.keydown ...

随机推荐

  1. 开发apple pay碰到的问题总结

    本来想简单总结一下Apple Pay 开发过程中的几个问题, 结果被下面这篇文章全碰上了, 干脆全文转载, 作者对相关资源整理得比较详细, 比较有参考价值 总的来说, 我们做过 APNs 推送的话, ...

  2. ALV中处理过滤掉的行

    有时候我们在ALV的时候,客户会对输出的数据进行二次筛选,这时候如果我们做全选(checkbox)系统会把我们过滤掉得数据也选择: 用下面的method就可避免此问题: DATA:it_rows TY ...

  3. Oracle12C相关

    1.jar包安装到MVN本地库 mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.1 ...

  4. Day Tips:Remote 服务器黑屏

    如果是台式机:CTRL+ALT+End 笔记本一般情况下End建和其他的键混合使用,所以是Fn+CTRL+ALT+End

  5. Excel里生成GUID

    Private Declare Function CoCreateGuid Lib "ole32" (id As Any) As Long    Private Function ...

  6. iOS 三方库fmdb 的使用

    使用fmdb 做本地数据的存储非常方便, 1. github 上搜索fmdb 下载压缩包 导入到工程中 (如果你的mac 有cocoapod 也可以直接通过cocoapod 添加) 2. 以下代码是通 ...

  7. UINavigationController和UIScrollView一起使用时导致UIScrollView位置偏移

    iOS7之后,当UIViewController成为UINavigationController的控制视图,UIViewController的控制视图上的第一个子视图是UIScrollView,UIS ...

  8. Android中的Interpolator

    Android中的Interpolator Interpolator用于动画中的时间插值,其作用就是把0到1的浮点值变化映射到另一个浮点值变化. 本文列出Android API提供的Interpola ...

  9. Android之滑屏动画和自定义控件

    滑屏动画 在Android系统中,通过手势识别切换界面时,通常会在界面切换时加入动画,以提高用户的体验效果,这种动画一般都采用平移动画,下一个界面进入时,上一个界面移除屏幕. 图中标识的均为左上角坐标 ...

  10. XCode模拟器上下黑边、显示不完整、适配问题

    其实出现上下黑边是因为iOS默认将启动时的LaunchImage的宽高当成程序的宽高,所以启动图片如果只有小屏的图片,那么就会出现大屏状态下屏幕不能满屏的错误. 解决方法: 添加所有尺寸屏幕的Laun ...