引言
在 Web 开发人员的最常见任务之中,有一项任务是他们要反复执行的:建立更新数据库表的简单窗体。我们将创建一个列表页面和一个窗体页面,列表页面中以表格形式显示记录,窗体页面中带有用于各个数据库字段的适当的窗体控件。许多开发人员还使用表示数据库表的业务对象将代码组织到分为多层的设计中。如果以业务对象 (Document) 来表示数据库表 (Documents),许多窗体的代码看上去将如下所示:
<script runat="server">
protected void Page_Load(Object Src, EventArgs E) {
if (!IsPostBack) {
Document document =
Documents.GetDocument(Request.QueryString["DocumentID"]);
Title.Text = document.Title;
Active.Checked = document.Active;
CreatedDate.Text = document.CreatedDate.ToString();
AuthorID.FindByValue(document.AuthorID.ToString()).Selected =
true;
// 等等
HtmlBody.Text = document.HtmlBody;
}
}
protected void SaveButton_Click(Object Src, EventArgs E) {
Document document =
Documents.GetDocument(Request.QueryString["DocumentID"]);
document.Title = Title.Text;
document.Active = Active.Checked;
document.CreatedDate = Convert.ToDateTime(CreatedDate.Text);
document.AuthorID = Convert.ToInt32(AuthorID.SelectedItem.Value);
// 等等
document.HtmlBody = HtmlBody.Text;
Documents.Update(document);
}
</script>
简化和缩短窗体代码
在以上代码中,对每个控件进行显式转换,并将其设置为窗体控件的正确属性。根据属性和窗体控件的数量,这部分代码可能会变长并难以管理。代码还应包含类型转换的错误更正和 ListControl,这将进一步增加复杂性。即使窗体是由代码生成工具(例如 Eric J. Smith 的优秀的 CodeSmith)生成的,当需要任何自定义逻辑关系时,很容易引入错误。
使用反射,可以仅使用单行代码便将业务对象的所有属性绑定到相应的窗体控件,从而减少代码的行数并增强可读性。完成反射系统的建立后,以上代码将简化为:
protected void Page_Load(Object Src, EventArgs E) {
if (!IsPostBack) {
Document document =
Documents.GetDocument(Request.QueryString["DocumentID"]);
FormBinding.BindObjectToControls(document);
}
}
protected void Save_Click(Object Src, EventArgs E) {
Document document =
Documents.GetDocument(Request.QueryString["DocumentID"]);
FormBinding.BindControlsToObject(document);
Documents.Update(document);
}
此代码可用于所有标准的 ASP.NET 控件(TextBox、DropDownList、CheckBox 等)和许多第三方控件(例如 Free TextBox 和 Calendar Popup)。无论有多少业务对象属性和窗体控件,这一行代码都能提供所需的全部功能,只要窗体控件的 ID 与业务对象属性名相匹配。
开始:从反射中检索属性列表
首先,我们需要检查业务对象的属性,并查找与业务对象属性名具有相同 ID 的 ASP.NET 控件。以下代码构成了绑定查找的基础:
public class FormBinding {
public static void BindObjectToControls(object obj,
Control container) {
if (obj == null) return;
Type objType = obj.GetType();
PropertyInfo objPropertiesArray =
objType.GetProperties();
foreach (PropertyInfo objProperty in objPropertiesArray) {
Control control =