零.引言
前面一篇文章介绍了如何在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:
1 class EventWrapper : PropertyDescriptor 2 { 3 string name; //名字 4 public EventWrapper(string name) 5 : base(name, null) 6 { 7 this.name = name; 8 } 9 10 public override bool CanResetValue(object component) 11 { 12 return true; 13 } 14 15 public override string DisplayName 16 { 17 get 18 { 19 return name; 20 } 21 } 22 23 public override string Description 24 { 25 get 26 { 27 return string.Format("{0} description", name); 28 } 29 } 30 31 public override bool IsReadOnly 32 { 33 get { return false; } 34 } 35 36 public override string Name 37 { 38 get 39 { 40 return "fs2_" + name; 41 } 42 } 43 44 public override Type ComponentType 45 { 46 get { throw new NotImplementedException(); } 47 } 48 49 public override object GetValue(object component) 50 { 51 //do something 52 return ""; 53 } 54 55 public override Type PropertyType 56 { 57 get { return typeof(string); } 58 } 59 60 public override void ResetValue(object component) 61 { 62 throw new NotImplementedException(); 63 } 64 65 public override void SetValue(object component, object value) 66 { 67 //do something 68 } 69 70 public override bool ShouldSerializeValue(object component) 71 { 72 return false; 73 } 74 }
继承PropertyDescriptor时,需要重写一些属性和方法。封装类中,我们定义了一个name,用来保存事件的名称。好了,现在EventWrapper是从PropertyDescriptor继承而来,可以作为GetProperties方法的返回类型了。
接下来像前一篇文章一样定义一个EventsTab选型卡类:
1 public class EventsTab : System.Windows.Forms.Design.PropertyTab 2 { 3 [BrowsableAttribute(true)] 4 // This string contains a Base-64 encoded and serialized example property tab image. 5 private string img = "AAEAAAD/////AQAAAAAAAAAMAgAAAFRTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj0xLjAuMzMwMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5CaXRtYXABAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA9gAAAAJCTfYAAAAAAAAANgAAACgAAAAIAAAACAAAAAEAGAAAAAAAAAAAAMQOAADEDgAAAAAAAAAAAAD///////////////////////////////////9ZgABZgADzPz/zPz/zPz9AgP//////////gAD/gAD/AAD/AAD/AACKyub///////+AAACAAAAAAP8AAP8AAP9AgP////////9ZgABZgABz13hz13hz13hAgP//////////gAD/gACA/wCA/wCA/wAA//////////+AAACAAAAAAP8AAP8AAP9AgP////////////////////////////////////8L"; 6 7 public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes) 8 { 9 //Return list of known events 10 EventDescriptorCollection events_info; 11 if (attributes == null) 12 events_info = TypeDescriptor.GetEvents(component); 13 else 14 events_info = TypeDescriptor.GetEvents(component, attributes); 15 //封装事件 16 var events = new PropertyDescriptor[events_info.Count]; 17 for (int i = 0; i < events_info.Count; i++) 18 events[i] = new EventWrapper(events_info[i].Name); 19 20 return new PropertyDescriptorCollection(events); 21 } 22 23 public override string TabName 24 { 25 get { return "Events"; } 26 } 27 28 public override System.Drawing.Bitmap Bitmap 29 { 30 get 31 { 32 Bitmap bmp = new Bitmap(DeserializeFromBase64Text(img)); 33 34 return bmp; 35 } 36 } 37 38 private Image DeserializeFromBase64Text(string text) 39 { 40 Image img = null; 41 byte[] memBytes = Convert.FromBase64String(text); 42 IFormatter formatter = new BinaryFormatter(); 43 MemoryStream stream = new MemoryStream(memBytes); 44 img = (Image)formatter.Deserialize(stream); 45 stream.Close(); 46 return img; 47 } 48 }
唯一的不同是在Getproperties方法中,我们先获取对象的事件信息,再将其封装为我们定义的事件封装类,并返回。
现在要做的就是将我们定义的EventsTab类型添加到PropertyGrid控件的PropertyTabs集合中,将MyControl对象赋值给PropertyGrid控件的SelectedObject属性,运行程序,就可以看到MyControl对象的事件列表,效果如下:
可见,事件都列出来了。
三.完整代码
下面是完整代码:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Windows.Forms; 6 using System.Windows.Forms.Design; 7 using System.ComponentModel; 8 using System.ComponentModel.Design; 9 using System.Drawing; 10 using System.IO; 11 using System.Runtime.Serialization; 12 using System.Runtime.Serialization.Formatters.Binary; 13 14 namespace TestAddTab 15 { 16 //控件类 17 //[PropertyTabAttribute(typeof(MyPropertyTab), PropertyTabScope.Component)] 18 public class MyControl : System.Windows.Forms.UserControl 19 { 20 private double _angle = 90; 21 22 public MyControl() 23 { 24 } 25 26 [BrowsableAttribute(true)] 27 [Category("角度")] 28 public double Angle 29 { 30 get 31 { return _angle; } 32 set 33 { _angle = value; } 34 } 35 36 37 protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) 38 { 39 e.Graphics.DrawString("The Angle is " + _angle, this.Font, Brushes.Red, 0, 0); 40 } 41 } 42 43 public class EventsTab : System.Windows.Forms.Design.PropertyTab 44 { 45 [BrowsableAttribute(true)] 46 // This string contains a Base-64 encoded and serialized example property tab image. 47 private string img = "AAEAAAD/////AQAAAAAAAAAMAgAAAFRTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj0xLjAuMzMwMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5CaXRtYXABAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA9gAAAAJCTfYAAAAAAAAANgAAACgAAAAIAAAACAAAAAEAGAAAAAAAAAAAAMQOAADEDgAAAAAAAAAAAAD///////////////////////////////////9ZgABZgADzPz/zPz/zPz9AgP//////////gAD/gAD/AAD/AAD/AACKyub///////+AAACAAAAAAP8AAP8AAP9AgP////////9ZgABZgABz13hz13hz13hAgP//////////gAD/gACA/wCA/wCA/wAA//////////+AAACAAAAAAP8AAP8AAP9AgP////////////////////////////////////8L"; 48 49 50 public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes) 51 { 52 //Return list of known events 53 EventDescriptorCollection events_info; 54 if (attributes == null) 55 events_info = TypeDescriptor.GetEvents(component); 56 else 57 events_info = TypeDescriptor.GetEvents(component, attributes); 58 59 var events = new PropertyDescriptor[events_info.Count]; 60 for (int i = 0; i < events_info.Count; i++) 61 events[i] = new EventWrapper(events_info[i].Name); 62 63 return new PropertyDescriptorCollection(events); 64 } 65 66 public override string TabName 67 { 68 get { return "Events"; } 69 } 70 71 public override System.Drawing.Bitmap Bitmap 72 { 73 get 74 { 75 Bitmap bmp = new Bitmap(DeserializeFromBase64Text(img)); 76 return bmp; 77 } 78 } 79 80 private Image DeserializeFromBase64Text(string text) 81 { 82 Image img = null; 83 byte[] memBytes = Convert.FromBase64String(text); 84 IFormatter formatter = new BinaryFormatter(); 85 MemoryStream stream = new MemoryStream(memBytes); 86 img = (Image)formatter.Deserialize(stream); 87 stream.Close(); 88 return img; 89 } 90 } 91 92 class EventWrapper : PropertyDescriptor 93 { 94 string name; 95 public EventWrapper(string name) 96 : base(name, null) 97 { 98 this.name = name; 99 } 100 101 public override bool CanResetValue(object component) 102 { 103 return true; 104 } 105 106 public override string DisplayName 107 { 108 get 109 { 110 return name; 111 } 112 } 113 114 public override string Description 115 { 116 get 117 { 118 return string.Format("{0} description", name); 119 } 120 } 121 122 public override bool IsReadOnly 123 { 124 get { return false; } 125 } 126 127 public override string Name 128 { 129 get 130 { 131 return "fs2_" + name; 132 } 133 } 134 135 public override Type ComponentType 136 { 137 get { throw new NotImplementedException(); } 138 } 139 140 public override object GetValue(object component) 141 { 142 //do something 143 return ""; 144 } 145 146 public override Type PropertyType 147 { 148 get { return typeof(string); } 149 } 150 151 public override void ResetValue(object component) 152 { 153 throw new NotImplementedException(); 154 } 155 156 public override void SetValue(object component, object value) 157 { 158 //do something 159 } 160 161 public override bool ShouldSerializeValue(object component) 162 { 163 return false; 164 } 165 } 166 }
新建Windows工程,添加该文件,在Form中拖入一个PropertyGrid控件和MyControl控件,在Form的构造函数中添加如下代码:
this.propertyGrid1.PropertyTabs.AddTabType(typeof(EventsTab));
this.propertyGrid1.SelectedObject = this.myControl1;
运行程序,查看效果。
这里只是实现了非常简单的功能,仅仅显示了控件的事件,而不能编辑,如果要达到VS那种效果,需要完善EventWrapper类。
还是那句话,个人浅见,错漏不正之处,敬请指出,万分感谢!