动态生成列表视图列

ASP.NET中,ListView控件是一个灵活的数据展示组件,它允许开发者自定义数据的展示方式。其中一种高级用法是动态生成列,这可以通过配置AutoGenerateColumns属性来实现。本文将介绍如何使用Common Table Expressions(CTE)和PIVOT操作来创建一个Employee-vs-Vendor表,并在ListView中动态生成列。

创建动态列的ListView

首先,需要创建一个Employee-vs-Vendor表,这可以通过使用CTE和PIVOT来实现。具体的SQL查询语句和数据表结构可以在附带的源代码中找到。

在ListView的布局模板中,需要声明一个占位符,用于后续动态生成列。以下是HTML代码示例:

<LayoutTemplate> <div class="listviewGrid"> <table id="tblViewHdr" class="CollapsableExpandable" cellpadding="0" cellspacing="0" style="word-break:break-all;word-wrap:break-word"> <tr class="head"> <asp:PlaceHolder runat="server" ID="phDynamicHdr" /> </tr> <tr id="itemPlaceholder" runat="server" /> </table> </div> </LayoutTemplate>

CSS样式用于处理列过多时的换行问题,确保内容不会溢出表格。

在ItemTemplate中,不需要额外添加动态列,因为这些列将通过程序自动生成。以下是HTML代码示例:

<ItemTemplate> <tr id="row" runat="server" class="item"> <td class="first"> <img src="Images/minus.png" /> </td> </tr> </ItemTemplate>

根据查询的级别,可能需要创建嵌套的ItemTemplate。这可以通过AJAX来实现,但本文暂不涉及这部分内容。

当开始将查询结果绑定到ListView时,需要从CTE和PIVOT获取的SQL结果逐级绑定。以下是C#代码示例:

public void bindListView(DataTable dtEmpID) { DataTable dt = new DataTable(); dt = ((DataTable)ViewState["cachedTable"]).Clone(); if (((DataTable)ViewState["cachedTable"]).Rows.Count > 0) { DataRow[] drResults = ((DataTable)ViewState["cachedTable"]).Select("GENERATION = 0"); foreach (DataRow dr in drResults) { object[] row = dr.ItemArray; dt.Rows.Add(row); } } lsvHighLvlFormAccess.DataSource = dt; lsvHighLvlFormAccess.DataBind(); }

在最高级别的绑定完成后,可以填充表头标题。这是设置列跨度和动态生成列标题的部分。

以下是C#代码示例,展示了如何在DataBound事件中动态生成列标题:

protected void lsvHighLvlFormAccess_DataBound(object sender, EventArgs e) { PlaceHolder phDynamicHdr = (PlaceHolder)lsvHighLvlFormAccess.FindControl("phDynamicHdr"); if (phDynamicHdr != null) { Literal ltrl = new Literal(); DataTable dt = ((DataTable)ViewState["cachedTable"]); if (dt != null && dt.Rows.Count > 0) { foreach (DataColumn dc in dt.Rows[0].Table.Columns) { if (!(dc.ColumnName.Equals("GENERATION") || dc.ColumnName.Equals("hierarchy") || dc.ColumnName.Equals("rowNo") || dc.ColumnName.Equals("EmployeeID"))) { if (dc.ColumnName.Equals("LoginID")) { ltrl.Text += "" + dc.ColumnName + ""; } else ltrl.Text += "" + dc.ColumnName + ""; } } } if (phDynamicHdr.Controls.Count > 0) { if (!((Literal)phDynamicHdr.Controls[0]).Text.Equals(ltrl.Text)) { phDynamicHdr.Controls.Remove(phDynamicHdr.Controls[0]); phDynamicHdr.Controls.Add(ltrl); } } else phDynamicHdr.Controls.Add(ltrl); } HtmlTableCell td = (HtmlTableCell)lsvHighLvlFormAccess.FindControl("imgCollapseExpand"); if (td != null) { DataTable dt = ((DataTable)ViewState["cachedTable"]); if (dt != null && dt.Rows.Count > 0) { td.ColSpan = dt.Rows[0].Table.Columns.Count + I_COLSPAN - 1; } } }

在每一级的行绑定时,需要触发事件以填充其后代。这里使用了复选框,但也可以使用其他控件。

以下是C#代码示例,展示了如何在ItemDataBound事件中动态填充行:

protected void lsvHighLvlFormAccess_ItemDataBound(object sender, ListViewItemEventArgs e) { HtmlTableRow row = (HtmlTableRow)e.Item.FindControl("row"); ListViewDataItem item = (ListViewDataItem)e.Item; System.Data.DataRowView drv = (System.Data.DataRowView)item.DataItem; dynamicPopulateRow(row, drv, 0); }

其中dynamicPopulateRow()方法如下:

private void dynamicPopulateRow(HtmlTableRow row, System.Data.DataRowView drv, int iGeneration) { if (row != null) { foreach (DataColumn dc in drv.Row.Table.Columns) { string sEmployeeID = drv["LoginID"].ToString(); if (dc.ColumnName.Equals("LoginID")) { HtmlTableCell cell = new HtmlTableCell("td"); cell.Controls.Add(new LiteralControl(Convert.ToString(drv[dc.ColumnName]))); cell.ColSpan = dc.ColumnName.Equals("LoginID") ? I_COLSPAN - iGeneration : 1; row.Cells.Add(cell); } else if (!(dc.ColumnName.Equals("GENERATION") || dc.ColumnName.Equals("hierarchy") || dc.ColumnName.Equals("rowNo") || dc.ColumnName.Equals("EmployeeID"))) { HtmlTableCell cell = new HtmlTableCell("td"); bool bIsNull = drv[dc.ColumnName] is System.DBNull; Literal ltrl = new Literal(); ltrl.Text += " 0 ? "checked>" : ">"); cell.Controls.Add(ltrl); row.Cells.Add(cell); } else { // 其他行 } } } }

如果有更多的嵌套级别,只需在ItemDataBound事件的末尾添加这些代码:

var lst1stLevel = (ListView)e.Item.FindControl("lst1stLevel"); populateLV(lst1stLevel, 1, (string)drv["hierarchy"], Convert.ToInt32(drv["rowNo"]));

其中populateLV()方法如下:

private void populateLV(ListView lv, int iNextGeneration, string sHierarchy, int iCurrRowNo) { if (lv != null) { DataTable dt = new DataTable(); dt = ((DataTable)ViewState["cachedTable"]).Clone(); List levels = ((DataTable)ViewState["cachedTable"]).Select("GENERATION = " + (iNextGeneration > 0 ? iNextGeneration - 1 : 0) + " AND hierarchy LIKE '" + sHierarchy + "%'").AsEnumerable().Select(al => Convert.ToInt32(al.Field("rowNo"))).Distinct().ToList(); if (levels.Count > 0 && levels.Min() == iCurrRowNo) { DataRow[] drResults = ((DataTable)ViewState["cachedTable"]).Select("GENERATION = " + iNextGeneration + " AND hierarchy LIKE '" + sHierarchy + "%'"); foreach (DataRow dr in drResults) { object[] obRow = dr.ItemArray; dt.Rows.Add(obRow); } lv.DataSource = dt; lv.DataBind(); } } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485