c# Events (推荐)
本文讨论了在C#里面events的基础,和如何在自己的应用程序里面利用events。
基于应用的窗口都是基于消息机制的。应用程序通过窗口(Forms)来交流信息(通讯),并且窗口(Forms)通过应用程序预先定义的消息机制来交流信息。.Net用“EVENTS”来封装消息机制,并且.Net通过“handign events”来自动响应内部的消息。"Events"是一个object发送的消息,并指定某个事件来响应这个消息。"Event"也可以定义成一个成员,这样可以使object提供通知功能(博主注:这个就是观察者模式了)。“Events”提供了强有力的内部进程通讯功能。“Events”常用于Objects之间的通讯. Objects之间的通讯通过事件来完成。
在应用程序接收到一个消息时,Delegates(委托)常用于装配event.
Event 接收者
event 接收者可能是:
- 一个应用程序
- 一个对象
- 一个组件
当某些事情发生时,Event 接收者将得到更改.
Event 发送者
Event 发送者可能是:
- 应用程序里面的一个assembly
- 一个对象
- 系统事件,比如:鼠标和键盘事件.
Event 发送者的工作是触发一个Event. Event发送者对event本身一无所知,包括谁是接收者和什么是接收者. To handle the event, there would be some method inside
event receiver. This Event handler method will get executed each time
when event is registered to be raised.
这里DELEGATE 就很有用了,因为evenet的发送者并不知道谁是接收者.
绑定(hooking up)一个 event handler的过程 及时我们熟悉的配置(WIRING UP)一个 Event.
wiring up的简单例子就是CLICK EVENT.
The EventHandler Delegate
Delegate 已经在.Net framework中定义了. 它是定义在 System 命名空间下. 将会用的所有事件,都已经在.Net framework 中定义了。
- EventHandler 不能返回任何值, 换句话说就是返回 Void.
- 参数只能是Object 和 EventArgs
- 第一行参数是出发事件(Event)的对象(Object).
- 第二个参数是 EventArgs. 它包含了这个 Event 的所有信息.
Example:
Private void Button_Click(Object sender, EventArgs e)
{
}
这里,第一个参数是一个Button; 如果form里有很多buttons, 它可以是任何一个button .
第二个参数是 EventArags事件. 包含当前被使用Button的所有属性
Example 1:
using
System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace EventExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Adding EventHandler to Click event of Buttons
btn1.Click +=new EventHandler(Button_Click);
btn2.Click +=new EventHandler(Button_Click);
}
// Button Click Method , here signature of this is same as of Eventhandler
private void Button_Click(Object sender, EventArgs e)
{
string str;
if (sender == btn1)
{
str = btn1.Text;
MessageBox.Show(str+" Clicked ");
}
if (sender == btn2)
{
str = btn2.Text;
MessageBox.Show(str+ " Clicked ");
}
}
}
}
In above code - 在以上代码中
Step 1: 创建一个 Windows Application
Step 2: 两个 butttons 被拖到form上. buttons的名字分别是 btn1 和 btn2 .
Step 3: 在 Form的构造函数里 , Eventhandlers 正在增加 Button . += 操作符被用来增加 EventHandlers.
Step 4: Button_Click 是一个方法, 拥有跟 EventHandler一样的签名(signature ),其实就是跟EventHandler一样的参数(参数个数和类型一致,这个也叫签名)。.
输出:
When button Scott is clicked, in message Box Scott is displaying. In this case Button_Click method is called by btn1_click delegate. In Button_Click() method , checking has been done for which Button object is calling the event. Or in other words which button is event sender. Code snippet which is checking the sender is
if
(sender == btn1){
str = btn1.Text;
MessageBox.Show(str+" Clicked ");
}
if (sender == btn2)
{
str = btn2.Text;
MessageBox.Show(str+ " Clicked ");
}
事件的发布和订阅
- 在设计模式里面, 控件(Control )的创建者(比如 Button, List 等) "PUBLISHES(发布)" the events(事件) to 到某个响应的button (比如 click).
- Programmer who uses the Button (those who put Button on their Form) may choose to "SUBSCRIBE" to one or more of the Button's event 我们用一个Button来订阅(SUBSCRIBE) ”Button“事件的一个或者几个. For example As a programmer any one could choose to subscribe ( or Notify) click event of Button but not Mouse Hover over the Button
- Mechanism of publishing is "Creating a Delegate".
- Mechanism of subscribing is to create a "method "with same signature as of delegate.
- The Subscribing method is called the "Event Handler"
- In .Net Framework all event handlers return void and take two parameters. The first parameter is "Source" of the event. The Second parameter is object derived from "EventArgs".
- EventArgs is the base class for all event data. Other than its constructor, this class inherits all method from Object class. It contains a public static field named "Empty". This represents an Event with no state. The EventArgs derived class contains information about the Event.
Publish and Subscribe Example
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace EventExampleTime
{
#region infoOfEvent
public class TimeEvent : EventArgs
{
public readonly int Hour;
public readonly int Minute;
public readonly int Second;
public TimeEvent(int hour, int minute, int second)
{
this.Hour = hour;
this.Minute = minute;
this.Second = second;
}
}
#endregion
#region publishClass
public class Clock
{
private int hour;
private int minute;
private int second;
public delegate void SecondChangeHandlerDelegate(object clock, TimeEvent timeInformation);
public SecondChangeHandlerDelegate SecondChanged;
protected virtual void OnSecondChanged(TimeEvent e)
{
if (SecondChanged != null)
{
SecondChanged(this, e);
}
}
public void Run()
{
for (; ; )
{
Thread.Sleep(10);
DateTime dt = DateTime.Now;
if(dt.Second!= second)
{
TimeEvent timeInformation = new TimeEvent(dt.Hour, dt.Minute, dt.Second);
OnSecondChanged(timeInformation);
}
this.second = dt.Second;
this.minute = dt.Minute;
this.hour = dt.Hour;
}
}
}
#endregion
#region observerClass
public class DisplayClock
{
public void Subscribe(Clock theClock)
{
theClock.SecondChanged += new Clock.SecondChangeHandlerDelegate(timeHasChanged);
}
public void timeHasChanged(object theClock, TimeEvent ti)
{
Console.WriteLine("Current Time : {0}:{1}:{2}", ti.Hour.ToString(), ti.Minute.ToString(), ti.Second.ToString());
}
}
#endregion
#region observerClass2
public class LogCurrentTime
{
public void Subscribe(Clock theClock)
{
theClock.SecondChanged += new Clock.SecondChangeHandlerDelegate(writelogentry);
}
public void writelogentry(object theClock, TimeEvent ti)
{
Console.WriteLine(" Logging to File : {0}:{1}:{2}", ti.Hour.ToString(), ti.Minute.ToString(), ti.Second.ToString());
}
}
#endregion
class Program
{
static void Main(string[] args)
{
Clock theClock = new Clock();
DisplayClock dc = new DisplayClock();
dc.Subscribe(theClock);
LogCurrentTime lct = new LogCurrentTime();
lct.Subscribe(theClock);
theClock.Run();
Console.Read();
}
}
}