0x52——C#中自定义Event与Handler
最初学会自定义Event和Handler是通过这篇博客:Simple custom event handling。另外我也看过:Writing C# Custom Events,不过没太看懂那篇在讲什么,可能是因为没有细看。
C#中的Event模型是基于发布者(Publisher)与订阅者(Subscriber)(注:应该是在讲Observer Pattern)。每一个发布者可以拥有多个时间,每一个事件又可以有多个订阅者。Publisher在满足一定条件之后,会发布一个Event给所有的订阅者。订阅者则会做出相应的反应。在C#中,任意一个控件都可以发布event,其他的任何控件也都可以订阅此event,并针对此做出相应的反应。
惯例
在处理Event时,有如下的惯例:
1. .net framework中的Event Handlers返回值为空,且需要传两个参数;
2. 第一个参数是事件源(即发布者);
3. 第二个参数是一个EventArgs的衍生类;
4. Event是发布它的类的性质(Properties);
5. Event的Keyword控制该Event如何被订阅的类获得。
例子
我们有一个产品,它有一个Name的Property,当它的名字发生变化时,我们希望一个Label中的内容也发生相应的变化。于是就需要Product是一个Publisher,而Label就是一个订阅者。
注:我这里的代码是考的样例代码,实际上其中并没有使用什么Label,而只是直接修改了一次。但我觉得基本是讲清楚了Event的定制方法。更详细地也可以参加原文。
首先我们先定义Event,以及会触发此Event的Method。
public class Product { public string Name { get; set; } // Delegate public delegate void PropertyChangeHandler (object sender, EventArgs data); // The event public event PropertyChangeHandler PropertyChange; // The method which fires the Event protected void OnPropertyChange (object sender, EventArgs data) { // Check if there are any Subscribers if (PropertyChange!= null) { // Call the Event PropertyChange (this, data); } } }
这里我们定义一个delegate,叫做PropertyChangeHandler,这个delegate需要被所有的订阅者执行。
之后我们就需要定义一个Event,它是EventArgs的衍生类。
public class PropertyChangeEventArgs : EventArgs { public string PropertyName { get; internal set; } public object OldValue { get; internal set; } public object NewValue { get; internal set; } public PropertyChangeEventArgs(string propertyName, object oldValue, object newValue) { this.PropertyName = propertyName; this.OldValue = oldValue; this.NewValue = newValue; } } public class Product { private string name; public string Name { get { this.name; } set { Object old = this.name; this.name = value; OnPropertyChange(this, new PropertyChangeEventArgs(“Name”, old, value)); } } // Delegate public delegate void PropertyChangeHandler (object sender, PropertyChangeEventArgs data); // The event public event PropertyChangeHandler PropertyChange; // The method which fires the Event protected void OnPropertyChange (object sender, PropertyChangeEventArgs data) { // Check if there are any Subscribers if (PropertyChange!= null) { // Call the Event PropertyChange (this, data); } } }
注:从后文看,Event中的PropertyName只是一个调用事件的条件项,实际上并不是主要的。也可以通过满足其它条件时触发此事件,甚至可以任何时候都触发此事件。
然后我们定义一个Product并订阅此事件。
private static Product Product; static void Main(string[] args) { Program.Product = new Product();
//订阅 Program.Product.PropertyChange += new Product.PropertyChangeHandler(Program.PropertyHasChanged); Program.Product.Name = "new"; Program.Product.Name = "value changed again"; Console.ReadLine(); } public static void PropertyHasChanged(object sender, PropertyChangeEventArgs data) { if (data.PropertyName == "Name") { Console.WriteLine("New value: '" + (string)data.NewValue + "' was: '" + (string)data.OldValue + "'"); } }
在Name改变的时候,OnPropertyChange就会raise event。然后所有的订阅者都会调用相应的函数。