利用反射实现ASP.NET控件和数据实体之间的双向绑定,并且在客户端自动验证输入的内容是否合法
首先请原谅我蹩脚的中文...玩电脑太多都不太会说话了,但愿大家看的明白
ASP.NET的UI不像做Winform那么容易,设个DataSource和DataField就什么都搞定了.虽然提供了<%#%>这样形式的绑定,但是这种绑定是单向的,只能从数据源赋值给控件,无法把控件的内容写回数据源.所以,在保存数据时得一条一条写,还得处理null,类型转换什么的.例如
anObject.AnIntProperty = Convert.ToInt32(aControl.Text == "" ? aControl.Text : "0"); //用数据实体的话
或者
aDatarow["AnIntField"] = Convert.ToInt32(aControl.Text == "" ? aControl.Text : "0"); //用datarow的话
有时一张表单几十个字段,这样写准会疯的 >_<
于是我利用反射做了一个东西,实现了让控件显示数据实体(我惯用o-r mapping而不是DataSet/DataRow,当然DataRow也能用类似的方式去搞)的内容和把控件的内容赋回给数据实体,然后,顺便把数据合法性验证也做进去了(反射性能损耗大,不干多点东西心里不平衡啊)
在我的BindingManager类中约定,凡是"_"结尾的控件将会被处理,这些控件会和实体类相对应的属性自动关联起来.通过设置PrefixLength的值指定从控件名的第几个字符开始匹配实体类属性,例如我习惯用3个字符做控件前缀,于是设PrefixLength为3,和Name属性关联的控件名就形如txtName_.然后调用GetEntityValues(Page,theObject)和SetEntityValue(Page,theObject)来实现控件和数据实体之间的绑定.
至于"顺便"做的合法性验证的功能,首先确保了控件输入的内容符合实体属性的类型,这是自动完成的,例如一个int属性对应的控件不能填写字母.如果有更多的要求,例如用正则表达式,不允许空值,或者在出错时给用户更详细的提示,则给实体的属性加上ValidateAttribute后就可以实现.
这是一个我写的Demo的其中一部分:Person类,其中有各种不同类型的属性.可以看到ValidateAttribute指定了Name不可空,描述为"姓名",这样,当 txtName_.Text 是空值时提交数据,将会弹出提示"姓名不能为空".而Id则规定了要输入现在新身份证的格式,如果不符合的话则提示"身份证号码格式不正确".另外,Sex是个自定义的类.得做个针对他的TypeConverter,然后给Sex类加上TypeConverterAttribute才可能被正确的处理.
在使用Person类时,一行语句就能实现控件和数据间赋值.以下是一个aspx后台代码的片断:
Person p = new Person();
BindingManager bm = new BindingManager();
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
//validateForm()是客户端验证控件合法性时调用的函数
Button1.Attributes["onclick"] = "return validateForm();";
//给p随便设点值
p.Name = "Yok";
p.Height = 170;
p.Sex = Sex.Male;
p.Birthday = new DateTime(1980, 11, 21);
//这样就可以让控件显示p的内容
bm.GetEntityValues(Page, p);
}
}
private void Button1_Click(object sender, System.EventArgs e)
{
//把值赋给实体
bm.SetEntityValues(Page, p);
//这时p已经从控件获得各个属性的值.Write出来看一下是否正确
Response.Write("Name = " + p.Name + "<br>");
Response.Write("Height = " + p.Height + "<br>");
Response.Write("Birthday = " + p.Birthday.ToShortDateString() + "<br>");
Response.Write("Id = " + p.Id + "<br>");
Response.Write("Sex = " + p.Sex.ToString() + "<br>");
}
不说了,我的代码应该比我的文字好懂
ASP.NET的UI不像做Winform那么容易,设个DataSource和DataField就什么都搞定了.虽然提供了<%#%>这样形式的绑定,但是这种绑定是单向的,只能从数据源赋值给控件,无法把控件的内容写回数据源.所以,在保存数据时得一条一条写,还得处理null,类型转换什么的.例如
anObject.AnIntProperty = Convert.ToInt32(aControl.Text == "" ? aControl.Text : "0"); //用数据实体的话
或者
aDatarow["AnIntField"] = Convert.ToInt32(aControl.Text == "" ? aControl.Text : "0"); //用datarow的话
有时一张表单几十个字段,这样写准会疯的 >_<
于是我利用反射做了一个东西,实现了让控件显示数据实体(我惯用o-r mapping而不是DataSet/DataRow,当然DataRow也能用类似的方式去搞)的内容和把控件的内容赋回给数据实体,然后,顺便把数据合法性验证也做进去了(反射性能损耗大,不干多点东西心里不平衡啊)
在我的BindingManager类中约定,凡是"_"结尾的控件将会被处理,这些控件会和实体类相对应的属性自动关联起来.通过设置PrefixLength的值指定从控件名的第几个字符开始匹配实体类属性,例如我习惯用3个字符做控件前缀,于是设PrefixLength为3,和Name属性关联的控件名就形如txtName_.然后调用GetEntityValues(Page,theObject)和SetEntityValue(Page,theObject)来实现控件和数据实体之间的绑定.
至于"顺便"做的合法性验证的功能,首先确保了控件输入的内容符合实体属性的类型,这是自动完成的,例如一个int属性对应的控件不能填写字母.如果有更多的要求,例如用正则表达式,不允许空值,或者在出错时给用户更详细的提示,则给实体的属性加上ValidateAttribute后就可以实现.
这是一个我写的Demo的其中一部分:Person类,其中有各种不同类型的属性.可以看到ValidateAttribute指定了Name不可空,描述为"姓名",这样,当 txtName_.Text 是空值时提交数据,将会弹出提示"姓名不能为空".而Id则规定了要输入现在新身份证的格式,如果不符合的话则提示"身份证号码格式不正确".另外,Sex是个自定义的类.得做个针对他的TypeConverter,然后给Sex类加上TypeConverterAttribute才可能被正确的处理.
public class Person
{
public Person()
{
}
string _name;
decimal _height;
DateTime _birthday;
Sex _sex;
[Validate(AllowNull = false, Description = "姓名")]
public string Name
{
get {return _name;}
set {_name = value;}
}
[Validate(Description = "身高")]
public decimal Height
{
get {return _height;}
set {_height = value;}
}
string _id;
[Validate(RegEx = "^\\d{17}(\\d|x)$", Description = "身份证号码")]
public string Id
{
get {return _id;}
set {_id = value;}
}
public DateTime Birthday
{
get {return _birthday;}
set {_birthday = value;}
}
public Sex Sex
{
get {return _sex;}
set {_sex = value;}
}
}
{
public Person()
{
}
string _name;
decimal _height;
DateTime _birthday;
Sex _sex;
[Validate(AllowNull = false, Description = "姓名")]
public string Name
{
get {return _name;}
set {_name = value;}
}
[Validate(Description = "身高")]
public decimal Height
{
get {return _height;}
set {_height = value;}
}
string _id;
[Validate(RegEx = "^\\d{17}(\\d|x)$", Description = "身份证号码")]
public string Id
{
get {return _id;}
set {_id = value;}
}
public DateTime Birthday
{
get {return _birthday;}
set {_birthday = value;}
}
public Sex Sex
{
get {return _sex;}
set {_sex = value;}
}
}
在使用Person类时,一行语句就能实现控件和数据间赋值.以下是一个aspx后台代码的片断:
Person p = new Person();
BindingManager bm = new BindingManager();
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
//validateForm()是客户端验证控件合法性时调用的函数
Button1.Attributes["onclick"] = "return validateForm();";
//给p随便设点值
p.Name = "Yok";
p.Height = 170;
p.Sex = Sex.Male;
p.Birthday = new DateTime(1980, 11, 21);
//这样就可以让控件显示p的内容
bm.GetEntityValues(Page, p);
}
}
private void Button1_Click(object sender, System.EventArgs e)
{
//把值赋给实体
bm.SetEntityValues(Page, p);
//这时p已经从控件获得各个属性的值.Write出来看一下是否正确
Response.Write("Name = " + p.Name + "<br>");
Response.Write("Height = " + p.Height + "<br>");
Response.Write("Birthday = " + p.Birthday.ToShortDateString() + "<br>");
Response.Write("Id = " + p.Id + "<br>");
Response.Write("Sex = " + p.Sex.ToString() + "<br>");
}
不说了,我的代码应该比我的文字好懂