实现WebForm下面的自动收集对象属性(与MVC下在的UpdateFrom一样)
2008-04-06 21:12
423 查看
对ASP.net MVC有了解的同学估计都对里面的UpdateFrom方法有较深的印象。它接受一个对象参数,然后,它会对任何匹配该对象的公开属性,自动对本身进行属性赋值。这样的功能都引来一片叫好声。可惜的是他只能在MVC下使用。那么在WebForm下面就不能实现这样的功能了吗?答案是可以的,其实还可以做得更好。这里把以前的代码翻出来晒晒。
我们还是先看一下UpdateFrom的实现。其实实现很简单,就是先用反射取得对象的所有的属性。然后在Requet.QuerySting或Requet.Form中查找对应的键。如果 找到了对应的值就再调用Property.SetValue方法对其设置属性值。代码如下
public static void UpdateFrom(this object obj, NameValueCollection values, string objectPrefix)
...{
Type objType = obj.GetType();
string objName = objType.Name;
StringBuilder exceptionList = new StringBuilder();
PropertyInfo[] fields = objType.GetProperties();
PopulateTypeException ex = null;
foreach (PropertyInfo property in fields)
...{
//check the key
//going to be forgiving here, allowing for full declaration
//or just propname
string httpKey = property.Name;
if (objectPrefix != string.Empty)
httpKey = objectPrefix + httpKey;
if (values[httpKey] == null)
...{
httpKey = objName + "." + property.Name;
}
if (values[httpKey] == null)
...{
httpKey = objName + "_" + property.Name;
}
if (values[httpKey] != null)
...{
TypeConverter conv = TypeDescriptor.GetConverter(property.PropertyType);
object value = values[httpKey];
if (conv.CanConvertFrom(typeof(string)))
...{
try
...{
value = conv.ConvertFrom(values[httpKey]);
property.SetValue(obj, value, null);
}
catch (Exception e)
...{
string message = property.Name + " is not a valid " + property.PropertyType.Name + "; " + e.Message;
if (ex == null)
ex = new PopulateTypeException("Errors occurred during object binding - review the LoadExceptions property of this exception for more details");
PopulateTypeException.ExceptionInfo info = new PopulateTypeException.ExceptionInfo();
info.AttemptedValue = value;
info.PropertyName = property.Name;
info.ErrorMessage = message;
ex.LoadExceptions.Add(info);
}
}
else
...{
throw new Exception("No type converter available for type: " + property.PropertyType);
}
}
}
if (ex != null)
throw ex;
}
下面进入正题。看看在Webform下面的实现,思路还是一样的。先把我的实现代码贴上来再说
/// <summary>
/// 根据对象自动给相应控件取值或者赋值
/// </summary>
public class ValuePicker
{
/// <summary>
/// 把对象赋值给相应控件
/// </summary>
/// <param name="dataEntity">对象</param>
/// <param name="page">要搜索控件的Page或者Master里的ContentPlaceHolder</param>
/// <returns></returns>
public int SetValue(object dataEntity, Control page)
{
return OperateValue(dataEntity, page, true);
}
/// <summary>
/// 把相应控件的属性值赋给对象的相应属性
/// </summary>
/// <param name="dataEntity">对象</param>
/// <param name="page">要搜索控件的Page或者Master里的ContentPlaceHolder</param>
/// <returns></returns>
public int GetValue(object dataEntity, Control page)
{
return OperateValue(dataEntity, page, false);
}
/// <summary>
/// 根据每个控件的类型,获取对应操作的属性名称
/// </summary>
/// <param name="typeName">控件类型</param>
/// <returns></returns>
private string GetPropertyTypeName(string typeName)
{
switch (typeName)
{
case "TextBox":
return "Text";
case "DropDownList":
return "SelectedValue";
case "CheckBox":
return "Checked";
case "HiddenField":
return "Value";
default:
return "Text";
}
}
/// <summary>
/// 具体实现赋值和取值的方法
/// </summary>
/// <param name="dataEntity">对象</param>
/// <param name="page">要搜索控件的Page或者Master里的ContentPlaceHolder</param>
/// <param name="isSetting">是否是要设置控件的值</param>
/// <returns></returns>
private int OperateValue(object dataEntity, Control page, bool isSetting)
{
try
{
Type EntityType = dataEntity.GetType();
Type ControlType;
//取得所有的属性
PropertyInfo[] Pinfos = EntityType.GetProperties(); ;
Control Ctrl;
Object Data = null;
string PropertyTypeName;
//遍历所有的属性
foreach (PropertyInfo Pinfo in Pinfos)
{
//查找属性对应的控件
Ctrl = page.FindControl(Pinfo.Name);
if (Ctrl != null)
{
ControlType = Ctrl.GetType();
//取得控件存储值的属性
PropertyTypeName = GetPropertyTypeName(ControlType.Name);
if (isSetting == true)
{//把对象的值设置给控件
Data = EntityType.InvokeMember(Pinfo.Name,
BindingFlags.GetProperty, null, dataEntity, null);
Data = ReDefineData(ControlType, Data, PropertyTypeName);
object[] SettingData = { Data };
ControlType.InvokeMember(PropertyTypeName,
BindingFlags.SetProperty, null, Ctrl, SettingData);
}
else
{//取得控件的值赋给对象对应的属性
Data = ControlType.InvokeMember(PropertyTypeName,
BindingFlags.GetProperty, null, Ctrl, null);
Data = ReDefineData(EntityType, Data, Pinfo.Name);
object[] SettingData = { Data };
EntityType.InvokeMember(Pinfo.Name,
BindingFlags.SetProperty, null, dataEntity, SettingData);
}
}
}
return 0;
}
catch (System.Exception E)
{
System.Diagnostics.Debug.WriteLine(E.ToString());
//注意
throw (E);
return -1;
}
}
/// <summary>
/// 进行数据类型转换
/// </summary>
/// <param name="controlType"></param>
/// <param name="data"></param>
/// <param name="PropertyTypeName"></param>
/// <returns></returns>
private object ReDefineData(Type controlType, Object data, string PropertyTypeName)
{
if (data == null)
return null;
switch (controlType.GetProperty(PropertyTypeName).PropertyType.Name)
{
case "Boolean":
if ((int)data == 1)
data = true;
else
data = false;
break;
case "String":
data = data.ToString();
break;
case "Int32":
data = Convert.ToInt32(data);
break;
case "Double":
data = Convert.ToDouble(data);
break;
default:
break;
}
return data;
}
}
在GetPropertyTypeName里面的类型还不够多。比如如果你用到了RadioButtonList,你可以自己加上对应的属性SelectedValue,在这里就只列这么多了。你可以自己改成更好的实现方法。另外ReDefineData应该也要相应的添加一些对应关现。在看了UpdateFrom的实现以后,其实这个类异常的处理应该要改成UpdateFrom才更好,这里就不改了,有空的话我会再改进一下。
另外你还可以写一个类以方便调用
/**//// <summary>
/// 提供页面操作的常用函数
/// </summary>
public class PageUtility
...{
/**//// <summary>
/// 设置当前页面上的控件值
/// </summary>
/// <param name="dataEntity">源数据</param>
/// <returns></returns>
public static int SetPageValueForM(object dataEntity)
...{
ValuePicker Vp = new ValuePicker();
Control ctl = CurPage.Master.FindControl("ContentPlaceHolder2");
return Vp.SetValue(dataEntity, ctl);
}
/**//// <summary>
/// 把当前页面的值读取到控件
/// </summary>
/// <param name="dataEntity">取值的对象</param>
/// <returns></returns>
public static int GetPageValueForM(object dataEntity)
...{
ValuePicker Vp = new ValuePicker();
Control ctl = CurPage.Master.FindControl("ContentPlaceHolder2");
return Vp.GetValue(dataEntity, ctl);
}
/**//// <summary>
/// 把当前页面的值读取到控件
/// </summary>
/// <param name="dataEntity">取值的对象</param>
/// <returns></returns>
public static int GetPageValue(object dataEntity)
...{
ValuePicker Vp = new ValuePicker();
return Vp.GetValue(dataEntity, CurPage);
}
/**//// <summary>
/// 设置当前页面上的控件值
/// </summary>
/// <param name="dataEntity">源数据</param>
/// <returns></returns>
public static int SetPageValue(object dataEntity)
...{
ValuePicker Vp = new ValuePicker();
return Vp.SetValue(dataEntity, CurPage);
}
/**//// <summary>
/// 返回当前页面类
/// </summary>
public static Page CurPage
...{
get ...{ return System.Web.HttpContext.Current.Handler as Page; }
}
}
我们还是先看一下UpdateFrom的实现。其实实现很简单,就是先用反射取得对象的所有的属性。然后在Requet.QuerySting或Requet.Form中查找对应的键。如果 找到了对应的值就再调用Property.SetValue方法对其设置属性值。代码如下
public static void UpdateFrom(this object obj, NameValueCollection values, string objectPrefix)
...{
Type objType = obj.GetType();
string objName = objType.Name;
StringBuilder exceptionList = new StringBuilder();
PropertyInfo[] fields = objType.GetProperties();
PopulateTypeException ex = null;
foreach (PropertyInfo property in fields)
...{
//check the key
//going to be forgiving here, allowing for full declaration
//or just propname
string httpKey = property.Name;
if (objectPrefix != string.Empty)
httpKey = objectPrefix + httpKey;
if (values[httpKey] == null)
...{
httpKey = objName + "." + property.Name;
}
if (values[httpKey] == null)
...{
httpKey = objName + "_" + property.Name;
}
if (values[httpKey] != null)
...{
TypeConverter conv = TypeDescriptor.GetConverter(property.PropertyType);
object value = values[httpKey];
if (conv.CanConvertFrom(typeof(string)))
...{
try
...{
value = conv.ConvertFrom(values[httpKey]);
property.SetValue(obj, value, null);
}
catch (Exception e)
...{
string message = property.Name + " is not a valid " + property.PropertyType.Name + "; " + e.Message;
if (ex == null)
ex = new PopulateTypeException("Errors occurred during object binding - review the LoadExceptions property of this exception for more details");
PopulateTypeException.ExceptionInfo info = new PopulateTypeException.ExceptionInfo();
info.AttemptedValue = value;
info.PropertyName = property.Name;
info.ErrorMessage = message;
ex.LoadExceptions.Add(info);
}
}
else
...{
throw new Exception("No type converter available for type: " + property.PropertyType);
}
}
}
if (ex != null)
throw ex;
}
下面进入正题。看看在Webform下面的实现,思路还是一样的。先把我的实现代码贴上来再说
/// <summary>
/// 根据对象自动给相应控件取值或者赋值
/// </summary>
public class ValuePicker
{
/// <summary>
/// 把对象赋值给相应控件
/// </summary>
/// <param name="dataEntity">对象</param>
/// <param name="page">要搜索控件的Page或者Master里的ContentPlaceHolder</param>
/// <returns></returns>
public int SetValue(object dataEntity, Control page)
{
return OperateValue(dataEntity, page, true);
}
/// <summary>
/// 把相应控件的属性值赋给对象的相应属性
/// </summary>
/// <param name="dataEntity">对象</param>
/// <param name="page">要搜索控件的Page或者Master里的ContentPlaceHolder</param>
/// <returns></returns>
public int GetValue(object dataEntity, Control page)
{
return OperateValue(dataEntity, page, false);
}
/// <summary>
/// 根据每个控件的类型,获取对应操作的属性名称
/// </summary>
/// <param name="typeName">控件类型</param>
/// <returns></returns>
private string GetPropertyTypeName(string typeName)
{
switch (typeName)
{
case "TextBox":
return "Text";
case "DropDownList":
return "SelectedValue";
case "CheckBox":
return "Checked";
case "HiddenField":
return "Value";
default:
return "Text";
}
}
/// <summary>
/// 具体实现赋值和取值的方法
/// </summary>
/// <param name="dataEntity">对象</param>
/// <param name="page">要搜索控件的Page或者Master里的ContentPlaceHolder</param>
/// <param name="isSetting">是否是要设置控件的值</param>
/// <returns></returns>
private int OperateValue(object dataEntity, Control page, bool isSetting)
{
try
{
Type EntityType = dataEntity.GetType();
Type ControlType;
//取得所有的属性
PropertyInfo[] Pinfos = EntityType.GetProperties(); ;
Control Ctrl;
Object Data = null;
string PropertyTypeName;
//遍历所有的属性
foreach (PropertyInfo Pinfo in Pinfos)
{
//查找属性对应的控件
Ctrl = page.FindControl(Pinfo.Name);
if (Ctrl != null)
{
ControlType = Ctrl.GetType();
//取得控件存储值的属性
PropertyTypeName = GetPropertyTypeName(ControlType.Name);
if (isSetting == true)
{//把对象的值设置给控件
Data = EntityType.InvokeMember(Pinfo.Name,
BindingFlags.GetProperty, null, dataEntity, null);
Data = ReDefineData(ControlType, Data, PropertyTypeName);
object[] SettingData = { Data };
ControlType.InvokeMember(PropertyTypeName,
BindingFlags.SetProperty, null, Ctrl, SettingData);
}
else
{//取得控件的值赋给对象对应的属性
Data = ControlType.InvokeMember(PropertyTypeName,
BindingFlags.GetProperty, null, Ctrl, null);
Data = ReDefineData(EntityType, Data, Pinfo.Name);
object[] SettingData = { Data };
EntityType.InvokeMember(Pinfo.Name,
BindingFlags.SetProperty, null, dataEntity, SettingData);
}
}
}
return 0;
}
catch (System.Exception E)
{
System.Diagnostics.Debug.WriteLine(E.ToString());
//注意
throw (E);
return -1;
}
}
/// <summary>
/// 进行数据类型转换
/// </summary>
/// <param name="controlType"></param>
/// <param name="data"></param>
/// <param name="PropertyTypeName"></param>
/// <returns></returns>
private object ReDefineData(Type controlType, Object data, string PropertyTypeName)
{
if (data == null)
return null;
switch (controlType.GetProperty(PropertyTypeName).PropertyType.Name)
{
case "Boolean":
if ((int)data == 1)
data = true;
else
data = false;
break;
case "String":
data = data.ToString();
break;
case "Int32":
data = Convert.ToInt32(data);
break;
case "Double":
data = Convert.ToDouble(data);
break;
default:
break;
}
return data;
}
}
在GetPropertyTypeName里面的类型还不够多。比如如果你用到了RadioButtonList,你可以自己加上对应的属性SelectedValue,在这里就只列这么多了。你可以自己改成更好的实现方法。另外ReDefineData应该也要相应的添加一些对应关现。在看了UpdateFrom的实现以后,其实这个类异常的处理应该要改成UpdateFrom才更好,这里就不改了,有空的话我会再改进一下。
另外你还可以写一个类以方便调用
/**//// <summary>
/// 提供页面操作的常用函数
/// </summary>
public class PageUtility
...{
/**//// <summary>
/// 设置当前页面上的控件值
/// </summary>
/// <param name="dataEntity">源数据</param>
/// <returns></returns>
public static int SetPageValueForM(object dataEntity)
...{
ValuePicker Vp = new ValuePicker();
Control ctl = CurPage.Master.FindControl("ContentPlaceHolder2");
return Vp.SetValue(dataEntity, ctl);
}
/**//// <summary>
/// 把当前页面的值读取到控件
/// </summary>
/// <param name="dataEntity">取值的对象</param>
/// <returns></returns>
public static int GetPageValueForM(object dataEntity)
...{
ValuePicker Vp = new ValuePicker();
Control ctl = CurPage.Master.FindControl("ContentPlaceHolder2");
return Vp.GetValue(dataEntity, ctl);
}
/**//// <summary>
/// 把当前页面的值读取到控件
/// </summary>
/// <param name="dataEntity">取值的对象</param>
/// <returns></returns>
public static int GetPageValue(object dataEntity)
...{
ValuePicker Vp = new ValuePicker();
return Vp.GetValue(dataEntity, CurPage);
}
/**//// <summary>
/// 设置当前页面上的控件值
/// </summary>
/// <param name="dataEntity">源数据</param>
/// <returns></returns>
public static int SetPageValue(object dataEntity)
...{
ValuePicker Vp = new ValuePicker();
return Vp.SetValue(dataEntity, CurPage);
}
/**//// <summary>
/// 返回当前页面类
/// </summary>
public static Page CurPage
...{
get ...{ return System.Web.HttpContext.Current.Handler as Page; }
}
}
相关文章推荐
- 实现WebForm下面的自动收集对象属性(与MVC下在的UpdateFrom一样)
- 【整理】.Net Framework3.5之隐式类型的本地变量和数组、对象初始值设定项、集合初始值设定项、自动实现的属性和匿名类型
- ASP.NET MVC之表单集合数据自动绑定到对象属性(集合)中
- C++实现自动为对象添加“属性”访问代码
- ###Springmvc封装复杂表单数据:表单提交多个实体类的参数【对象类型参数,自动封装】name属性值不能重复。和实体类属性名一致
- ASP.NET WebForm Form表单如何实现MVC那种“自动装配”效果呢?
- ASP.NET WebForm Form表单如何实现MVC那种“自动装配”效果呢?
- 实现对象属性的"监控" - 修改数据后自动更新页面
- ASP.NET MVC之表单集合数据自动绑定到对象属性(集合)中
- 写一个算法,使对象可以像数组一样进行foreach循环,要求属性必须是私有的(Interator模式的PHP5实现,写一类实现Interator接口)
- ASP.NET WebForm Form表单如何实现MVC那种“自动装配”效果呢?
- ASP.NET WebForm Form表单如何实现MVC那种“自动装配”
- C++实现自动为对象添加“属性”访问代码
- 非“自动实现的属性”也可以用“对象初始值设定项”进行初始化
- ASP.NET WebForm Form表单如何实现MVC那种“自动装配”效果呢?
- C#利用反射实现两个类的对象之间相同属性的值的复制
- c#语法糖代码——自动属性, 匿名类型,对象与集合初始化器,扩展方法
- Asp.net MVC: BindingHelperExtension的UpdateFrom如何使用?
- select from update row的实现
- Angularjs实现下拉框自动匹配键值对对象技巧