基础_C# 事件
来源:互联网 发布:英语家教 知乎 编辑:程序博客网 时间:2024/06/06 00:53
C# 事件
event 关键字用于指定事件。类和结构使用事件将出现的可能影响对象状态的事件通知给对象。
向类中添加事件需要使用 event 关键字,并提供委托类型和事件名称。
在下面的示例中,类 TestButton
包含事件 OnClick。派生自 TestButton
的类可以选择响应 OnClick 事件,并且定义了处理事件要调用的方法。可以以委托和匿名方法的形式指定多个处理程序。
public delegate void ButtonEventHandler();
class TestButton
{
// OnClick is an event, implemented by a delegate ButtonEventHandler.
public event ButtonEventHandler OnClick;
// A method that triggers the event:
public void Click()
{
OnClick();
}
}
TestButton mb = new TestButton();
// Specify the method that will be triggered by the OnClick event.
mb.OnClick += new ButtonEventHandler(TestHandler);
// Specify an additional anonymous method.
mb.OnClick += delegate { System.Console.WriteLine("Hello, World!"); };
// Trigger the event
mb.Click();
事件概述
事件具有以下特点:
事件是类用来通知对象需要执行某种操作的方式。
尽管事件在其他时候(如信号状态更改)也很有用,事件通常还是用在图形用户界面中。
事件通常使用委托事件处理程序进行声明。
事件可以调用匿名方法来替代委托。有关更多信息,请参见匿名方法
引发事件
若要引发事件,类可以调用委托,并传递所有与事件有关的参数。然后,委托调用已添加到该事件的所有处理程序。如果该事件没有任何处理程序,则该事件为空。因此在引发事件之前,事件源应确保该事件不为空以避免 NullReferenceException
。若要避免争用条件(最后一个处理程序会在空检查和事件调用之间被移除),在执行空检查和引发事件之前,事件源还应创建事件的一个副本。例如:
private void RaiseTestEvent(){ // Safely invoke an event: TestEventDelegate temp = TestEvent; if (temp != null) { temp(this, new System.EventArgs()); }}
订阅事件
要接收某个事件的类可以创建一个方法来接收该事件,然后向类事件自身添加该方法的一个委托。这个过程称为“订阅事件”。
首先,接收类必须具有与事件自身具有相同签名(如委托签名)的方法。然后,该方法(称为事件处理程序)可以采取适当的操作来响应该事件。例如
public class EventReceiver{ public void ReceiveTestEvent(object sender, System.EventArgs e) { System.Console.Write("Event received from "); System.Console.WriteLine(sender.ToString()); }}
每个事件可有多个处理程序。多个处理程序由源按顺序调用。如果一个处理程序引发异常,还未调用的处理程序则没有机会接收事件。由于这个原因,建议事件处理程序迅速处理事件并避免引发异常。
若要订阅事件,接收器必须创建一个与事件具有相同类型的委托,并使用事件处理程序作为委托目标。然后,接收器必须使用加法赋值运算符 (+=) 将该委托添加到源对象的事件中。例如:
public void Subscribe(EventSource source){ TestEventDelegate temp = new TestEventDelegate(ReceiveTestEvent); source.TestEvent += temp;}
若要取消订阅事件,接收器可以使用减法赋值运算符 (-=) 从源对象的事件中移除事件处理程序的委托。例如:
public void UnSubscribe(EventSource source){ TestEventDelegate temp = new TestEventDelegate(ReceiveTestEvent); source.TestEvent -= temp;}
声明事件访问器
使用 add 关键字和代码块添加事件的事件处理程序,使用 remove 关键字和代码块移除事件的事件处理程序。
public class EventSource2{ private TestEventDelegate TestEventHandlers; public event TestEventDelegate TestEvent { add { lock (TestEventHandlers) { TestEventHandlers += value; } } remove { lock (TestEventHandlers) { TestEventHandlers -= value; } } } private void RaiseTestEvent() { // Safely invoke an event. TestEventDelegate temp = TestEventHandlers; if (temp != null) { temp(this, new System.EventArgs()); } }}
前面示例中的 lock 语句用于防止多个线程同时操作事件列表。请参见 lock 语句和线程处理。
创建响应事件的控件
案例:某字处理器可能包含打开的文档的列表。每当该列表更改时,可能需要通知字处理器中的许多不同对象,以便能够更新用户界面。使用事件,维护文档列表的代码不需要知道需要通知谁,一旦文档列表发生了更改,将自动调用该事件,正确通知每个需要通知的对象。使用事件提高了程序的模块化程度。
ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_csref/html/2d20556a-0aad-46fc-845e-f85d86ea617a.htm
示例:
namespace TestCollections{ // A delegate type for hooking up change notifications. public delegate void ChangedEventHandler(object sender, System.EventArgs e); // A class that works just like ArrayList, but sends event // notifications whenever the list changes. public class ListWithChangedEvent : System.Collections.ArrayList { // An event that clients can use to be notified whenever the // elements of the list change. public event ChangedEventHandler Changed; // Invoke the Changed event; called whenever list changes protected virtual void OnChanged(System.EventArgs e) { if (Changed != null) { Changed(this, e); } } // Override some of the methods that can change the list; // invoke event after each public override int Add(object value) { int i = base.Add(value); OnChanged(System.EventArgs.Empty); return i; } public override void Clear() { base.Clear(); OnChanged(System.EventArgs.Empty); } public override object this[int index] { set { base[index] = value; OnChanged(System.EventArgs.Empty); } } }}namespace TestEvents{ using TestCollections; class EventListener { private ListWithChangedEvent m_list; public EventListener(ListWithChangedEvent list) { m_list = list; // Add "ListChanged" to the Changed event on m_list: m_list.Changed += new ChangedEventHandler(ListChanged); } // This will be called whenever the list changes. private void ListChanged(object sender, System.EventArgs e) { System.Console.WriteLine("This is called when the event fires."); } public void Detach() { // Detach the event and delete the list m_list.Changed -= new ChangedEventHandler(ListChanged); m_list = null; } } class Test { // Test the ListWithChangedEvent class. static void Main() { // Create a new list. ListWithChangedEvent list = new ListWithChangedEvent(); // Create a class that listens to the list's change event. EventListener listener = new EventListener(list); // Add and remove items from the list. list.Add("item 1"); list.Clear(); listener.Detach(); } }}
.NET Framework 指南指示用于事件的委托类型应采用两个参数:“对象源”参数(用于指示事件源)和特定于事件的参数(它封装有关事件的其他任何信息)。特定于事件的参数应从 EventArgs 类派生。对于不使用任何附加信息的事件,.NET Framework 提供了 EventHandler 类
如上面例子中修改成 .Net Framework 规则
namespace TestCollections{ // A class that works just like ArrayList, but sends event // notifications whenever the list changes: public class ListWithChangedEvent : System.Collections.ArrayList { // An event that clients can use to be notified whenever the // elements of the list change: public event System.EventHandler Changed; // Invoke the Changed event; called whenever list changes: protected virtual void OnChanged(System.EventArgs e) { if (Changed != null) { Changed(this, e); } } // Override some of the methods that can change the list; // invoke event after each: public override int Add(object value) { int i = base.Add(value); OnChanged(System.EventArgs.Empty); return i; } public override void Clear() { base.Clear(); OnChanged(System.EventArgs.Empty); } public override object this[int index] { set { base[index] = value; OnChanged(System.EventArgs.Empty); } } }}
在接口中声明一个事件,然后在类中实现该事件
public delegate void TestDelegate(); // delegate declarationpublic interface ITestInterface{ event TestDelegate TestEvent; void FireAway();}public class TestClass : ITestInterface{ public event TestDelegate TestEvent; public void FireAway() { if (TestEvent != null) { TestEvent(); } }}public class MainClass{ static private void F() { System.Console.WriteLine("This is called when the event fires."); } static void Main() { ITestInterface i = new TestClass(); i.TestEvent += new TestDelegate(F); i.FireAway(); }}
实现两个具有同名事件的接口
当要实现两个具有同名事件的接口时,也需要用到事件属性。在这种情况下,必须使用显式实现事件属性。
但是,在显式地实现接口中的事件时,您需要提供添加和移除方法。
- 基础_C# 事件
- C#_C#中的事件
- 基础_C# 数组
- 基础_C# 字符串
- 基础_C# 委托
- 基础_C# 接口
- 基础_C# 泛型
- 基础_C# 迭代器
- 基础_C# 线程处理
- 01_C语言基础
- 基础_C各种表
- 基础_C# 析构函数
- 黑马程序员_C#编程基础
- 黑马程序员_C#编程基础
- 黑马程序员_C#基础回顾
- 黑马程序员_C#基础1
- 黑马程序员_C#基础2
- 黑马程序员_C#基础3
- 1 K&R C C90,C99的改进
- 关于交通灯管理系统设计的思考:
- VS2005下编译wince平台下的sqlite3源码出错启示
- Linux下MeeGo源码下载 — repo+git
- STM32 USART中断小程序
- 基础_C# 事件
- VIM终极实例
- AIX下的cron使用小结
- FOJ有奖月赛-2010年12月
- STRUTS2中的设计模式
- VIM终极实例
- 运行MeeGo SDK 的linux版本
- Tomcat Undefined exploded archive location 项目不能部署
- 最好的开源项目的一些的在VC + +和MFC的