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

本文围绕TypeConverter类型转换器展开。先回顾上篇探讨的控件开发与propertyGrid的关系,提出对控件属性分类显示的思考。接着列举了System.Web.UI.WebControls和System.ComponentModel命名空间下的多种转换器,重点介绍不同类型与String的转换实现,还说明了调用基类方法的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TypeConverter

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

“另起炉灶”


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

None.gif [PropertyTab(typeof(YourPropertyTab), PropertyTabScope.Component)]
None.gif 
public class YourControlClass
ExpandedBlockStart.gifContractedBlock.gif 
dot.gif{
InBlock.gif  dot.gifdot.gif
ExpandedBlockEnd.gif }

None.gif

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

None.gifinternal class YourPropertyTab : PropertyTab 
ExpandedBlockStart.gifContractedBlock.gif 
dot.gif{
InBlock.gif  
internal YourControlType target;
InBlock.gif
InBlock.gif    
public override string TabName 
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif   
get 
ExpandedSubBlockStart.gifContractedSubBlock.gif   
dot.gif{
InBlock.gif    
return "选项卡的名字";
ExpandedSubBlockEnd.gif   }

ExpandedSubBlockEnd.gif  }

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

ExpandedSubBlockEnd.gif  }

InBlock.gif
InBlock.gif  
public override bool CanExtend(object o) 
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif   
return o is YourControlType;//什么时候用这个Tab
ExpandedSubBlockEnd.gif
  }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif          
public override PropertyDescriptorCollection GetProperties(object component, Attribute[] attrs) dot.gif{
InBlock.gif              
return GetProperties(null, component, attrs);
ExpandedSubBlockEnd.gif         }

InBlock.gif
InBlock.gif 
ExpandedSubBlockStart.gifContractedSubBlock.gif  
/**//// 主要的逻辑.  在这里定义如何实现分Tab显示
InBlock.gif  
InBlock.gif  
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object component, Attribute[] attrs)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif   YourControlType uc 
= component as YourControlType;
InBlock.gif
InBlock.gif   
if (uc == null
ExpandedSubBlockStart.gifContractedSubBlock.gif   
dot.gif{
InBlock.gif    
//以下代码实现不是YourControlType时,使用本身类型的逻辑。 
InBlock.gif
    TypeConverter tc = TypeDescriptor.GetConverter(component);
InBlock.gif    
if (tc != null
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif     
return tc.GetProperties(context, component, attrs);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else 
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif     
return TypeDescriptor.GetProperties(component, attrs);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif   }

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

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

InBlock.gif
InBlock.gif   
public override Type PropertyType//属性的类型 
ExpandedSubBlockStart.gifContractedSubBlock.gif
   dot.gif{
InBlock.gif    
get 
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif     
return typeof(int);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif   }

InBlock.gif   属性关联对象是什么类型
InBlock.gif   
public override Type ComponentType
ExpandedSubBlockStart.gifContractedSubBlock.gif   
dot.gif{
InBlock.gif    
get 
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif     
return typeof(YourControlType);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif   }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif   
public override bool IsReadOnly dot.gif{getdot.gif{return false;}}
InBlock.gif  
InBlock.gif   
public override object GetValue(object o) //和关联对象的什么属性相关
ExpandedSubBlockStart.gifContractedSubBlock.gif
   dot.gif{
InBlock.gif    
return ((YourControlType)o).Proterty_1;
ExpandedSubBlockEnd.gif   }

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

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif   
public override void ResetValue(object o)dot.gif{}//望文生义
InBlock.gif

InBlock.gif
InBlock.gif   
public override bool CanResetValue(object o) //望文生义
ExpandedSubBlockStart.gifContractedSubBlock.gif
   dot.gif{
InBlock.gif    
return false;
ExpandedSubBlockEnd.gif   }

ExpandedSubBlockStart.gifContractedSubBlock.gif   
/**////Does this property participate in code generation?
InBlock.gif   public override bool ShouldSerializeValue(object o) 
ExpandedSubBlockStart.gifContractedSubBlock.gif   
dot.gif{
InBlock.gif    
return false;
ExpandedSubBlockEnd.gif   }

ExpandedSubBlockEnd.gif  }

InBlock.gif 
ExpandedBlockEnd.gif }

None.gif
None.gif


类型转换器


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

None.gif
public class YourControl
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif [TypeConverter(
typeof(YourConverter))]
InBlock.gif 
public YourPropertyClass ExpandableProperty
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif  dot.gifdot.gif.
ExpandedSubBlockEnd.gif }

ExpandedBlockEnd.gif}

None.gif

 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怎么样来转换。
 下面这个实例应该就得达到这个目的。

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

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

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

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

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

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

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

InBlock.gif  
//以下的例子实现"20,30"转换成new YourType(20,30),分两步,分隔,变Int
InBlock.gif
                string[] parts = s.Split(culture.TextInfo.ListSeparator[0]);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                
if (parts.Length != 2dot.gif{
InBlock.gif                    
throw new ArgumentException("Invalid YourType""value");
ExpandedSubBlockEnd.gif                }

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

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

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

ExpandedSubBlockEnd.gif            }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (destinationType == typeof(string)) dot.gif{//转成string的逻辑
ExpandedSubBlockStart.gifContractedSubBlock.gif
                if (value == nulldot.gif{
InBlock.gif                    
return String.Empty;
ExpandedSubBlockEnd.gif                }

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

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

InBlock.gif
InBlock.gif                MemberInfo mi 
= null;//通过对YourType MetaData的访问得到它的构造函数
InBlock.gif
                object[] args = null;
InBlock.gif
InBlock.gif                YourType yourType 
= (YourType)value;
ExpandedSubBlockStart.gifContractedSubBlock.gif                
if (yourType.IsEmpty) dot.gif{
InBlock.gif                    mi 
= typeof(YourType).GetConstructor(new Type[0]);
ExpandedSubBlockEnd.gif                }

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

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                
if (mi != nulldot.gif{
InBlock.gif                    
return new InstanceDescriptor(mi, args);//根据选择的构造子和参数建立实例
ExpandedSubBlockEnd.gif
                }

ExpandedSubBlockStart.gifContractedSubBlock.gif                
else dot.gif{
InBlock.gif                    
return null;
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

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

ExpandedBlockEnd.gif    }

None.gif
None.gif

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值