在基類中聲明可以從派生類引發的事件的標准方法。此模式廣泛應用於.Net Framework類庫中的Windows窗體類。
我們來看一個Button類的定義
public class Button : ButtonBase, IButtonControl
{
protected override void OnClick(EventArgs e); //override基類的事件觸發程序
}
我們通過ButtonBase最後找到基類Control
public class Control : Component, IDropTarget, ISynchronizeInvoke, IWin32Window, IArrangedElement, IBindableComponent, IComponent, IDisposable
{
public event EventHandler Click; //基類中定義事件
protected virtual void OnClick(EventArgs e);//protected封裝事件觸發程序,允許繼承類調用或重寫
}
在包含事件的基類中創建一個受保護的調用方法。通過調用或重寫方法,派生類便可以間接調用該事件。
我們來看一個例子:
namespace BaseClassEvents
{
//Special EventArgs class to hold info about Shapes.
public class ShapeEventArgs:EventArgs
{
private double newArea;
public ShapeEventArgs (double d)
{
newArea = d;
}
public double NewArea
{
get
{
return newArea;
}
}
}
//Declare a delegate
public delegate void CustomEventHandler(object sender, ShapeEventArgs e);
//Base class event publisher
public abstract class Shape
{
protected double area;
public double Area
{
get
{
return area;
}
set
{
area = value;
}
}
//raise an event
public event CustomEventHandler ShapeChanged;
public abstract void Draw();
//event-invoking method
protected virtual void OnShapeChanged(ShapeEventArgs e)
{
if(ShapeChanged !=null)
{
ShapeChanged(this, e);
}
}
}
public class Circle:Shape
{
private double radius;
public Circle (double d)
{
radius = d;
area = 3.14 * radius * radius;
}
public void Update(double d)
{
radius = d;
area = 3.14 * radius * radius;
OnShapeChanged(new ShapeEventArgs(area));
}
protected override void OnShapeChanged(ShapeEventArgs e)
{
base.OnShapeChanged(e);
}
public override void Draw()
{
Console.WriteLine("Drawing a circle");
}
}
public class Rectangle:Shape
{
private double length;
private double width;
public Rectangle (double length,double width)
{
this.length = length;
this.width = width;
area = length * width;
}
public void Update(double length,double width)
{
this.length = length;
this.width = width;
area = length * width;
OnShapeChanged(new ShapeEventArgs(area));
}
protected override void OnShapeChanged(ShapeEventArgs e)
{
base.OnShapeChanged(e);
}
public override void Draw()
{
Console.WriteLine("Drawing a rectangle");
}
}
//Subscriber
//Represents the surface on which the shapes are drawn
//Subscibes to shape events so that it knows
//when to redraw a shape
public class ShapeContainer
{
List<Shape> _list;
public ShapeContainer ()
{
_list = new List<Shape>();
}
public void AddShape(Shape s)
{
_list.Add(s);
//Subscribe to the base class event.
s.ShapeChanged += HandleShapeChanged;
}
private void HandleShapeChanged(object sender,ShapeEventArgs e)
{
Shape s = (Shape)sender;
Console.WriteLine("Received event. Shape area is now {0}", e.NewArea);
s.Draw();
}
}
class Program
{
static void Main(string[] args)
{
//Create the event publishers and subscriber
Circle c1 = new Circle(54);
Rectangle r1 = new Rectangle(12, 9);
ShapeContainer sc = new ShapeContainer();
//Add the shapes to the container
sc.AddShape(c1);
sc.AddShape(r1);
//Cause some events to be raised
c1.Update(57);
r1.Update(7, 7);
Console.ReadKey();
}
}
}