ASP.NET控件开发基础之类型转换器浅析

开发 后端
ASP.NET控件开发基础之类型转换器是在一步步的加上元数据(特性)之后,使得设计时效果更加好,如对复杂属性应用以下特性,使属性浏览器支持扩展/折叠效果,使你更加容易编辑子属性,但接着我又遇到了问题,所以必须去解决,那么本文ASP.NET控件开发基础之类型转换器就向你讲述这方面的内容。

ASP.NET控件开发基础之类型转换器1.认识默认属性浏览器支持

让我们再认识一下属性,大家知道每个属性都是有类型的,最熟悉就是string,int这些类型了,VS2005属性浏览器对这些属性类型进行了识别,
如下例子

(1)table控件的Height属性,当你设置属性为字符串时,则提示错误信息

提示错误信息 

(2)当属性类型为Color属性时,属性浏览器为你提供颜色选择器

类型为Color属性 

(3)当属性类型为枚举类型时,属性浏览器则支持下拉框选择

类型为枚举类型时 

(4)当类型是时间类型,属性浏览器则支持时间选择器

类型是时间类型 

通过上面,我们认识到属性浏览器默认会判别属性类型,当属性值跟属性类型不符时,则会提示错误信息.这里我们还认识到属性浏览器默认为一些属性类型提供了便利

ASP.NET控件开发基础之类型转换器2.属性表现形式的多样性

在定义控件属性时,可以直接这样定义,属性都为字符串形式

  1. ﹤asp:TextBox ID="TextBox1" runat="server"   
  2.         Height="11" BackColor="Blue"   
  3.         ForeColor="#FF8000"﹥测试﹤/asp:TextBox﹥ 

用代码表示则是这样,在后台代码中定义的属性类型必须相对应,BackColor必须为Color类型,否则则会出错,当在页面呈现时,则以字符串形式呈现.

  1. protected void Page_Load(object sender, EventArgs e)  
  2.  
  3.    //TextBox1.BackColor = "blue";  
  4.    TextBox1.BackColor = System.Drawing.Color.Red;  
  5.    TextBox1.BackColor = System.Drawing.Color.FromName("blue");  

通过上面,我们认识到属性类型需要转换,这里便要引出我们所要讲的话题,类型转换器.

例如,当BackColor="Blue" 时,则会激活一个类型转换器实例将字符串值转换成声明的类型(即将"blue"转换成Color类型,然后赋给BackColor.

.net类库中的基本类型和许多类型都有与其相关联的类型转换器.

一般常用的类型有String,Int,Boolean,DateTime,Enum等类型,其类型已默认与其相对应的类型转换器关联起来.

Color类默认关联的类型转换器System.Drawing.ColorConverter

FontInto类默认关联的类型转换器System.Drawing.FontConverter

类型转换器的基类为System.ComponentModel.TypeConverter,所有的类型转换器都从其派生.

下面我们再来看一个例子,

我们先定义一个复杂属性,用于测试

示例一

  1.  using System;  
  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.   }  

再看aspx文件

其中我们输出了Label的几个属性,包括FontInfo这个复杂属性,并且实例化了上面定义的Name类

  1. ﹤%@ Page Language="C#" %﹥  
  2.  
  3. ﹤!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  4. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"﹥  
  5.  
  6. ﹤script runat="server"﹥  
  7.  
  8.   void Page_Load(object sender, EventArgs e)  
  9.   {  
  10.     myLabel.Font.Bold = true;  
  11.     myLabel.Font.Italic = false;  
  12.     myLabel.Font.Name = "verdana";  
  13.     myLabel.Font.Overline = false;  
  14.     myLabel.Font.Size = 10;  
  15.     myLabel.Font.Strikeout = false;  
  16.     myLabel.Font.Underline = true;  
  17.     
  18.     Response.Write(myLabel.Font + "﹤br﹥");  
  19.     Response.Write(Label1.Width);  
  20.     Response.Write(Label1.BackColor+"﹤br﹥");  
  21.     Response.Write(Label1.ForeColor + "﹤br﹥");  
  22.  
  23.     CustomComponents.Name n = new CustomComponents.Name();  
  24.     n.FirstName = "张";  
  25.     n.LastName = "三";  
  26.     Response.Write(n);  
  27.   }  
  28.  
  29. ﹤/script﹥  
  30. ﹤html xmlns="http://www.w3.org/1999/xhtml" ﹥  
  31. ﹤head id="Head1" runat="server"﹥  
  32.     ﹤title﹥FontInfo Example﹤/title﹥  
  33. ﹤/head﹥  
  34.   ﹤body﹥  
  35.     ﹤form id="form1" runat="server"﹥  
  36.     ﹤h3﹥FontInfo Example﹤/h3﹥  
  37.       ﹤asp:Label id="myLabel"   
  38.         runat="server" ﹥  
  39.       ﹤/asp:Label﹥  
  40.         ﹤br /﹥  
  41.         ﹤br /﹥  
  42.         ﹤asp:Label ID="Label1" Width="200px" runat="server"   
  43.                     BackColor="#FF8080" Text="Label" ForeColor="Red"﹥  
  44.           ﹤/asp:Label﹥  
  45.     ﹤/form﹥  
  46.   ﹤/body﹥  
  47. ﹤/html﹥ 

