熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

使用反射將業務對象綁定到 ASP.NET 窗體控件

2013-11-13 10:32:07  來源: .NET編程 

  引言
  
  在 Web 開發人員的最常見任務之中有一項任務是他們要反復執行的建立更新數據庫表的簡單窗體我們將創建一個列表頁面和一個窗體頁面列表頁面中以表格形式顯示記錄窗體頁面中帶有用於各個數據庫字段的適當的窗體控件許多開發人員還使用表示數據庫表的業務對象將代碼組織到分為多層的設計中如果以業務對象 (Document) 來表示數據庫表 (Documents)許多窗體的代碼看上去將如下所示
  
  <script runat=server>
  protected void Page_Load(Object Src EventArgs E) {
  if (!IsPostBack) {
  Document document =
  DocumentsGetDocument(RequestQueryString[DocumentID]);
  
  TitleText = documentTitle;
  ActiveChecked = documentActive;
  CreatedDateText = documentCreatedDateToString();
  AuthorIDFindByValue(documentAuthorIDToString())Selected =
  true;
  // 等等
  HtmlBodyText = documentHtmlBody;
  }
  }
  protected void SaveButton_Click(Object Src EventArgs E) {
  Document document =
  DocumentsGetDocument(RequestQueryString[DocumentID]);
  
  documentTitle = TitleText;
  documentActive = ActiveChecked;
  documentCreatedDate = ConvertToDateTime(CreatedDateText);
  documentAuthorID = ConvertToInt(AuthorIDSelectedItemValue);
  // 等等
  documentHtmlBody = HtmlBodyText;
  
  DocumentsUpdate(document);
  }
  </script>
  
  簡化和縮短窗體代碼
  
  在以上代碼中對每個控件進行顯式轉換並將其設置為窗體控件的正確屬性根據屬性和窗體控件的數量這部分代碼可能會變長並難以管理代碼還應包含類型轉換的錯誤更正和 ListControl這將進一步增加復雜性即使窗體是由代碼生成工具(例如 Eric J Smith 的優秀的 CodeSmith)生成的當需要任何自定義邏輯關系時很容易引入錯誤
  
  使用反射可以僅使用單行代碼便將業務對象的所有屬性綁定到相應的窗體控件從而減少代碼的行數並增強可讀性完成反射系統的建立後以上代碼將簡化為
  
  protected void Page_Load(Object Src EventArgs E) {
  if (!IsPostBack) {
  Document document =
  DocumentsGetDocument(RequestQueryString[DocumentID]);
  
  FormBindingBindObjectToControls(document);
  }
  }
  protected void Save_Click(Object Src EventArgs E) {
  Document document =
  DocumentsGetDocument(RequestQueryString[DocumentID]);
  
  FormBindingBindControlsToObject(document);
  
  DocumentsUpdate(document);
  }
  
  此代碼可用於所有標准的 ASPNET 控件(TextBoxDropDownListCheckBox 等)和許多第三方控件(例如 Free TextBox 和 Calendar Popup)無論有多少業務對象屬性和窗體控件這一行代碼都能提供所需的全部功能只要窗體控件的 ID 與業務對象屬性名相匹配
  
  開始從反射中檢索屬性列表
  
  首先我們需要檢查業務對象的屬性並查找與業務對象屬性名具有相同 ID 的 ASPNET 控件以下代碼構成了綁定查找的基礎
  
  public class FormBinding {
  public static void BindObjectToControls(object obj
  Control container) {
  if (obj == null) return;
  Type objType = objGetType();
  PropertyInfo[] objPropertiesArray =
  objTypeGetProperties();
  
  foreach (PropertyInfo objProperty in objPropertiesArray) {
  
  Control control =
  containerFindControl(objPropertyName);
  if (control != null) {
  // 處理控件
  }
  }
  }
  }
  
  在以上代碼中方法 BindObjectsToControls 接受了業務對象 obj 和一個容器控件容器控件通常是當前 Web 窗體的 Page 對象如果所用版本是會在運行時更改控件嵌套順序的 ASPNET x MasterPages您將需要指定窗體控件所在的 Content 控件這是在 ASPNET x 中FindControl 方法對嵌套控件和命名容器的處理方式導致的
  
  在以上代碼中我們獲取了業務對象的 Type然後使用該 Type 來獲取 PropertyInfo 對象的數組每個 PropertyInfo 對象都包含關於業務對象屬性以及從業務對象獲取和設置值的能力的信息我們使用 foreach 循環檢查具有與業務對象屬性名 (PropertyInfoName) 對應的 ID 屬性的 ASPNET 控件的容器如果找到控件則嘗試將屬性值綁定到該控件
  
  將對象屬性值綁定到控件
  
  過程中的大部分操作是在此階段執行的我們需要用對象的屬性值來填充找到的控件一種實現方法是為每種控件類型創建一個 if else 語句派生自 ListControl(DropDownListRadioButtonListCheckBoxList 和 ListBox)的所有控件都具有可以統一訪問的公用接口所以可以將它們編組在一起如果找到的控件是 ListControl我們可以將其作為 ListControl 進行轉換然後設置選定項
  
  Control control = containerFindControl(objPropertyName);
  if (control != null) {
  if (control is ListControl) {
  ListControl listControl = (ListControl) control;
  string propertyValue = objPropertyGetValue(obj
  null)ToString();
  ListItem listItem =
  listControlItemsFindByValue(propertyValue);
  if (listItem != null) listItemSelected = true;
  } else {
  // 處理其他控件類型
  }
  }
  
  不幸的是其他控件類型並不從父類中派生以下幾個公用控件都具有 Text 字符串屬性TextBoxLiteral 和 Label但該屬性不是從公用父類中派生出來的所以需要分別轉換每種控件類型我們還需要轉換其他控件類型例如 Calendar 控件以便使用適當的屬性(在 Calendar 的例子中是 SelectedDate 屬性)要包含所有標准的 ASPNET 窗體控件並訪問窗體控件的正確屬性並不需要太多的代碼行
  
  if (control is ListControl) {
  ListControl listControl = (ListControl) control;
  string propertyValue = objPropertyGetValue(obj
  null)ToString();
  ListItem listItem = listControlItemsFindByValue(propertyValue);
  if (listItem != null) listItemSelected = true;
  } else if (control is CheckBox) {
  if (objPropertyPropertyType == typeof(bool))
  ((CheckBox) control)Checked = (bool)
  objPropertyGetValue(obj null);
  } else if (control is Calendar) {
  if (objPropertyPropertyType == typeof(DateTime))
  ((Calendar) control)SelectedDate = (DateTime)
  objPropertyGetValue(obj null);
  } else if (control is TextBox) {
  ((TextBox) control)Text = objPropertyGetValue(obj
  null)ToString();
  } else if (control is Literal)(
  // 等等還可用於標簽等屬性
  }
  
  此方法完整地涵蓋了標准的 ASPNET x 控件從這個角度來看我們擁有了功能齊全的 BindObjectToControls 方法但在起作用的同時此方法的應用范圍會受到限制因為它僅考慮內置的 ASPNET x 控件如果要支持新的 ASPNET 控件或者要使用任何第三方控件我們必須在 FormBinding 項目中引用控件的程序集並將控件類型添加到 if else 列表
  
  此問題的解決方案是第二次使用反射以查看各個控件的屬性並找出控件是否具有與業務對象的屬性類型對應的屬性類型
  
  用已知屬性設置未知控件的值
  
  如上所述有些控件共享字符串屬性 Text大多數窗體控件以實質相同的方式使用此屬性該屬性用於獲取和設置用戶輸入的數據有大量控件還使用了其他一些公用屬性和屬性類型以下是這些屬性中的一些稱為 SelectedDate 的 DateTime 屬性它在許多日歷和日期選取器控件中使用稱為 Checked 的布爾屬性它在布爾型控件中使用稱為 Value 的字符串屬性它常見於隱藏控件這四個屬性(string Textstring Valuebool Checked 和 DateTime SelectedDate)是最常見的控件屬性如果可以將系統設計成無論何種控件類型都綁定到這些屬性那麼我們的綁定方法將適用於使用那四個屬性的任何控件
  
  在以下代碼中我們將第二次使用反射(這一次是對窗體控件使用而不是對業務對象使用)以確定它是否具有任何常用屬性如果有則嘗試將業務對象的屬性值設置為控件的屬性作為示例我們將對整個 PropertyInfo 數組進行迭代並查找稱為 Text 的字符串屬性如果控件具有該屬性則將數據從業務對象發送到該控件的屬性
  
  if (control is ListControl) {
  //
  } else {
  // 獲取控件的類型和屬性
  //
  Type controlType = controlGetType();
  PropertyInfo[] controlPropertiesArray =
  controlTypeGetProperties();
  
  // 查找 Text 屬性
  //
  foreach (Pro
From:http://tw.wingwit.com/Article/program/net/201311/13927.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.