在上一篇ViewState——自定义状态管理(一) 中我在自定义属性的类里面加入了一个重写的ToString方法和一个从字符串获取一个该类型实例的一个构造函数。大家可能会觉得谈到自定义属性的状态管理却不提及TypeConverter(Attribute),有些神奇。好吧,下面就来说说TypeConverter。
先看下MSDN的解释:提供一种将值的类型转换为其他类型以及访问标准值和子属性的统一方法。
在上一篇我自己写了两个方法而没有使用TypeConverter就是想从一方面说明TypeConverter的作用(从这一点来说就是类型转换)。当然TypeConverter还有很多其他用途,比方说提供一组标准值什么的。因此在通常情况下我们都使用TypeConverter来完成这些工作(即使仅仅是只处理类型转换的问题)。就个人理解,TypeConverter是我们在属性窗体为控件属性输入值时使用的,它可以将特定的输入转换为特定的类型。您可能会说,其实我们自己也可以调用它来做些操作啊,对,这样也可以。
首先,修改下以前的例子:
ViewStateManagement4
namespace Controls
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.ComponentModel;
using System.Globalization;
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public class ViewStateManagement4 : Control
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
private CustomProperty4 m_Property;
[DesignerSerializationVisibility( DesignerSerializationVisibility.Content )]
public CustomProperty4 Property
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
get
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (m_Property == null)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
m_Property = new CustomProperty4();
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return m_Property;
}
//set
//{
//}
}
protected override void LoadViewState(object savedState)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (savedState is Pair)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
Pair properties = (Pair)savedState;
base.LoadViewState(properties.First);
m_Property = (CustomProperty4)properties.Second;
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
base.LoadViewState(savedState);
}
}
protected override object SaveViewState()
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
object baseState = base.SaveViewState();
if (Property != null)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
return new Pair( baseState, Property);
}
return baseState;
}
protected override void TrackViewState()
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
base.TrackViewState();
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
protected override void Render(HtmlTextWriter writer)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
//CustomTypeConverter c = new CustomTypeConverter();
//c.ConvertTo(null, CultureInfo.InvariantCulture, Property, typeof(string));
//writer.Write(c.ConvertTo(null, CultureInfo.InvariantCulture, Property, typeof(string)));
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
writer.Write(TypeDescriptor.GetConverter(Property.GetType()).ConvertTo(null, CultureInfo.InvariantCulture, Property, typeof(string)));
}
}
[TypeConverter(typeof( CustomTypeConverter))]
public class CustomProperty4
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
private string m_Property1;
private string m_Property2;
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public string Property2
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
get
{ return m_Property2; }
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
set
{ m_Property2 = value; }
}
public string Property1
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
get
{ return m_Property1; }
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
set
{ m_Property1 = value; }
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
}
public class CustomTypeConverter : ExpandableObjectConverter
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
/**//// <summary>
/// 指定是否可以从特定的类型进行转换
/// </summary>
/// <param name="context"></param>
/// <param name="sourceType"></param>
/// <returns>true:可以;false:不可以</returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
//如果源类型是字符串
if (sourceType == typeof(string))
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return false;
}
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
/**//// <summary>
/// 指定是否可以转换为特定类型
/// </summary>
/// <param name="context"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (destinationType == typeof(string))
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return false;
}
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
/**//// <summary>
/// 从特定值进行转换
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value"></param>
/// <returns></returns>
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (value is string)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
string str = (string)value;
string[] propertyValues = str.Split(';');
if (propertyValues.Length == 2)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
CustomProperty4 obj = new CustomProperty4();
obj.Property1 = propertyValues[0];
obj.Property2 = propertyValues[1];
return obj;
}
}
return base.ConvertFrom(context, culture, value);
}
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
/**//// <summary>
/// 转换成特定值
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (value is CustomProperty4)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
CustomProperty4 obj = (CustomProperty4)value;
return obj.Property1 + ";" + obj.Property2;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
这里我自定义了一个类型转换的Attribute(它所完成的任务很简单,仅仅是类型之间的转换)。注意在Render里面注释掉的代码,事实上它的效果和后面的那行代码完全一样,但是在MSDN有这样一句话:【决不要直接访问类型转换器。而应通过使用 TypeDescriptor 访问适当的转换器】。至于原因我现在也不清楚,就暂时先知其然吧。这样我们就在类型转换Attribute的帮助下完成了我们的视图状态的保存工作。
当然提到视图状态的保存就不得不提到另外一位高人:IStateManager,当我们让复杂属性的类从该接口继承时,我们也可以实现视图状态的保存。
在讨论这个接口前,我想先讨论下另外一个问题:ViewState里面可以直接存储哪些类型的信息?
抛开标记为可序列化的不谈,事实上ViewState里面可以存储的内容都是指定了TypeConverter或者从其派生的Attribute的类型。您可能会问那哪些基本的类型呢(如int,string),我们平时在将这些数据放入ViewState并没有定义这样的Attribute啊。是的,我们没有做这些,但是ms做了,这些基本类型都已经有了相应的类型转换Attribute。
好,回到正题,先来考虑一个简单的例子。假如我们又定义了一个类型CustomProperty5,照旧他还是只包含两个基本类型(string)的属性Property1和Property2。那么是不是可以直接将这两个属性放到ViewState中去呢?可是我们的自定义类并没有也不会从Control或WebControl派生,也就是这个ViewSt属性是没有的。怎么办呢?难道我们不能自己增加一个这样的属性吗?ViewState的类型是StateBag,我们自己定义这样一个成员变量不就可以了吗?定义了这样一个成员变量后问题又来了,怎么才能让包含该类型的复杂属性的自定义控件知道这些信息呢?这时候就要IStateManager出场了。
ViewStateManagement5
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.ComponentModel;
using System.Globalization;
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
namespace Controls
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
{
public class ViewStateManagement5 : Control
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
private CustomProperty5 m_Property;
[DesignerSerializationVisibility( DesignerSerializationVisibility.Content )]
public CustomProperty5 Property
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
get
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (m_Property == null)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
m_Property = new CustomProperty5();
m_Property.TrackViewState();
}
return m_Property;
}
//set
//{
//}
}
protected override object SaveViewState()
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
object baseState = base.SaveViewState();
object customPropertyState = Property.SaveViewState();
if (customPropertyState != null)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
return new Pair(baseState, customPropertyState);
}
return baseState;
}
protected override void LoadViewState(object savedState)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (savedState is Pair)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
Pair p = (Pair)savedState;
base.LoadViewState(p.First);
Property.LoadViewState(p.Second);
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
base.LoadViewState(savedState);
}
}
protected override void TrackViewState()
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
base.TrackViewState();
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
protected override void Render(HtmlTextWriter writer)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
writer.Write( TypeDescriptor.GetConverter( Property.GetType()).ConvertTo( null, CultureInfo.InvariantCulture, Property, typeof(string )));
}
}
[TypeConverter( typeof( CustomTypeConverter2))]
public class CustomProperty5 : IStateManager
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
private StateBag viewState = new StateBag();
private bool isTrackingViewState;
string m_Property1;
string m_Property2;
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public string Property1
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
get
{ return viewState["Property1"] == null ? string.Empty : viewState["Property1"].ToString(); }
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
set
{ viewState["Property1"] = value; }
}
public string Property2
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
get
{ return viewState["Property2"] == null ? string.Empty : viewState["Property2"].ToString(); }
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
set
{ viewState["Property2"] = value; }
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f2671b7f42ce505d9bf55a7a0ca257fb.gif)
IStateManager Members#region IStateManager Members
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public bool IsTrackingViewState
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
get
{ return isTrackingViewState; }
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public void LoadViewState(object state)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
((IStateManager)viewState).LoadViewState(state);
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public object SaveViewState()
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (isTrackingViewState)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
return ((IStateManager)viewState).SaveViewState();
}
return null;
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public void TrackViewState()
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
isTrackingViewState = true;
((IStateManager)viewState).TrackViewState();//重要
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
#endregion
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public class CustomTypeConverter2 : ExpandableObjectConverter
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
/**//// <summary>
/// 指定是否可以从特定的类型进行转换
/// </summary>
/// <param name="context"></param>
/// <param name="sourceType"></param>
/// <returns>true:可以;false:不可以</returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
//如果源类型是字符串
if (sourceType == typeof(string))
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return false;
}
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
/**//// <summary>
/// 指定是否可以转换为特定类型
/// </summary>
/// <param name="context"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (destinationType == typeof(string))
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return false;
}
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
/**//// <summary>
/// 从特定值进行转换
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value"></param>
/// <returns></returns>
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (value is string)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
string str = (string)value;
string[] propertyValues = str.Split(';');
if (propertyValues.Length == 2)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
CustomProperty5 obj = new CustomProperty5();
obj.Property1 = propertyValues[0];
obj.Property2 = propertyValues[1];
return obj;
}
}
return base.ConvertFrom(context, culture, value);
}
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
/**//// <summary>
/// 转换成特定值
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (value is CustomProperty5)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
CustomProperty5 obj = (CustomProperty5)value;
return obj.Property1 + ";" + obj.Property2;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
不难发现,其实就是通过LoadViewState和SaveViewState以及TrackViewState来进行沟通的。
注意这段代码,public void TrackViewState()
{
isTrackingViewState = true;
((IStateManager)viewState).TrackViewState();//重要
}
如果去掉加注释的那段,结果发现视图状态保存失败了,为什么呢?这就又要回归到StateBag的源代码上了,大家可以参考下我的ViewState——运用这篇拙作。
在上面的例子中。可以发现复杂属性的set器都是被注释掉了的,为什么呢?我试过给控件的Font属性这样赋值:先new一个FontInfo的对象,然后将这个对象赋给控件的Font属性。结果失败了,因为我们根本就不能访问FontInfo的构造函数。而我们在平时使用的时候基本上都是通过obj.Font.Bold这种形式,而且这种方式也完全满足了我们的需求。但是我们自定义的复杂属性也一定要去掉set访问器吗?当然不是。我们完全可以加上set访问器。当然,加上之后视图状态的管理的逻辑也就要做相应的变化了。
末了,才发现有些东西自己心里知道,但是要写出来却完全是两码事。我也就越发佩服和感谢那些写出那么多优秀的心得体会的前辈和朋友们。这段时间在网上看了很多关于视图状态的文章,个人觉得有很多是很优秀的,等我整理完后我会提供一个列表供大家参考。
评论
更多相关内容: http://www.***
回复 引用