下面看看输出结果,如下图

输出结果 

结果是将FontInfo属性和Color属性转换成字符串形式呈现,而我们自定义的Name属性只以其类型呈现,并未呈现其子属性值.
再来看看***点默认属性浏览器支持和第五篇我们所定义的一个复杂属性CustomComponents.Address,
CustomComponents.Address属性同样存在着这样的问题,再对比一下FontInfo属性在属性浏览器的支持,如下图

FontInfo属性 

---------------------------------------------------------------------------

FontInfo属性 

复杂属性CustomComponents.Address无法编辑,只读,而且显示的是其属性类型.
复杂属性Font则默认显示了子其属性的值(其默认只显示Names值和Size值,且为只读)

问题来了,我们要根据需要为自定义属性实现类型转换器.

ASP.NET控件开发基础之类型转换器3.自定义属性类型转换器

上面已经说明问题所在了,实现类型转换器,可以将属性类型和字符串类型之间相互转换.

下面我们就为解决这个问题而来了解类型转换器,我们还是以第五篇的那个例子来学习

在说第二点属性表现形式的多样性的时候已经说过了

类型转换器的基类为System.ComponentModel.TypeConverter,所有的类型转换器都从其派生.

下面以第五篇时的例子为基础

我们为Address实现了一个类型转换器,其实现了复杂属性代码的折叠,如下代码

  1. [TypeConverter(typeof(ExpandableObjectConverter))]  
  2.     public class Address  
  3.     {  

System.ComponentModel.ExpandableObjectConverter 类也是从TypeConverter类派生

所以当自定义复杂类型的类型转换器时,则可从ExpandableObjectConverter 类派生

如果你定义的属性不是复杂属性,则可以直接从TypeConverter类派生

(1) 值翻译的类型转换器

从TypeConverter类派生的自定义类型转换器则需要重写TypeConverter类几个方法,主要目的就是实现自定义属性类型与字符串值之间的转换.

你需要了解以下几个方法,这里我们就以Address属性为例子,这样来解释以下方法更好理解.

其实可以理解成一来一去的关系,Form,To,相互之间的转换,如下代码:

TypeDescriptor类的方法为静态方法,通过GetConverter方法获取类型转换器
然后通过TypeConverter类的ConvertFromString方法和ConvertToString相互转换类型.

示例二

  1. public class AddressConverter : ExpandableObjectConverter  
  2.    {  
  3.        方法#region 方法  
  4.        // 返回值能否将String类型转换为Address类型  
  5.        //sourceType表示要转换的类型  
  6.        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)  
  7.        {  
  8.            if (sourceType == typeof(string))  
  9.            {  
  10.                return true;  
  11.            }  
  12.            return base.CanConvertFrom(context, sourceType);  
  13.        }  
  14.  
  15.        // 返回值能否将Address类型转换为String类型  
  16.        //sourceType表示要转换到的类型  
  17.        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)  
  18.        {  
  19.            if (destinationType == typeof(string))  
  20.            {  
  21.                return true;  
  22.            }  
  23.            return base.CanConvertTo(context, destinationType);  
  24.        }  
  25.  
  26.        //将String类型转换为Address类型  
  27.        //value为要转换的类型  
  28.        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture,  
  29.            object value)  
  30.        {  
  31.            if (value == null)  
  32.            {  
  33.                return new Address();  
  34.            }  
  35.  
  36.            if (value is string)  
  37.            {  
  38.                string s = (string)value;  
  39.                if (s.Length == 0)  
  40.                {  
  41.                    return new Address();  
  42.                }  
  43.  
  44.                string[] parts = s.Split(culture.TextInfo.ListSeparator[0]);  
  45.  
  46.                if (parts.Length != 4)  
  47.                {  
  48.                    throw new ArgumentException("Invalid Address""value");  
  49.                }  
  50.                //返回指定类型转换器  
  51.                TypeConverter stringConverter = TypeDescriptor.GetConverter(typeof(string));  
  52.                return new Address((string)stringConverter.ConvertFromString(context, culture, parts[0]),  
  53.                    (string)stringConverter.ConvertFromString(context, culture, parts[1]),  
  54.                    (string)stringConverter.ConvertFromString(context, culture, parts[2]),  
  55.                    (string)stringConverter.ConvertFromString(context, culture, parts[3]));  
  56.  
  57.            }  
  58.  
  59.  
  60.            return base.ConvertFrom(context, culture, value);  
  61.        }  
  62.  
  63.        //将Address类型转换为String类型  
  64.        //value为要转换的类型  
  65.        public override object ConvertTo(  
  66.            ITypeDescriptorContext context,  
  67.            CultureInfo culture, object value, Type destinationType)  
  68.        {  
  69.            if (value != null)  
  70.            {  
  71.                if (!(value is Address))  
  72.                {  
  73.                    throw new ArgumentException(  
  74.                        "Invalid Address""value");  
  75.                }  
  76.            }  
  77.  
  78.            if (destinationType == typeof(string))  
  79.            {  
  80.                if (value == null)  
  81.                {  
  82.                    return String.Empty;  
  83.                }  
  84.  
  85.                Address ad = (Address)value;  
  86.  
  87.                TypeConverter stringConverter = TypeDescriptor.GetConverter(typeof(string));  
  88.                return String.Join(culture.TextInfo.ListSeparator,  
  89.                    new string[] {  
  90.                                     stringConverter.ConvertToString(context, culture, ad.Street),  
  91.                                     stringConverter.ConvertToString(context, culture, ad.City),  
  92.                                     stringConverter.ConvertToString(context, culture, ad.State),  
  93.                                     stringConverter.ConvertToString(context, culture, ad.Zip)  
  94.                                 });  
  95.            }  
  96.            return base.ConvertTo(context, culture, value,  
  97.                destinationType);  
  98.        }  
  99.        #endregion  
  100.  
  101.    } 

