6.4 TypeConverter
最后一个在设计时扮演重要角色的是类型换器——TypeConverter。正是由于TypeConverter,设计时控件属性序列化才得以完成,aspx源代码和最终的控件实例的属性才能相互转换,也就是说ForeColor = “#000000”这样的源代码才能在运行时对应成ForeColor = Color.Black。
6.4.1 TypeConverter概述
支持特写类型和字符串类型之间的相互转换是TypeConverter最基本的功能。和类型转换相关的方法包括:CanConvertFrom()、CanConvertTo()、ConvertFrom()和ConvertTo()。对于不变模式(Immutable Pattern)的类型,需要CreateInstance()和GetCreateInstanceSupported()的支持。如果类型有子属性,则需要GetProperties()方法和GetPropertiesSupported()方法的支持。
比如负责将颜色和”#xxxxxx”这样的HTML中的颜色表达方式进行转换的WebColorConverter的ConvertFrom()和ConvertTo()方法实现如下:
public override object ConvertFrom(ITypeDescriptorContext context,
CultureInfo culture, object value)
{
if (value is string)
{
string text = ((string) value).Trim();
Color empty = Color.Empty;
if (string.IsNullOrEmpty(text))
{
return empty;
}
if (text[0] == '#')
{
return base.ConvertFrom(context, culture, value);
}
if (StringUtil.EqualsIgnoreCase(text, "LightGrey"))
{
return Color.LightGray;
}
if (htmlSysColorTable == null)
{
InitializeHTMLSysColorTable();
}
object obj2 = htmlSysColorTable[text];
if (obj2 != null)
{
return (Color) obj2;
}
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context
, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == null)
{
throw new ArgumentNullException("destinationType");
}
if ((destinationType == typeof(string)) && (value != null))
{
Color color = (Color) value;
if (color == Color.Empty)
{
return string.Empty;
}
if (!color.IsKnownColor)
{
StringBuilder builder = new StringBuilder("#", 7);
builder.Append(color.R.ToString("X2",
CultureInfo.InvariantCulture));
builder.Append(color.G.ToString("X2",
CultureInfo.InvariantCulture));
builder.Append(color.B.ToString("X2",
CultureInfo.InvariantCulture));
return builder.ToString();
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
6.4.2 支持标准值
对于一些有固定取值范围的属性,提供一个标准值的选择列表比单纯的输入框要方便得多,比如枚举类型的属性,或颜色属性。有些属性的值只能从几个值中选择一个,比如BorderStyle属性,有些属性的值有一些标准值,也有很多变数,比如ForeColor属性,如图6-21所示。


图6-21 具有标准值的属性
TypeConvert除了为特定类型提供与字符串类型的转换支持,还负责为特定类型提供标准值集合。
如果一种数据类型有标准值,则其关联的TypeConvert的GetStandardValuesSupported()方法需要返回true,并且在GetStandardValues()方法中提供标准值列表。
如果一种数据类型的值只能是标准值之一,则其关联的TypeConvert方法的GetStandardValuesExclusive()返回true。
回顾TabControl的任务列表,我们为SelectedTabIndex属性提供了一种以下拉列表的方式选择值的方式,当时我们是在设计器属性上关联了SelectedIndexConvert转换器,该类型转换器类的代码如下:
public class SelectedIndexConverter:Int32Converter
{
public override bool GetStandardValuesExclusive(
ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesSupported(
ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection
GetStandardValues (ITypeDescriptorContext context)
{
if (context != null)
{
TabControl control = context.Instance as TabControl;
if (control == null)
{
control = (context.Instance as
TabControlDesigner.TabControlActionList)
.Component as TabControl;
}
if (control != null)
{
List<int> values = new List<int>(control.Controls.Count);
for (int i = 0; i < control.Controls.Count; i++)
{
values.Add(i);
}
return new StandardValuesCollection(values);
}
}
return base.GetStandardValues(context);
}
}
SelectedIndexConvert也关联了TabControl的SelectedTabIndex,所以该属性在属性窗口中也提供了标准值选择,如图6-22所示。

图6-22 属性窗口中的SelectedTabIndex属性







