但是事件并不局限于图像界面,也可能是满足程序的某个逻辑判断触发了事件。引发事件的对象叫做事件发送方,捕获事件并对其做出响应的对象叫做事件接收方。但是事件发送方并不知道哪个对象或者方法会处理它引发的事件,所以需要在事件发送方和事件接收方之间存在一媒介,明确某个对象或者某个类型的某个方法会对这个事件进行响应。.NET用委托作为事件发送方与事件接收方之间的媒介,委托只有一个签名,只要方法签名与委托签名匹配的方法,都可以声明自己对这个委托类型的事件的感兴趣,接收并处理它。 事件发送方的对象为了给事件接收对象传递一些额外信息,就需要写一个派生于System.EventArgs的类,封装一些数据。 复制代码 代码如下: public class DrawEventArgs:EventArgs { privatedouble m_Size; public DrawEventArgs(doublesize) { m_Size = size; } public double Size { get { returnm_Size; } } }
下面声明一委托,该委托有两个参数,一个是参数代表事件的发送方,另一个是参数是该事件封装的数据。 public delegate void ShapeSizeChanged(objectsender,DrawEventArgs e); ShapeSizeChanged的实例可以绑定到任何和它方法签名匹配的方法上。 下面是自定义事件委托, public event ShapeSizeChanged SizeChanged; 下面是一个负责引发事件的类型代码, 复制代码 代码如下:
public class DrawManager { public event ShapeSizeChangedSizeChanged; protectedvoid OnSizeChanged(DrawEventArgse) { ShapeSizeChangedtemp = SizeChanged; //是否有委托与该事件关联 if(temp != null) { temp(this,e); } } public void SizeChange(doublesize) { DrawEventArgse = new DrawEventArgs(size); OnSizeChanged(e); } }
而后定义两个监听事件的类型, 复制代码 代码如下: public class Square { publicSquare(DrawManager drawManager) { //drawManager.SizeChanged+= DrawSquare; //把事件关联到委托上 drawManager.SizeChanged += new ShapeSizeChanged(DrawSquare); } public void DrawSquare(objectsender, DrawEventArgs e) { Console.WriteLine(string.Format("TheSquare'Length = {0}", e.Size)); } public void Detach(DrawManagerdrawManager) { //drawManager.SizeChanged-= DrawSquare; //解除事件和委托的关联 drawManager.SizeChanged -= new ShapeSizeChanged(DrawSquare); } } public class Rectangle { publicRectangle(DrawManager drawManager) { drawManager.SizeChanged +=DrawRectangle; } public void DrawRectangle(objectsender, DrawEventArgs e) { Console.WriteLine(string.Format("TheRectangle'length={0} and width={1}.",e.Size*2,e.Size)); } public void Detach(DrawManagerdrawManager) { drawManager.SizeChanged -=DrawRectangle; } }
测试代码, 复制代码 代码如下: class Program { static void Main(string[]args) { DrawManagerdrawManager = new DrawManager(); Rectanglerect = new Rectangle(drawManager); Squaresquare = new Square(drawManager); //引发事件 drawManager.SizeChange(5);
//解除监听事件 square.Detach(drawManager); drawManager.SizeChange(10); Console.ReadLine(); } } /*运行结果 The Rectangle'length=10 and width=5. The Square'Length = 5 The Rectangle'length=20 and width=10. */
.NET中的事件模式和观察者模式非常相似,也可谓是观察者模式在.NET下的进化版吧,下面用观察者模式实现上面功能以做对比,首先定义两个接口,IObserver和IObservable,如下 复制代码 代码如下: public interface IObserver { voidNotify(DrawEventArgs e); } public interface IObservable { voidRegister(IObserver observer); voidUnRegister(IObserver observer); }
下面是改写后的两个观察者类, 复制代码 代码如下: public class NewRectangle:IObserver { privateObserverManager m; publicNewRectangle(ObserverManager oManager) { m=oManager; oManager.Register(this); } public void Notify(DrawEventArgse) { Console.WriteLine(string.Format("TheRectangle'length={0} and width={1}.", e.Size * 2, e.Size)); } public void Detach() { m.UnRegister(this); } } public class NewSquare:IObserver { privateObserverManager m;
publicNewSquare(ObserverManager oManager) { m=oManager; oManager.Register(this); } public void Notify(DrawEventArgse) { Console.WriteLine(string.Format("TheSquare'Length = {0}.", e.Size)); } public void Detach() { m.UnRegister(this); } }
下面是负责通知观察者的类型, 复制代码 代码如下: public class ObserverManager:IObservable { protectedArrayList arrList; publicObserverManager() { arrList = newArrayList(); } public void Register(IObserverobserver) { arrList.Add(observer); } public void UnRegister(IObserverobserver) { if(arrList.Contains(observer)) { arrList.Remove(observer); } } public void NotifyObservers(doublesize) { DrawEventArgse = new DrawEventArgs(size); foreach(IObserver observer inarrList) { observer.Notify(e); } } public void SizeChanged(doublesize) { NotifyObservers(size); } }
下面是调用代码, 复制代码 代码如下: static void Main(string[]args) { ObserverManageroManager = new ObserverManager(); NewRectanglerect = new NewRectangle(oManager); NewSquaresquare = new NewSquare(oManager); oManager.SizeChanged(5); square.Detach(); oManager.SizeChanged(10); Console.ReadLine(); }
最好运行下代码,这样可以更easy的理解这两种模式微妙的差别了。 对事件来说,还可以显式的用add和remove编写事件访问器,事件访问器通常有编译器生成,所以可以显式的用事件访问器修改DrawManager类型, 复制代码 代码如下: public class DrawManager { privateevent ShapeSizeChangedm_SizeChanged; privatereadonly objectm_lock = new object(); public event ShapeSizeChangedSizeChanged { add { lock(m_lock) { m_SizeChanged += value; } } remove { lock(m_lock) { m_SizeChanged -= value; } } } protectedvoid OnSizeChanged(DrawEventArgse) { ShapeSizeChangedtemp = m_SizeChanged; //是否有委托与该事件关联 if(temp != null) { temp(this,e); } } public void SizeChange(doublesize) { DrawEventArgse = new DrawEventArgs(size); OnSizeChanged(e); } }
|