PropertyGrid—添加EventTab
零.引言
前面一篇文章介绍了如何在PropertyGrid中添加属性Tab,本文主要介绍如何添加事件选项卡。事件在许多对象中都有,尤其是在控件中,如何让对象的事件在PropertyGrid中显示出来呢,本文将进行简单的说明。
一.回顾添加属性Tab
在上篇文章中详细的讲解了如何添加属性Tab,这里简单回顾一下:
1.新建一个Tab类并继承于PropertyTab。
2.重写TabName和Bitmap属性以及GetProperties方法。
3.给特定类添加PropertyTab特性或将自定义Tab类添加到PropertyGrid的PropertyTabs集合中。
三步就可以完成了,添加EventTab与此类似,现在问题的关键在于我们要显示的是事件,而GetProperties方法只能返回属性集合(PropertyDescriptorCollection)。怎么办呢,很简单,我们把事件封装成PropertyDescriptor,再返回就行了。
二. 添加EventTab
GetProperties方法只能返回属性集合。那我们就把事件封装成PropertyDescriptor。首先定义一个封装事件的类,该类继承于PropertyDescriptor:
class EventWrapper : PropertyDescriptor { string name; //名字 public EventWrapper(string name) : base(name, null) { this.name = name; } public override bool CanResetValue(object component) { return true; } public override string DisplayName { get { return name; } } public override string Description { get { return string.Format("{0} description", name); } } public override bool IsReadOnly { get { return false; } } public override string Name { get { return "fs2_" + name; } } public override Type ComponentType { get { throw new NotImplementedException(); } } public override object GetValue(object component) { //do something return ""; } public override Type PropertyType { get { return typeof(string); } } public override void ResetValue(object component) { throw new NotImplementedException(); } public override void SetValue(object component, object value) { //do something } public override bool ShouldSerializeValue(object component) { return false; } }
继承PropertyDescriptor时,需要重写一些属性和方法。封装类中,我们定义了一个name,用来保存事件的名称。好了,现在EventWrapper是从PropertyDescriptor继承而来,可以作为GetProperties方法的返回类型了。
接下来像前一篇文章一样定义一个EventsTab选型卡类:
public class EventsTab : System.Windows.Forms.Design.PropertyTab { [BrowsableAttribute(true)] // This string contains a Base-64 encoded and serialized example property tab image. private string img = "AAEAAAD/////AQAAAAAAAAAMAgAAAFRTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj0xLjAuMzMwMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5CaXRtYXABAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA9gAAAAJCTfYAAAAAAAAANgAAACgAAAAIAAAACAAAAAEAGAAAAAAAAAAAAMQOAADEDgAAAAAAAAAAAAD///////////////////////////////////9ZgABZgADzPz/zPz/zPz9AgP//////////gAD/gAD/AAD/AAD/AACKyub///////+AAACAAAAAAP8AAP8AAP9AgP////////9ZgABZgABz13hz13hz13hAgP//////////gAD/gACA/wCA/wCA/wAA//////////+AAACAAAAAAP8AAP8AAP9AgP////////////////////////////////////8L"; public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes) { //Return list of known events EventDescriptorCollection events_info; if (attributes == null) events_info = TypeDescriptor.GetEvents(component); else events_info = TypeDescriptor.GetEvents(component, attributes); //封装事件 var events = new PropertyDescriptor[events_info.Count]; for (int i = 0; i < events_info.Count; i++) events[i] = new EventWrapper(events_info[i].Name); return new PropertyDescriptorCollection(events); } public override string TabName { get { return "Events"; } } public override System.Drawing.Bitmap Bitmap { get { Bitmap bmp = new Bitmap(DeserializeFromBase64Text(img)); return bmp; } } private Image DeserializeFromBase64Text(string text) { Image img = null; byte[] memBytes = Convert.FromBase64String(text); IFormatter formatter = new BinaryFormatter(); MemoryStream stream = new MemoryStream(memBytes); img = (Image)formatter.Deserialize(stream); stream.Close(); return img; } }
唯一的不同是在Getproperties方法中,我们先获取对象的事件信息,再将其封装为我们定义的事件封装类,并返回。
现在要做的就是将我们定义的EventsTab类型添加到PropertyGrid控件的PropertyTabs集合中,将MyControl对象赋值给PropertyGrid控件的SelectedObject属性,运行程序,就可以看到MyControl对象的事件列表,效果如下:
可见,事件都列出来了。
三.完整代码
下面是完整代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.Windows.Forms.Design; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; namespace TestAddTab { //控件类 //[PropertyTabAttribute(typeof(MyPropertyTab), PropertyTabScope.Component)] public class MyControl : System.Windows.Forms.UserControl { private double _angle = 90; public MyControl() { } [BrowsableAttribute(true)] [Category("角度")] public double Angle { get { return _angle; } set { _angle = value; } } protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { e.Graphics.DrawString("The Angle is " + _angle, this.Font, Brushes.Red, 0, 0); } } public class EventsTab : System.Windows.Forms.Design.PropertyTab { [BrowsableAttribute(true)] // This string contains a Base-64 encoded and serialized example property tab image. private string img = "AAEAAAD/////AQAAAAAAAAAMAgAAAFRTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj0xLjAuMzMwMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5CaXRtYXABAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA9gAAAAJCTfYAAAAAAAAANgAAACgAAAAIAAAACAAAAAEAGAAAAAAAAAAAAMQOAADEDgAAAAAAAAAAAAD///////////////////////////////////9ZgABZgADzPz/zPz/zPz9AgP//////////gAD/gAD/AAD/AAD/AACKyub///////+AAACAAAAAAP8AAP8AAP9AgP////////9ZgABZgABz13hz13hz13hAgP//////////gAD/gACA/wCA/wCA/wAA//////////+AAACAAAAAAP8AAP8AAP9AgP////////////////////////////////////8L"; public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes) { //Return list of known events EventDescriptorCollection events_info; if (attributes == null) events_info = TypeDescriptor.GetEvents(component); else events_info = TypeDescriptor.GetEvents(component, attributes); var events = new PropertyDescriptor[events_info.Count]; for (int i = 0; i < events_info.Count; i++) events[i] = new EventWrapper(events_info[i].Name); return new PropertyDescriptorCollection(events); } public override string TabName { get { return "Events"; } } public override System.Drawing.Bitmap Bitmap { get { Bitmap bmp = new Bitmap(DeserializeFromBase64Text(img)); return bmp; } } private Image DeserializeFromBase64Text(string text) { Image img = null; byte[] memBytes = Convert.FromBase64String(text); IFormatter formatter = new BinaryFormatter(); MemoryStream stream = new MemoryStream(memBytes); img = (Image)formatter.Deserialize(stream); stream.Close(); return img; } } class EventWrapper : PropertyDescriptor { string name; public EventWrapper(string name) : base(name, null) { this.name = name; } public override bool CanResetValue(object component) { return true; } public override string DisplayName { get { return name; } } public override string Description { get { return string.Format("{0} description", name); } } public override bool IsReadOnly { get { return false; } } public override string Name { get { return "fs2_" + name; } } public override Type ComponentType { get { throw new NotImplementedException(); } } public override object GetValue(object component) { //do something return ""; } public override Type PropertyType { get { return typeof(string); } } public override void ResetValue(object component) { throw new NotImplementedException(); } public override void SetValue(object component, object value) { //do something } public override bool ShouldSerializeValue(object component) { return false; } } }
新建Windows工程,添加该文件,在Form中拖入一个PropertyGrid控件和MyControl控件,在Form的构造函数中添加如下代码:
this.propertyGrid1.PropertyTabs.AddTabType(typeof(EventsTab));
this.propertyGrid1.SelectedObject = this.myControl1;
运行程序,查看效果。
这里只是实现了非常简单的功能,仅仅显示了控件的事件,而不能编辑,如果要达到VS那种效果,需要完善EventWrapper类。
还是那句话,个人浅见,错漏不正之处,敬请指出,万分感谢!
(原文)