• 今天你写控件了吗?ASP.net控件开发系列(五)


    TypeConverter

         在本系列的上篇文章中,和大家控讨了控件开发与propertyGrid的关系,不知现在大家现在对propertygrid有没有一个较全面的了解,也不知大家有没有做个工程,把propertyGrid拉进去鼓捣鼓捣?

    “另起炉灶”


         现在我们来思考一个问题:假于,propertygrid没有把属性和事件分成两个分页来显示,会产生什么效果?
         那还用说,太乱了。
         那如果你设计的控件有很多的属性,而一些关联性很强,或都是操作一个方面的,那么我们可以把它们分门别类,摆到一起,怎么做呢?
     我们可以给这个控件类指定以下Attribute:

     [PropertyTab(typeof(YourPropertyTab), PropertyTabScope.Component)]
     
    public class YourControlClass
     
    {
      
     }

    其中,前面一个参数指定处理PropertyTab的类,后一个参数说明要应用在什么时候,Component为当前组件专用,Document当前文档专用,Global只能由父给件显式去除,Static不能去除。
     

    internal class YourPropertyTab : PropertyTab 
     
    {
      
    internal YourControlType target;

        
    public override string TabName 
      
    {
       
    get 
       
    {
        
    return "选项卡的名字";
       }

      }

      
    public override Bitmap Bitmap 
      
    {
       
    get
       
    {
        
    return new Bitmap(base.Bitmap, new Size(16,16));//这里是使用保存为嵌入资源的和YourPropertyTab类同名的.bmp文件
       }

      }


      
    public override bool CanExtend(object o) 
      
    {
       
    return o is YourControlType;//什么时候用这个Tab
      }


              
    public override PropertyDescriptorCollection GetProperties(object component, Attribute[] attrs) {
                  
    return GetProperties(null, component, attrs);
             }


     
      
    /// 主要的逻辑.  在这里定义如何实现分Tab显示
      
      
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object component, Attribute[] attrs)
      
    {
       YourControlType uc 
    = component as YourControlType;

       
    if (uc == null
       
    {
        
    //以下代码实现不是YourControlType时,使用本身类型的逻辑。 
        TypeConverter tc = TypeDescriptor.GetConverter(component);
        
    if (tc != null
        
    {
         
    return tc.GetProperties(context, component, attrs);
        }

        
    else 
        
    {
         
    return TypeDescriptor.GetProperties(component, attrs);
        }

       }

        
       target 
    = uc;
       ArrayList propList 
    = new ArrayList();
       
    //..建立一个属性List
       propList.Add(new YourPropertyDescriptor(this);
       PropertyDescriptor[] props 
    = (PropertyDescriptor[])propList.ToArray(typeof(PropertyDescriptor));    
       
    return new PropertyDescriptorCollection(props);
      }

      
    //我们还要建立自定义的PropertyDescriptor供GetProperties方法使用。
      private class YourPropertyDescriptor : PropertyDescriptor 
      
    {
       YourPropertyTab owner;
       
    public NumPointsPropertyDescriptor(YourPropertyTab owner) ://注意这里的参数
        base("PropertyName"new Attribute[]{CategoryAttribute.Data, RefreshPropertiesAttribute.All})//第二个参数是指定属性改变时,与         //其它属性的联动,整个属性页是否刷新,All-刷新,Default-不,Repaint-重画属性窗口
       {
        
    this.owner = owner;     
       }


       
    public override Type PropertyType//属性的类型 
       {
        
    get 
        
    {
         
    return typeof(int);
        }

       }

       属性关联对象是什么类型
       
    public override Type ComponentType
       
    {
        
    get 
        
    {
         
    return typeof(YourControlType);
        }

       }


       
    public override bool IsReadOnly {get{return false;}}
      
       
    public override object GetValue(object o) //和关联对象的什么属性相关
       {
        
    return ((YourControlType)o).Proterty_1;
       }


       
    public override void SetValue(object o, object value) //和关联对象的什么属性相关
       {
        YourControlType uc 
    = o as YourControlType;
        uc.Property_1 
    = (int)value;    
       }


       
    public override void ResetValue(object o){}//望文生义


       
    public override bool CanResetValue(object o) //望文生义
       {
        
    return false;
       }

       
    ///Does this property participate in code generation?
       public override bool ShouldSerializeValue(object o) 
       
    {
        
    return false;
       }

      }

     
     }



    类型转换器


     在上一篇文章中,我们已经接触了TypeConverter,现在我们全面的来看看这个Interpreter:
     1、TypeConverter从System.ComponentModel.TypeConverter类派生。
     2、用使用[TypeConverter(typeof(YourTypeConverter))]绑定到属性。
     3、在设计期和运行期都要用到TypeConverter,因为,两个时期都有特定类型-String之间的转换。
     4、功能一:把属性转换成字符串显示在属性浏览器,把属性浏览器的设的值转换成属性需要的类型。
     5、功能二:为子属性提供一个展开/折叠的UI。如下图:
     要实现这个功能非常之简单,你先让属性通过TypeConverterAttribute关联到转换器类System.ComponentModel.ExpandableObjectConverter,或者继承自这个类的转换器。

    public class YourConverter : ExpandableObjectConverter {
     
    do something,example: override CovertTo function
        }

    public class YourControl
    {
     [TypeConverter(
    typeof(YourConverter))]
     
    public YourPropertyClass ExpandableProperty
     
    {
      .
     }

    }

     6、为属性提供一个设计期值的下拉列表,正如我上篇文章所述。
     7、System.Web.UI.WebControls namespace & System.ComponentModel namespace下已经有了这些转换器:UnitConverter,BooleanConverter,CharConverter,EnumConverter,CollectionConverter,ArrayConverter,BaseNumberConverter,ByteConverter,ReferenceConverter,CultureInfoCOnverter,DateTimeConverter,DecimalConverter,DoubleConverter,ExpandableObjectConverter,GuidConverter,Int16(32/64)Converter,sByteConverter,SingleConverter,StringConverter,TimeSpanConverter,TypeListConverter,UInt16(32/64)Converter,ObjectConverter,PropertyConverter,DataBindingCollectionConverter,DataFieldConverter,DataMemberConverter,DataSourceConverter,FontNamesConverter,FontUnitConverter,TargetConverter,ValidatedControlConverter,CursorConverter......(WinForm的我就不列出来了)

    下面,我们就重点来看看如何实现不同类型和String怎么样来转换。
     下面这个实例应该就得达到这个目的。

        public class YourTypeConverter : TypeConverter {//类型转换器需直接或间接继承自TypeConverter类,
          
    //上面例子继承自ExpandableObjectConverter也是间接继承TypeConverter类

            
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {//源类型能不能转换成转换器关联类型
                if (sourceType == typeof(string)) {
                    
    return true;
                }

                
    return base.CanConvertFrom(context, sourceType);//我们实现了和String的转换,所以为String的话为True,然后,简单调用基类的方法就行。
            }


            
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {//string能不能转换成目标类
                if ((destinationType == typeof(string)) ||
                    (destinationType 
    == typeof(InstanceDescriptor))) {//System.ComponentModel.Design.Serialization.InstanceDescriptor
            
    //提供创建对象的实例所需的信息,此处返回转换器关联类型的实例
                    return true;
                }

                
    return base.CanConvertTo(context, destinationType);//只有实现了ConverTo目标类型才能为TRUE(我们在后面实现了string),如果String可以转换成目标类型,        //那么也会为TRUE,因为这里我们可以将之转成String,再调用String的转换。
            }


            
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {//从一种类型转换成我们的类型
                if (value == null{
                    
    return new YourType();//空值来,默认实现
                }


                
    if (value is string{//如果是string,定制转化逻辑
                    string s = (string)value;
                    
    if (s.Length == 0{
                        
    return new YourType();
                    }

      
    //以下的例子实现"20,30"转换成new YourType(20,30),分两步,分隔,变Int
                    string[] parts = s.Split(culture.TextInfo.ListSeparator[0]);

                    
    if (parts.Length != 2{
                        
    throw new ArgumentException("Invalid YourType""value");
                    }


                    TypeConverter intConverter 
    = TypeDescriptor.GetConverter(typeof(Int32));
                    
    return new YourType((int)intConverter.ConvertFromString(context, culture, parts[0]),
                        (
    int)intConverter.ConvertFromString(context, culture, parts[1]));
                }


                
    return base.ConvertFrom(context, culture, value);//还是要调用一下基类的方法。
            }


            
    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {//我们的类型转换成其它类型
                if (value != null{//先确定源类型是不我们的要转的类型。
                    if (!(value is YourType)) {
                        
    throw new ArgumentException("Invalid YourType""value");
                    }

                }


                
    if (destinationType == typeof(string)) {//转成string的逻辑
                    if (value == null{
                        
    return String.Empty;
                    }


                    YourType yourType 
    = (YourType)value;
      
    //以下的例子将yourType的两个int属性变成"属性值1,属性值2"的字符串。
                    TypeConverter intConverter = TypeDescriptor.GetConverter(typeof(Int32));
                    
    return String.Join(culture.TextInfo.ListSeparator,
                        
    new string[] {
                                         intConverter.ConvertToString(context, culture, yourType.Value_1),
                                         intConverter.ConvertToString(context, culture, yourType.Value_2)
                                     }
    );
                }

                
    else if (destinationType == typeof(InstanceDescriptor)) {
      
    //以下的例子实现如果源类型本身就是这个类型时,我们的处理逻辑,
      
    //这里就用了System.Reflection namespace下的方法来分别调用YourType的无参构造函数和有两个参数的构造函数。
                    if (value == null{
                        
    return null;
                    }


                    MemberInfo mi 
    = null;//通过对YourType MetaData的访问得到它的构造函数
                    object[] args = null;

                    YourType yourType 
    = (YourType)value;
                    
    if (yourType.IsEmpty) {
                        mi 
    = typeof(YourType).GetConstructor(new Type[0]);
                    }

                    
    else {
                        Type intType 
    = typeof(int);
                        mi 
    = typeof(YourType).GetConstructor(new Type[] { intType, intType });
                        args 
    = new object[] { yourType.Value_1, yourType.Value_2 };
                    }


                    
    if (mi != null{
                        
    return new InstanceDescriptor(mi, args);//根据选择的构造子和参数建立实例
                    }

                    
    else {
                        
    return null;
                    }

                }


                
    return base.ConvertTo(context, culture, value, destinationType);//还是调用基类的方法。
            }

        }


    大家看到在上面的代码中我们老是在override方法中最后调用基类的方法,这么做是省去实现转换失败时的返回等逻辑的实现,避免出现莫名其妙的错误。
    现在,我们回过头来看看上面的那张图,我们使用了继承自ExpandableObjectConverter的转换器,而且,我们可以看到,我们既可以分开来为属性的子属性赋值,也可以总的为属性赋值,如图中所示,"100,50,50"这个字符串值发映的就是被TypeConverter转换了的值,在需要的时候,TypeConverter也会将它转换为YourType.Property_1= 100,YouType.Property2=50......这样的实际类型的实例及赋予它正确的值。

  • 相关阅读:
    (1)java设计模式之简单工厂模式
    QuartZ Cron表达式在java定时框架中的应用
    java.lang.OutOfMemoryError:GC overhead limit exceeded填坑心得
    https实现安全传输的流程
    liunx上运行mybase
    liux之sed用法
    java并发之CyclicBarrier
    java并发之Semaphore
    关于ConcurrentSkipListMap的理解
    java中Iterator和ListIterator的区别与联系
  • 原文地址:https://www.cnblogs.com/think/p/160808.html
Copyright © 2020-2023  润新知