写第五篇的时候,我一步步的加上元数据(特性),使得设计时效果更加好,如对复杂属性应用以下特性,使属性浏览器支持扩展/折叠效果,使你更加容易编辑子属性,但接着我又遇到了问题,所以必须去解决
1.认识默认属性浏览器支持
让我们再认识一下属性,大家知道每个属性都是有类型的,最熟悉就是string,int这些类型了,vs2005属性浏览器对这些属性类型进行了识别, 如下例子
(1)table控件的Height属性,当你设置属性为字符串时,则提示错误信息
(2)当属性类型为Color属性时,属性浏览器为你提供颜色选择器
(3)当属性类型为枚举类型时,属性浏览器则支持下拉框选择
(4)当类型是时间类型,属性浏览器则支持时间选择器
通过上面,我们认识到属性浏览器默认会判别属性类型,当属性值跟属性类型不符时,则会提示错误信息.这里我们还认识到属性浏览器默认为一些属性类型提供了便利
2.属性表现形式的多样性
在定义控件属性时,可以直接这样定义,属性都为字符串形式
Height ="11" BackColor ="Blue"
ForeColor ="#FF8000" > 测试 </ asp:TextBox >
用代码表示则是这样,在后台代码中定义的属性类型必须相对应,BackColor必须为Color类型,否则则会出错,当在页面呈现时,则以字符串形式呈现.
{
//TextBox1.BackColor = "blue";
TextBox1.BackColor = System.Drawing.Color.Red;
TextBox1.BackColor = System.Drawing.Color.FromName("blue");
}
一般常用的类型有String,Int,Boolean,DateTime,Enum等类型,其类型已默认与其相对应的类型转换器关联起来,如Color类默认关联的类型转换器System.Drawing.ColorConverter;FontInto类默认关联的类型转换器System.Drawing.FontConverter类型转换器的基类为System.ComponentModel.TypeConverter,所有的类型转换器都从其派生.。下面我们再来看一个例子,
我们先定义一个复杂属性,用于测试
示例一
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace CustomComponents
6 {
7 public class Name
8 {
9 private string firstName;
10 private string lastName;
11 public String FirstName
12 {
13 get
14 {
15 return firstName;
16 }
17 set
18 {
19 firstName = value;
20 }
21 }
22
23 public String LastName
24 {
25 get
26 {
27 return lastName;
28 }
29 set
30 {
31 lastName = value;
32 }
33 }
34 }
35 }
其中我们输出了Label的几个属性,包括FontInfo这个复杂属性,并且实例化了上面定义的Name类
2
3 <! DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Transitional//EN " " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd " >
4
5 < script runat = " server " >
6
7 void Page_Load( object sender, EventArgs e)
8 {
9 myLabel.Font.Bold = true ;
10 myLabel.Font.Italic = false ;
11 myLabel.Font.Name = " verdana " ;
12 myLabel.Font.Overline = false ;
13 myLabel.Font.Size = 10 ;
14 myLabel.Font.Strikeout = false ;
15 myLabel.Font.Underline = true ;
16
17 Response.Write(myLabel.Font + " <br> " );
18 Response.Write(Label1.Width);
19 Response.Write(Label1.BackColor + " <br> " );
20 Response.Write(Label1.ForeColor + " <br> " );
21
22 CustomComponents.Name n = new CustomComponents.Name();
23 n.FirstName = " 张 " ;
24 n.LastName = " 三 " ;
25 Response.Write(n);
26 }
27
28 </ script >
29 < html xmlns = " http://www.w3.org/1999/xhtml " >
30 < head id = " Head1 " runat = " server " >
31 < title > FontInfo Example </ title >
32 </ head >
33 < body >
34 < form id = " form1 " runat = " server " >
35 < h3 > FontInfo Example </ h3 >
36 < asp:Label id = " myLabel "
37 runat = " server " >
38 </ asp:Label >
39 < br />
40 < br />
41 < asp:Label ID = " Label1 " Width = " 200px " runat = " server " BackColor = " #FF8080 " Text = " Label " ForeColor = " Red " ></ asp:Label >
42 </ form >
43 </ body >
44 </ html >
45
46
下面看看输出结果,如下图
结果是将FontInfo属性和Color属性转换成字符串形式呈现,而我们自定义的Name属性只以其类型呈现,并未呈现其子属性值。再来看看第一点 默认属性浏览器支持和第五篇我们所定义的一个复杂属性CustomComponents.Address,CustomComponents.Address属性同样存在着这样的问题,再对比一下FontInfo属性在属性浏览器的支持,如下图
--------------------------------------------------------------------------
复杂属性CustomComponents.Address无法编辑,只读,而且显示的是其属性类型。复杂属性Font则默认显示了子其属性的值(其默认只显示Names值和Size值,且为只读)。问题来了,我们要根据需要为自定义属性实现类型转换器.
3.自定义属性类型转换器
上面已经说明问题所在了,实现类型转换器,可以将属性类型和字符串类型之间相互转换。下面我们就为解决这个问题而来了解类型转换器,我们还是以 第五篇的那个例子来学习。在说第二点 属性表现形式的多样性的时候已经说过了类型转换器的基类为 System.ComponentModel.TypeConverter,所有的类型转换器都从其派生。下面以第五篇时的例子为基础,我们为Address实现了一个类型转换器,其实现了复杂属性代码的折叠,如下代码
public class Address
{
}
(1) 值翻译的类型转换器
从TypeConverter类派生的自定义类型转换器则需要重写TypeConverter类几个方法,主要目的就是实现自定义属性类型与字符串值之间的转换。你需要了解以下几个方法,这里我们就以Address属性为例子,这样来解释以下方法更好理解。其实可以理解成一来一去的关系,Form,To,相互之间的转换,如下代码:
TypeDescriptor类的方法为静态方法,通过GetConverter方法获取类型转换器,然后通过TypeConverter类的ConvertFromString方法和ConvertToString相互转换类型.
示例二
{
方法
}
自定义好类型转换器后,要与属性相关联起来
public class Address
{
public Address()
:
this(String.Empty, String.Empty,
String.Empty, String.Empty)
{ }
public Address(string street, string city,
string state, string zip)
{
this.street = street;
this.city = city;
this.state = state;
this.zip = zip;
}
.......
}
下面来看下效果,如下图,属性编辑器显示的CustomAddress不再显示其类型了,已将其转化为字符串形式了,如果你设置CustomAddress可写的话,就可以直接编辑CustomAddress属性,但其只有四个子属性,所以当大于5个时就会出错,且格式也不可以乱改,一般情况下都设置其只读。
为了在页面上显示这个CustomAddress属性,还需要为Address类重写一下ToString方法,如下代码
public override string ToString()
{
return ToString(CultureInfo.CurrentCulture);
}
public virtual string ToString(CultureInfo culture)
{
return TypeDescriptor.GetConverter( typeof (Address)).ConvertToString( null , culture, this );
}
#endregion
通过上面重写ToString方法后,输出的CustomAddress属性将不再是其类型,而是以字符串形式呈现,以下以Response.Write方法输出Custom1.CustomAddress输出,如下图
上面讲了最基本的值翻译类型转换器,希望对大家有帮助
(2)向“属性”窗口提供标准值列表的类型转换器
像省份这样的属性,为了方便用户填写,我们往往做成下拉框形式,一个省份里面又有城市,我们往往列出一部分,如果其中数据不符合用户要求的话,用户还可以自己输入,使用类型转换器转换器也可以做到这一点。实现这一效果你需要重写以下方法,我们添加一个属性喜欢的游戏的名称。因为属性为String类型,可以直接从StringConverter 派生
示例三
{
//返回此对象是否支持可以从列表中选取的标准值集
public override bool GetStandardValuesSupported(
ITypeDescriptorContext context)
{
return true;
}
//返回下拉框集合类
public override StandardValuesCollection
GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(new string[]{"传奇",
"魔兽世界",
"龙与地下城"});
}
//标准值的集合是否为独占列表
//默认为flase,为true则表示无法修改列表值
public override bool GetStandardValuesExclusive(
ITypeDescriptorContext context)
{
return false;
}
}
然后与相关属性关联起来
[Description( " 喜欢的游戏 " )]
public String Game
{
get
{
return game;
}
set
{
game = value;
}
}
好了,.下面我们看一下效果,如下图,你可以选择下拉框的值,也可以自己手动输入,跟枚举类型很相似,但枚举类型无法自己修改值.
下一篇:asp.net控件开发基础(10)