打印本文 打印本文 关闭窗口 关闭窗口
使用反射将业务对象绑定到 ASP.NET 窗体控件
作者:武汉SEO闵涛  文章来源:敏韬网  点击数1966  更新时间:2009/4/23 10:40:58  文章录入:mintao  责任编辑:mintao
lPropertiesArray, "Checked", typeof(bool) ); if (!success) success = FindAndSetControlProperty(obj, objProperty, control, controlPropertiesArray, "SelectedDate", typeof(DateTime) ); if (!success) success = FindAndSetControlProperty(obj, objProperty, control, controlPropertiesArray, "Value", typeof(String) ); if (!success) success = FindAndSetControlProperty(obj, objProperty, control, controlPropertiesArray, "Text", typeof(String) ); } private static void FindAndSetControlProperty(object obj, PropertyInfo objProperty, Control control, PropertyInfo[] controlPropertiesArray, string propertyName, Type type) { // 在整个控件属性中进行迭代 foreach (PropertyInfo controlProperty in controlPropertiesArray) { // 检查匹配的名称和类型 if (controlPropertiesArray.Name == "Text" && controlPropertiesArray.PropertyType == typeof(String)) { // 将控件的属性设置为 // 业务对象属性值 controlProperty.SetValue(control, Convert.ChangeType( objProperty.GetValue(obj, null), type) , null); return true; } } return false; }

以上属性检查的顺序很重要,因为有些控件具有以上属性中的多个,但我们只想设置一个。例如,CheckBox 控件既有 .Text 属性也有 .Checked 属性。在此示例中,我们希望使用 .Checked 属性而不是 .Text 属性,所以将 .Checked 放在属性搜索顺序的首位。任何情况下,如果找到具有正确名称和类型的控件属性,则尝试将控件的属性设置为业务对象属性的值。

从这个角度来看,我们拥有了功能齐全的 BindObjectToControls 方法。利用该方法,我们可以在 ASPX 窗体上的任何地方,使用任何类和控件的任意组合进行调用,而这确实有效。现在,我们需要创建在提交窗体时进行反转的方法。我们需要从表示用户输入的控件中检索新值,而不是将控件属性的值设置为业务对象的值。

返回页首返回页首

反转过程:BindControlsToObject

BindControlsToObject 方法中,我们将以同样的方式开始,即从业务对象中检索属性的列表,然后使用 FindControl 方法找到具有与对象属性相匹配的 ID 的控件。如果找到控件,则检索值并将该值返回给业务对象。此部分还将包含 ListControl 的单独代码,因为这些控件具有公用接口。我们将使用另一种辅助方法来搜索并检索控件中的值,然后将该值返回给业务对象。

public static void BindControlsToObject(object obj, 
  Control container) {
   Type objType = obj.GetType();
   PropertyInfo[] objPropertiesArray = objType.GetProperties();

   foreach (PropertyInfo objProperty in objPropertiesArray) {

      if (control is ListControl) {
         ListControl listControl = (ListControl) control;
         if (listControl.SelectedItem != null)
            objProperty.SetValue(obj, 
                          Convert.ChangeType(list.SelectedItem.Value,
                          objProperty.PropertyType), null);

      } else {
         // 获取控件的属性
         //
         Type controlType = control.GetType();
         PropertyInfo[] controlPropertiesArray = 
                     controlType.GetProperties();

         bool success = false;
         success = FindAndGetControlProperty(obj, 
                    objProperty, control, controlPropertiesArray, 
                    "Checked", typeof(bool) );

         if (!success)
            success = FindAndGetControlProperty(obj, 
                         objProperty, control, controlPropertiesArray, 
                         "SelectedDate", typeof(DateTime) );

         if (!success)
            success = FindAndGetControlProperty(obj, 
                          objProperty, control, controlPropertiesArray, 
                          "Value", typeof(String) );

         if (!success)
            success = FindAndGetControlProperty(obj, 
                         objProperty, control, controlPropertiesArray, 
                         "Text", typeof(String) );

      }
   }
}

private static void FindAndGetControlProperty(object obj, 
  PropertyInfo objProperty, Control control, PropertyInfo[] 
  controlPropertiesArray, string propertyName, Type type) {
   // 在整个控件属性中进行迭代
   foreach (PropertyInfo controlProperty in 
        controlPropertiesArray) {
      // 检查匹配的名称和类型
      if (controlPropertiesArray.Name == "Text" && 
              controlPropertiesArray.PropertyType == typeof(String)) {
         // 将控件的属性设置为
                  // 业务对象属性值
         try {
            objProperty.SetValue(obj, 
                          Convert.ChangeType( 
                          controlProperty.GetValue(control, null), 
                          objProperty.PropertyType) , null);
            return true;
         } catch {
            // 无法将来自窗体控件 
                        // 的数据转换为 
                        // objProperty.PropertyType
            return false;
         }
      }
   }
   return true;
}

完成这两种方法后,我们的窗体语法将得到简化,如以上简化和缩短窗体代码中所述。每个属性和控件的类型转换与错误更正都是自动进行的。这两种方法(BindObjectToControlsBindControlsToObject)为开发人员创建窗体提供了很大的灵活性。它们还可以用于处理以下这些常见方案:

如果将新属性添加到业务对象,并且需要在窗体上访问该新属性,那么开发人员只需将控件添加到页面,并将控件的 ID 设置为新属性的名称,FormBinding 方法将处理剩下的一切。

如果开发人员需要更改用于特定属性的控件的类型,例如从 TextBox 更改为第三方的 HTML 编辑器控件,他/她仅需要确保新控件具有以上属性之一(例如 .Text ),窗体将以与之前完全一致的方式进行工作。

全部使用 TextBox 控件也可以快速生成窗体,但输入仍将转换为适用于业务对象属性的正确类型。例如,可以用 TextBox 控件来代替 Calendar 控件或第三方的日期选取器控件。只要用户输入 DateTime 字符串作为值,便会将 TextBox.Text 属性中的值转换为 DateTime,就如同它是日历控件上的 SelectedDate 属性一样。如果以后将 TextBox 更改为日期选取器控件,逻辑关系将保持不变。

通过将所有控件更改为 Literal 控件,开发人员还可以快速创建“视图”页面。Literal.Text 属性将被设置为业务对象属性的值,就如同它是 TextBox 一样。

在实际方案中,窗体还包含其他数据类型和自定义配置。用于处理这些特定操作的代码可以放置在对 BindObjectToControls BindControlsToObject 的调用之后。

返回页首返回页首

性能和 FormBinding 方案的扩展

有些开发人员可能想知道,使用反射引起的性能下降是否值得。在我的测试中,使用了具有七种属性(int DocumentID、bool Active、DateTime Created、int CategoryID、String Title、string Author 和 String htmlText)的对象,BindObjectToControls 用时约 1/3 毫秒,BindControlsToObject 用时大约 1 毫秒。这些值是通过循环运行 1000 次 BindObjectToControlsBindControlsToObject 方法得到的。对于常见的“添加”和“编辑”窗体方案,这样的性能应不会引起任何重大的问题,而且确实能够提高开发速度和灵活性。

尽管此方法几乎适用于每种窗体,但有时可能需要修改以上代码。在某些方案中,开发人员要使用的控件可能并不使用以上属性之一作为其主要接口。在此情形中,需要更新 FormBinding 方法,以包括该属性和类型。

返回页首返回页首

结论

这两种 FormBinding 方法(BindObjectToControlsBindControlsToObject)可用于极大地简化窗体代码,并为 ASP.NET 窗体的开发提供了最大的灵活性。对它们的使用使我获益良多,希望您的团队同样能够从中受益。

返回页首返回页首

转到原英文页面

上一页  [1] [2] 

打印本文 打印本文 关闭窗口 关闭窗口