面向对象开发中的数据控件绑定方案

在dotNET中,DataGrid, Repeater等控件的数据源只需要是一个从IEnumerable接口派上的对象就可以进行绑定了,所以可以将DataTable, DataView等作为数据源。

在面向对象开发的中,一般我们会返回一个对象集合而不是一个DataTable, 而dotNet中的集合对象(如Array, ArrayList等)都实现了IEnumerable接口,故而也可以直接将对象集合赋值给数据控件的数据源。

在本文中重点要讨论是如何定制绑定的属性,如标题等。

当不需要在同一页面修改数据时(我称之为原地编辑),我一般选择Repeater来显示数据,如果要原地编辑数据,则使用DataList,因为它们给予了页面和代码最大程度上的分离,这对于美工来说是非常重要的。下面先给出示例代码(部分)

//*** Product.aspx ***

<table>
<asp:Repeater id="rptProduct" runat="server">
   <headertemplate>
      <tr>
         <td><asp:Label id="ProductId" runat="server"/></td>
         <td><asp:Label id="Name" runat="server"/></td>
         <td><asp:Label id="UnitPrice" runat="server"/></td>
      </tr>
   </headertemplate>
   <itemtemplate>
      <tr>
         <td><asp:Label id="ProductId" runat="server"/></td>
         <td><asp:Label id="Name" runat="server"/></td>
         <td><asp:Label id="UnitPrice" runat="server"/></td>
      </tr>
   </itemtemplate>
</asp:Repeater>
</table>
这里定义了标题模板和项目模板, Label控件的值在后台代码中进行设置, 注意,控件的名称应取对象的属性名。

//*** Product.cs ***

public class Product {
   public Product() { }

   [Caption("产品Id")]
   public int ProductId
   {
      get { return productId; }
      set { productId = value; }
   }
   private int productId;

   [Caption("名称")]
   public string Name
   {
      get { return name; }
      set { name = value; }
   }
   private string name;

   [Caption("单价")]
   public decimal UnitPrice
   {
      get { return unitPrice; }
      set { unitPrice = value; }
   }
   private decimal unitPrice;

} //class Product 产品业务对象

//*** CaptionAttribute.cs ****

public class CaptionAttribute : Attribute {
   public CaptionAttribute( string text ) {
      this.text = text;
   }

   public string Text
   {
      get { return text; }
   }
   private string text;

} //class CaptionAttribute 标题特性对象
在这里简单的传入一个标题文本,如果需要多语言支持,应该传入一个资源Id,然后读取对应的资源字符串。

//*** Product.aspx.cs ***

void Page_Load( object sender, EventArgs e ) {
   if ( !IsPostBack ) {
      rptProduct.DataSource = GetProducts(); // GetProducts返回Product对象的集合,这里省略.
      rptProduct.DataBind();
   }
}

void rptProduct_ItemDataBound( object sender, RepeaterItemEventArgs e ) {
   if ( ListItemType.Header == e.Item.ItemType )
      ValueHelper.SetCaption( e.Item, typeof(Product) );
   else if ( ListItemType.Item == e.Item.ItemType ||
         ListItemType.AlternatingItem == e.Item.ItemType )
   {
      Product p = (Product)e.Item.DataItem;
      ValueHelper.SetData( e.Item, p );
   }
}


//*** ValueHelper.cs ***

public class ValueHelper {

   public static void SetCaption( Control container, Type type ) {
      foreach ( Control c in container.Controls ) {
         if ( c is Label ) {
            Label label = (Label)c;
            if ( !IsEmpty(label.Text) ) {
               PropertyInfo pi = type.GetProperty( label.ID );
               label.Text = label.Id // 默认的标题
               if ( pi != null ) {
                  object[] attributes = pi.GetCustomAttributes( typeof(CaptionAttribute), true );
                  if ( attributes.Length > 0 )
                      label.Text = ((CaptionAttribute)attributes[0]).Text;
               }
            } //end if ( IsEmpty )
         }
         else if ( c.HasControls() ) {
            SetCaption( c, type );
         }
      } //end foreach ( container.Controls )
   }
   // 遍历所有的Label控件,然后根据其ID值在类类型中查找属性,再在属性上取得定制的Caption特性。

   public static void SetData( Control container, Object obj ) {
      foreach ( Control c in container.Controls ) {
         if ( c is Label || c is TextBox )
            SetControlData( c, obj, c.ID );
         else if ( c.HasControls() )
            SetData( c, obj );
      }
   }
   // 遍历所有的Label和TextBox控件,然后设置其值。

   private static void SetControlData( Control c, Object obj, string propertyName ) {
      if ( c == null || obj == null ) return;
      PropertyInfo pi = obj.GetType().GetProperty( propertyName );
      if ( pi != null ) {
         object value = pi.GetValue( obj, null );
         if ( value != null ) {
            if ( c is Label )
               ((Label)c).Text = value.ToString();
            else if ( c is TextBox )
               ((TextBox)c).Text = value.ToString();
         }
      }
   }
   // 通过反射取得对象属性的值,然后赋与控件。这里还可以根据值的类型就值进行格式化,这个留给大家自由发挥了。

} //class ValueHelper

通过定制特性我们不难扩展出像FormattedAttribute, VisiableAttribute, WidthAttribute等特性来。

另一种可行的方案是定义一个对象表示->业务对象的映射文件,就像业务对象->数据库映射那样,这样的话应该能更好的分离表示层和业务层,有兴趣的朋友不妨试一下。

posted @ 2008-02-20 22:08  xin478  阅读(339)  评论(0编辑  收藏  举报