编写windows 控件需要注意的几个标签属性(Attribute)
我们在编程控件(Control)或者是组件(Component)的时候总是要暴露一些属性(Property,不同于Attribute)给用户进行配置,以得到可以变化的功能。
mapserver .NET组件编程(1) 基础 中说到的
2、Component是贴在容器Container上的,而Control则是贴在Windows Form或者Web Form上的。 举例来说,SqlCommand是个Component,DataGrid则是一个Control。
mapserver写了.net 组件编程系列,值得看看。
就说,如何在设计时对某个属性(property)提供一些帮助,那么就需要用到几个重要的属性(Attribute)。
下面ImageIndex的属性被贴上标签属性。
1: [//TypeConverter(typeof(ImageIndexConverter)),
2: Editor(typeof(newimageEditoer), typeof(UITypeEditor)),
3: Description("")]
4: public int ImageIndex
5: {
6: get { return myVar; }
7: set { myVar = value; }
8: }
TypeConverter 指类型转换。
Editor 在设计时,调用哪个Editor对它进行编辑修改。
DesignerSerializationVisibilityAttribute:指定通过Property Editor得到的结果是否保存在代码中。
LocalizableAttribute:用户要本地化某个窗体时,任何具有该特性的属性都将自动永久驻留到资源文件中。
TypeConverter 和 Editor有时候是相互作用的。比如上面的例子,大家可以用reflector看看微软的buttonBase 里面的ImageIndex的标签属性是什么,并找到ImageIndexConverter 和对应的Editor [ImageIndexEditor]。 如果我们继续是用TypeConverter[ImageIndexConverter ],重新完成一个新的Editor[newimageEditoer],你会发现新的Editor是不起作用的。
接下来,我们看看Serializable标签属性会在VS自动代码起到什么样的作用,接着,我们再回过头看看ButtonBase里面ImageIndex属性怎么通过在标签属性TypeConverter 和Editor配合下,我们就能在设计的时候选择button对应的图片的?
1: [Serializable]
2: public class XButton
3: {
1: this.userControl11.xButtons.Add(((WindowsControlLibrary1.XButton)(resources.GetObject("userControl11.xButtons"))));
1: //先实例
2: WindowsControlLibrary1.XButton xButton1 = new WindowsControlLibrary1.XButton();
3: WindowsControlLibrary1.XButton xButton2 = new WindowsControlLibrary1.XButton();
4: //
5: xButton1.component = null;
6: xButton1.ImageIndex = -1;
7: xButton2.component = null;
8: xButton2.ImageIndex = -1;
9: this.userControl11.xButtons.Add(xButton1);
10: this.userControl11.xButtons.Add(xButton2);
描述一下xButton类, xButtons是一个List<xButton>集合类型。
1: public class XButton
2:
3:
4: public XButton()
5: {
6:
7: }
8:
9: private string _txt = "";
10: [DefaultValue("")]
11: public string Text
12: {
13: get { return _txt; }
14: set { _txt = value; }
15: }
16:
17: private int myVar = -1;
18:
19: [//TypeConverter(typeof(ImageIndexConverter)),
20: r(typeof(newimageEditoer), typeof(UITypeEditor)),
21: iption("")]
22: public int ImageIndex
23: {
24: get { return myVar; }
25: set { myVar = value; }
26: }
27:
28: [NonSerialized]
29: private System.ComponentModel.Component _im;
30: [Browsable(false)]
31: public System.ComponentModel.Component component
32: {
33: get { return _im; }
34: set { _im = value; }
35: }
36:
37:
先看看UI,一开始,我以为Editor是完成了所有编辑功能(编辑样式[EditStyle]你可以选择三种,一种none,一种是下拉框,一种是对话框形式)
这个可以在继承UITypeEditor类复写
1: public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
2: {
3:
4: return UITypeEditorEditStyle.Modal;
5: //return base.GetEditStyle(context);
6: }
那么,我们是如何看到下拉框图片的呢?本来我以为这部分会在Editor里面实现,实际上不是的。有部分是在ImageIndexConverter中,它创建了Image的Collection
1: public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
2: {
3: if ((context != null) && (context.Instance != null))
4: {
5: object instance = context.Instance;
6: PropertyDescriptor imageListProperty = ImageListUtils2.GetImageListProperty(context.PropertyDescriptor, ref instance);
7: while ((instance != null) && (imageListProperty == null))
8: {
9: PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(instance);
10: foreach (PropertyDescriptor descriptor2 in properties)
11: {
12: if (typeof(ImageList).IsAssignableFrom(descriptor2.PropertyType))
13: {
14: imageListProperty = descriptor2;
15: break;
16: }
17: }
18: if (imageListProperty == null)
19: {
20: PropertyDescriptor descriptor3 = properties[this.ParentImageListProperty];
21: if (descriptor3 != null)
22: {
23: instance = descriptor3.GetValue(instance);
24: continue;
25: }
26: instance = null;
27: }
28: }
29: if (imageListProperty != null)
30: {
31: ImageList list = (ImageList)imageListProperty.GetValue(instance);
32: if (list != null)
33: {
34: object[] objArray;
35: int count = list.Images.Count;
36: if (this.IncludeNoneAsStandardValue)
37: {
38: objArray = new object[count + 1];
39: objArray[count] = -1;
40: }
41: else
42: {
43: objArray = new object[count];
44: }
45: for (int i = 0; i < count; i++)
46: {
47: objArray[i] = i;
48: }
49: return new TypeConverter.StandardValuesCollection(objArray);
50: }
51: }
52: }
53: if (this.IncludeNoneAsStandardValue)
54: {
55: return new TypeConverter.StandardValuesCollection(new object[] { -1 });
56: }
57: return new TypeConverter.StandardValuesCollection(new object[0]);
58: }
里面的实际上用了反射的机制来获取一个ImageList并把其中的Image加入到一个TypeConverter.StandardValuesCollection,但具体是谁来控制把这集合显示出来的呢?我不知道。
至于把它显示出来是在Editor里面实现的,其中调用了方法GetImage,就是去找到Image并画出来。
1: public override void PaintValue(PaintValueEventArgs e)
2: {
3: if (this.ImageEditor != null)
4: {
5: Image image = null;
6: if (e.Value is int)
7: {
8: image = this.GetImage(e.Context, (int)e.Value, null, true);
9: }
10: else if (e.Value is string)
11: {
12: image = this.GetImage(e.Context, -1, (string)e.Value, false);
13: }
14: if (image != null)
15: {
16: this.ImageEditor.PaintValue(new PaintValueEventArgs(e.Context, image, e.Graphics, e.Bounds));
17: }
18: }
19: }
关于这方面的一些资料
其中有一段话,我很感兴趣
所谓的刷新调用的是什么方法来进行? 比如,我设置了某个属性的值,这个属性的值又是关于空间外观的,那么如何来触发这个事件?