ASP.NET中GridView控件用于展现单表数据非常方便,只要简单地进行数据绑定便可。但很多时候,需要在页面上显示父子表数据,每一行父表的记录下方显示一个表格展现字表的数据。下图便是这样的一个例子:

MasterSlaveView

以上图中的订单数据为例,本文将介绍一种简单可行的利用GridView展现父子表数据的方法。

为方便说明,这里没有采用数据库来作为数据源,而是使用简单对象的方式。

创建一个C# ASP.NET测试项目,先定义用于表示订单和订单行的两个类:

订单行:
    public class OrderLine {
public string ProductID { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public float UnitPrice { get; set; }
public float TotalPrice { get { return Quantity * UnitPrice; } }
public OrderLine( string productID, string productName, int quantity, float unitPrice) { ProductID = productID; ProductName = productName; Quantity = quantity; UnitPrice = unitPrice; }
}

订单:

    public class Order {
public string OrderNo { get; set; }
public DateTime OrderDate { get; set; }
public string Customer { get; set; }
private IList<orderline> orderLines;
public IList<orderline> OrderLines { get { return orderLines; } }
public float TotalPrice { get { float total = 0; foreach (OrderLine line in OrderLines) { total += line.TotalPrice; } return total; } }
public Order( string orderNo, DateTime orderDate, string customer) { orderLines = new List<orderline>();
OrderNo = orderNo; OrderDate = orderDate; Customer = customer; }
}

在default.aspx页面上放一个GridView控件,命名为orderView。禁用自动生成列后,手工一个一个加入数据绑定列分别绑定到Order类的几个标量属性上。最后增加一个模板列,模板列里放入另一个GridView控件用于展现订单行的数据,命名为orderLineView。具体ASP.NET实现代码如下:

    <asp:gridview id="orderView" runat="server" autogeneratecolumns="False">
      <columns>
        <asp:boundfield datafield="OrderNo" headertext="订单号码" />
        <asp:boundfield datafield="OrderDate" headertext="订单日期"
              dataformatstring="{0:yyyy-MM-dd}" />
        <asp:boundfield datafield="Customer" headertext="客户名称" />
        <asp:boundfield datafield="TotalPrice" headertext="价格总计"
              dataformatstring="{0:N2}">
          <itemstyle horizontalalign="Right" />
        </asp:boundfield>
        <asp:templatefield>
          <itemtemplate>
            </td></tr><tr><td align="center" colspan="5">
            <asp:gridview id="orderLineView" runat="server"
                  autogeneratecolumns="false"
                  datasource='<%# Bind("OrderLines") %>' width="90%">
              <columns>
                <asp:boundfield datafield="ProductID" headertext="产品编码" />
                <asp:boundfield datafield="ProductName" headertext="产品名称" />
                <asp:boundfield datafield="Quantity" headertext="数量" />
                <asp:boundfield datafield="UnitPrice" headertext="单价"
                       dataformatstring="{0:N2}">
                  <itemstyle horizontalalign="Right" />
                </asp:boundfield>
                <asp:boundfield datafield="TotalPrice" headertext="合计"
                       dataformatstring="{0:N2}">
                  <itemstyle horizontalalign="Right" />
                </asp:boundfield>
              </columns>
            </asp:gridview>
          </itemtemplate>
        </asp:templatefield>
      </columns>
    </asp:gridview>

上面的代码中,几个绑定到Order类标量属性上的字段很好理解,这里就不解释了,这里着重说明一下第9行到第27行所定义的一个模板列。模板列,顾名思义,就是定义一个模板,GridView依照模板来产生要显示的内容。<ItemTemplate></ItemTemplate>标签对中便是模板定义的区域了。可以看到,上面的代码中,模板列的主体是一个命名为orderLineView的GridView控件,所以,针对每一行订单数据,由这个模板列定义的单元格都由GridView控件来展现一个表格。orderLineView内部各数据绑定列的内容这里也不做解释了。要注意的是第13行中的DataSource属性定义,<%# %>标签对中的Bind( "OrderLines" ) 方法将OrderLines绑定到了orderLineView上,由于Order类中的OrderLines属性是一个List,所以这样的绑定是可以正常工作的。

由于正常情况下,GridView只会为每一行数据产生表格中的一行,所以上面代码中的的第11行,在orderLineView控件之前,做了一些特殊的处理,先用</td></tr>关闭GridView自动产生的行,然后再用<tr><td colspan="5" align="center">开了一个新行,之后GridView自动产生的</td></tr>关闭的将是我们在模板列中定义的这个新行。新行中只有一个列,所以通过colspan="5"使它横跨了整个表格。其实这样的特殊处理也是无奈之举,用的是类似欺骗的手法来绕过了GridView的限制。不过在没有更好的而且也很简洁方法时,暂且就用这个办法吧。

好了,页面设计好了,运行时只要把数据绑定到控件上就可以便可以显示出本文开头处的图片中的那个表格了。以下的代码在Page_Load事件中准备一些数据并绑定到了orderView上:

    protected void Page_Load(object sender, EventArgs e)
    {
IList orders = new List();
Order order = new Order("2009010100001", new DateTime(2009, 1, 1), "九九志 • 重阳"); order.OrderLines.Add(new OrderLine("P0001", "GBA", 2, 500)); order.OrderLines.Add(new OrderLine("P0002", "PSP", 1, 1500)); order.OrderLines.Add(new OrderLine("P0003", "NDSL", 13, 1100)); orders.Add(order);
order = new Order("2009010300001", new DateTime(2009, 1, 3), "www.99log.com"); order.OrderLines.Add(new OrderLine("P0002", "PSP", 3, 1450)); order.OrderLines.Add(new OrderLine("P0004", "XBOX 360", 1, 2500)); orders.Add(order);
order = new Order("2009010300002", new DateTime(2009, 1, 3), "Yin Peng"); order.OrderLines.Add(new OrderLine("P0005", "LCD", 1, 1999)); order.OrderLines.Add(new OrderLine("P0006", "CPU", 1, 500)); order.OrderLines.Add(new OrderLine("P0007", "RAM", 4, 80)); order.OrderLines.Add(new OrderLine("P0008", "HDD", 2, 450)); orders.Add(order);
orderView.DataSource = orders; orderView.DataBind();
}

以上简单的介绍了一种使用GridView来展现父子表数据的方法。本文的目的只是通过一个简单的实例来展示这种方法的原理,基于此原理,还可以灵活应用其他技巧,比如,在每条主表记录前加上一个+/-号,用于显示和隐藏字表等等。

标签:,