浅谈ASP.NET内部机制(八)
前言:之前几篇文章写了有关视图的知识,也讲述了如何实现IStateManager接口。本篇将讲解如何实现自定义转换器。当然了,有大量的代码演示!本篇算是有关视图机制的终结篇,还会讲解有关ControlStatel控件状态的实现。
有个小插曲,其实之前我已经把文章写了一大半,不知道怎么回事,IE出了问题,自动关闭了,真是心痛阿,现在得重写一遍。我想每个写博文的朋友都有这样的经历吧,写一篇文章真的很不容易!
系列文章链接:
浅谈ASP.NET的内部机制(一)
浅谈ASP.NET的内部机制(二)
浅谈ASP.NET内部机制(三)
浅谈ASP.NET内部机制(四)
浅谈ASP.NET内部机制(五)
浅谈ASP.NET内部机制(六)
浅谈ASP.NET内部机制(七)
浅谈ASP.NET内部机制(八)
在上篇中,我们讲解了如何在一个自定义控件中保存自定义类的属性,我现在再次把代码贴出来,免得大家去翻页。
Code
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
namespace CustomComponents
{
/**//**//**//**//**//**//**//**//**//**//**//**//**//**//**//// <summary>
///MyLogin 的摘要说明
/// </summary>
public class MyLogin:WebControl
{
属性属性属性属性#region 属性
public string UserName
{
get
{
return ViewState["UserName"] != null ? (string)ViewState["UserName"] : "UserName";
}
set
{
ViewState["UserName"] = value;
}
}
public string UserPassword
{
get
{
return ViewState["UserPassword"] != null ? (string)ViewState["UserPassword"] : "UserPassword";
}
set
{
ViewState["UserPassword"] = value;
}
}
#endregion
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Table;
}
}
protected override void RenderContents(HtmlTextWriter writer)
{
//显示用户名
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write(UserName);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtUserName");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
//显示用户密码
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write(UserPassword);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtPassword");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
//显示登录按钮
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Id, "btnSubmit");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
writer.AddAttribute(HtmlTextWriterAttribute.Value, "Login");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
}
}
上面的代码开发了一个类似与Login的控件,然后我们也开发一个自定义的Person类:如下:
Code
public class Person
{
private string address;
public string Address
{
get{return address;}
set[address=value;}
}
}
然后我们使得Login控件有一个Person类型的属性(上面的代码没有写出来,但是大家要知道),用来保存一些其他的用户信息,而且我们还让Person类实现了IStateManager接口,用来在保存自身的状态。(大家不清楚,最好可以先看看之前的一篇文章)。
其实使得自定义类保存状态的方法除了实现IStateManager接口之外,还有其他的方法,如本篇要讲述的实现继承自TypeConvert的自定义类型转换器。
在.NET中要做一件事,其实有很多不同的解决的方法。
下面我们就来看看,我们怎么来实现自定义的转换器。
其实实现一个自定义的类型转换器不难,简单的说就是:继承TypeConvert,然后重写几个方法就OK,而且重写方法的套路很固定,和之前实现IStateManager接口的一样,很多时候可以照搬套用。
下面就来看看我们要重写的四个方法,一一讲解:
Code
public virtual bool CanConvertFrom(ITypeDescriptorContext context,Type sourceType)
public override bool CanConvertTo(ITypeDescriptorContext context,Type destinationType)
上面两个方法看起来很“对称”。实现起来也不难。
我们知道我们的状态机制基本可以理解为:从服务器把一些状态序列化为字符串然后发送到客户端,之后客户端把状态有回传到服务器,服务器然后反序列化那些保存状态的字符串,然后把这些状态还原,然后再赋给新的对象。
所以上面两个方法就不难理解了:
CanConvertFrom方法就是判断客户端到服务器的字符串是否可以被还原转换为对应的类型。本例中就是判断客户端发送的状态字符串是否可以转换为Person对象的实例。
同理了,CanConvertTo就是判断服务器的Person的状态是否可以转换为字符串了。
下面就来看看另外的两个方法:
Code
public override object ConvertFrom(ITypeDescriptorContext context,CultureInfo culture, object value)
public override object ConvertTo(ITypeDescriptorContext context,CultureInfo culture, object value, Type destinationType)
和之前的理解一样,这个两个方法就是实际用来转换的,ConvertForm就是把客户端发送来的状态字符串还原对应的类型,ConvertTo就是把服务器端的Person状态转换为字符串。
下面就实际的动手来实现自定义的转换器CustomPersonConverter,继承自TypeConvert;
Code
public class CustomPersonConverter:TypeConvert
我们自定义的转换器实际上就是用来把Person类进行转换的,为了使得例子更加的实际一点,我们在Person中多添加一个属性,代码如下:
Code
public class Person
{
private string address;
public string Address
{
get{return address;}
set{address=value;}
}
private string cardNum;
public string CardNum
{
get{return cardNum;}
set{cardNum=value;}
}
}
下面就开始重写上面的四个方法,一点都不难,很多的代码可以套用的:
Code
public override bool CanConvertFrom(ITypeDescriptorContext context,Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
上面的代码就是判断,sourceType就是从客户端发来的状态字符串。
Code
public override bool CanConvertTo(ITypeDescriptorContext context,Type destinationType)
{
if (destinationType == typeof(string))
return true;
return base.CanConvertTo(context, destinationType);
}
上面代码中的destinationType在本例中就是Person类最后转换成的字符串。
可以说上面两个方法在任何实现TypeConvert的自定义转换器中的写法一样的,套用就行了。
实际起作用的是后面的两个方法,也很好写的。
Code
public override object ConvertTo(ITypeDescriptorContext context,CultureInfo culture, object value, Type destinationType)
{
if (value != null && !(value is DefaultTemplateManager2))
throw new ArgumentException();
if (destinationType == typeof(string))
{
if (value == null)
return string.Empty;
Person myPerson= value as Person;
string ss = string.Join(“,”,
new string[] {
myPerson.Address,
myPerson.CardNum
});
return ss;
}
return base.ConvertTo(context, culture, value, destinationType);
}
上面的方法实际上就是把Person的一个实例myPerson转换为字符串,之后就发送给客户端的。
Code
public override object ConvertFrom(ITypeDescriptorContext context,CultureInfo culture, object value)
{
if (value == null)
return new DefaultTemplateManager2();
string svalue = value as string;
if (svalue == null)
return base.ConvertFrom(context, culture, value);
string[] myPersonString= svalue.Split(new char[] { ‘,’ });
if (templateTypes.Length != 2)
throw new ArgumentException();
Person myPerson=new Person();
myPerson.Address=myPersonString[0];
myPeron.CardNum=myPersonString[1];
return myPerson;
}
上面的代码就是重建myPerson对象。
到这里我们的自定义的转换器类就完成了。大家也看到了开发不是很难。
下面我们就来看看怎么用这个自定义转换器。
首先,在我们的Person类上加上如下Attribute:
Code
[TypeConverter(typeof(CustomPersonConverter))]
public class Person
因为在Login控件中有一个类型为Person的属性PersonInfo,如下:
Code
private Person personInfo;
public Person PersonInfo
{
//.时间关系,我省略了
}
然后再在Login控件中重写几个方法就OK,和上一篇差不多的,如下:
Code
protected override void TrackViewState()
{
if( personInfo!= null)
{
TypeConverter converter = TypeDescriptor.GetConverter(personInfo!);
if (converter.CanConvertTo(typeof(string)))
{
string svalue = (string)converter.ConvertTo(personInfo,typeof(string));
ViewState[“PersonInfo”] = svalue;
}
}
base.TrackViewState();
}
Code
protected override object SaveViewState()
{
if (personInfo!= null)
{
TypeConverter converter = TypeDescriptor.GetConverter(personInfo);
if (converter.CanConvertTo(typeof(string)))
{
string newValue = (string)converter.ConvertTo(personInfo,
typeof(string));
string oldValue = (string)ViewState[“PersonInfo”];
if (newValue != oldValue)
ViewState[“PersonInfo”] = newValue;
}
}
return base.SaveViewState();
}
Code
protected override void LoadViewState(object savedState)
{
string svalue = ViewState[“PersonInfo”] as string;
if (svalue != null)
{
TypeConverter converter =
TypeDescriptor.GetConverter(typeof(Person));
if (converter.CanConvertFrom(typeof(string)))
personInfo=(Person)converter.ConvertFrom(svalue);
}
else
base.LoadViewState(savedState);
}
今天到这里!