• 编写windows 控件需要注意的几个标签属性(Attribute)


    我们在编程控件(Control)或者是组件(Component)的时候总是要暴露一些属性(Property,不同于Attribute)给用户进行配置,以得到可以变化的功能。

    mapserver .NET组件编程(1) 基础 中说到的

    1、Component在Run Time时不能呈现UI,而Control可以在Run Time时呈现UI(但是vs 2005里的asp.net中的SqlDataSource是Control,但是它不能呈现UI)。
    2、Component是贴在容器Container上的,而Control则是贴在Windows Form或者Web Form上的。 举例来说,SqlCommand是个Component,DataGrid则是一个Control。

    mapserver写了.net 组件编程系列,值得看看。

    就说,如何在设计时对某个属性(property)提供一些帮助,那么就需要用到几个重要的属性(Attribute)。

    TypeConverter, Editor 标签属性

    下面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对应的图片的?

     

    Serializable 标签属性
       1: [Serializable]
       2:    public class XButton  
       3:    {
    注意,如果贴上Serilizable,则代码会自动生成(来之与from1.designer.cs文件的片段)
       1: this.userControl11.xButtons.Add(((WindowsControlLibrary1.XButton)(resources.GetObject("userControl11.xButtons"))));
    也就说它是通过从资源文件来保存(序列)值。如果不贴上[Serializable]标签,则自动生成在代码里面(来之与from1.designer.cs文件的片段)
       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:    
    ButtonBase里面ImageIndex属性怎么通过在标签属性TypeConverter 和Editor配合下,我们就能在设计的时候选择button对应的图片的?

    image

    先看看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:         }

    关于这方面的一些资料

    编写与.NET属性窗口交互的RAD组件

    其中有一段话,我很感兴趣

    在实现数据绑定的组件中,清除掉DataSource的值,自然的就会清除掉DataMember的值。RefreshPropertiesAttribute就让我们实现这个功能。他的默认值是“none,”不过如果指定其他的特性,属性窗口就可以在改变这个属性值的同时,自动的更新被更新属性的值。另外的两个值是Repaint,它让属性窗口重新获取属性的值并且重画他们,还有就是All,它就意味着组件自己要重新获取属性的值。如果值的改变导致属性的数目的增减,那么我们就要使用All。不过要注意到这个一般用在高级场合,并且速度要比Repaint慢。RefreshProperties.Repaint适用于大部分的情况。

    所谓的刷新调用的是什么方法来进行? 比如,我设置了某个属性的值,这个属性的值又是关于空间外观的,那么如何来触发这个事件?

  • 相关阅读:
    测试用例的优先级的概念
    Day02.测试用例和测试方法
    day01.测试理论
    开发python 面试题
    4.路径页面接口开发
    ps命令没有显示路径找到命令真实路径
    Linux软链接和硬链接
    Linux文件元数据和节点表结构
    jinjia2语言
    Ansible之YAML语言
  • 原文地址:https://www.cnblogs.com/king_astar/p/1183678.html
Copyright © 2020-2023  润新知