自定义好类型转换器后,要与属性相关联起来

  1. [TypeConverter(typeof(AddressConverter))]  
  2. public class Address  
  3. {  
  4.       
  5.     public Address()  
  6.         :  
  7.         this(String.Empty, String.Empty,  
  8.         String.Empty, String.Empty)  
  9.     { }  
  10.  
  11.     public Address(string street, string city,  
  12.         string state, string zip)  
  13.     {  
  14.         this.street = street;  
  15.         this.city = city;  
  16.         this.state = state;  
  17.         this.zip = zip;  
  18.     }  
  19.       .......  

下面来看下效果,如下图,属性编辑器显示的CustomAddress不再显示其类型了,已将其转化为字符串形式了,如果你设置CustomAddress可写的话,就可以直接编辑CustomAddress属性,但其只有四个子属性,所以当大于5个时就会出错,且格式也不可以乱改,一般情况下都设置其只读.

 

为了在页面上显示这个CustomAddress属性,还需要为Address类重写一下ToString方法,如下代码

  1. #region方法  
  2.         public override string ToString()  
  3.         {  
  4.             return ToString(CultureInfo.CurrentCulture);  
  5.         }  
  6.  
  7.         public virtual string ToString(CultureInfo culture)  
  8.         {  
  9.             return TypeDescriptor.GetConverter(typeof(Address)).ConvertToString(null, culture, this);  
  10.         }  
  11.  
  12.         #endregion  

通过上面重写ToString方法后,输出的CustomAddress属性将不再是其类型,而是以字符串形式呈现,以下以
Response.Write方法输出Custom1.CustomAddress输出,如下图

 

上面讲了最基本的值翻译类型转换器,希望对大家有帮助

(2)向“属性”窗口提供标准值列表的类型转换器

像省份这样的属性,为了方便用户填写,我们往往做成下拉框形式,一个省份里面又有城市,我们往往列出一部分,如果其中数据不符合用户要求的话,用户还可以自己输入,使用类型转换器转换器也可以做到这一点.

实现这一效果你需要重写以下方法,我们添加一个属性喜欢的游戏的名称
因为属性为String类型,可以直接从StringConverter 派生

示例三

  1. public class GameConverter : StringConverter   
  2.  
  3.    {  
  4.        //返回此对象是否支持可以从列表中选取的标准值集  
  5.        public override bool GetStandardValuesSupported(  
  6.                           ITypeDescriptorContext context)  
  7.        {  
  8.            return true;  
  9.        }  
  10.       //返回下拉框集合类  
  11.       public override StandardValuesCollection  
  12.                     GetStandardValues(ITypeDescriptorContext context)  
  13.       {  
  14.           return new StandardValuesCollection(new string[]{"传奇",   
  15.                                                     "魔兽世界",   
  16.                                                     "龙与地下城"});  
  17.       }  
  18.       //标准值的集合是否为独占列表  
  19.       //默认为flase,为true则表示无法修改列表值  
  20.       public override bool GetStandardValuesExclusive(  
  21.                           ITypeDescriptorContext context)  
  22.       {  
  23.           return false;  
  24.       }  
  25.    } 

然后与相关属性关联起来

  1. [TypeConverter(typeof(GameConverter))]  
  2.         [Description("喜欢的游戏")]  
  3.         public String Game  
  4.         {  
  5.             get 
  6.             {  
  7.                 return game;  
  8.             }  
  9.             set 
  10.             {  
  11.                 game = value;  
  12.             }  
  13.         } 

好了,.下面我们看一下效果,如下图,你可以选择下拉框的值,也可以自己手动输入,跟枚举类型很相似,但枚举类型无法自己修改值.

选择下拉框的值 

这一篇主要介绍了类型转换器的基本使用,希望对大家有所帮助,在写的同时我也学到了很多,讲的比较基础,什么时候我懂了可以再补充,水平有限呀.这一篇就写到这里,很高兴,我已经写到第9篇了,我会继续写下去的,也希望大家喜欢.

ASP.NET控件开发基础之类型转换器的相关内容就向你介绍到这里,希望对你了解ASP.NET控件开发基础之类型转换器有所帮助。

【编辑推荐】

  1. ASP.NET控件开发基础之RenderContents使用浅析
  2. ASP.NET自定义控件属性浅析
  3. ASP.NET控件开发基础之自定义控件样式属性浅析
  4. ASP.NET控件开发基础之复合控件浅析
  5. ASP.NET控件开发基础之复合控件事件处理浅析
责任编辑:仲衡 来源: 博客园
相关推荐

2009-08-06 18:18:27

ASP.NET控件开发ASP.NET复合控件

2009-08-06 13:08:23

ASP.NET控件开发

2009-08-07 15:24:16

ASP.NET模板控件

2009-08-07 17:49:44

控件设计器

2009-08-04 14:56:34

ASP.NET数据类型

2009-08-06 09:18:01

ASP.NET自定义控ASP.NET控件开发

2009-08-07 15:34:15

ASP.NET数据绑定

2009-08-06 18:32:00

ASP.NET控件开发ASP.NET复合控件

2009-07-27 17:25:53

ASP.NET验证控件

2009-08-05 17:11:51

ASP.NET控件开发ASP.NET服务器控

2009-08-06 15:21:45

ASP.NET控件开发RenderConte

2009-08-06 17:52:45

ASP.NET控件开发自定义控件

2009-08-03 18:00:00

ASP.NET服务器控

2009-07-28 09:32:41

ASP.NET自定义控

2009-08-10 14:25:33

ASP.NET服务器控

2009-08-06 10:49:45

ASP.NET服务器控

2009-08-07 14:05:21

ASP.NET控件

2009-08-05 18:46:21

ComboBox显示ASP.NET控件开发

2009-08-07 10:34:56

ASP.NET控件开发

2009-08-05 18:32:28

HtmlTextWriASP.NET控件开发
点赞
收藏

51CTO技术栈公众号