如何枚举ASP ListView控件?求助从控件还原为List的方法
解决ASP.NET ListView还原数据为List时DataItems为null的问题
我明白你遇到的困扰了——你已经成功把List转换成DataTable绑定到ListView,但想反向把ListView的数据还原成List时,发现DataItems集合是null,明明计数是对的却拿不到实际值,没法枚举所有行对吧?这其实是ASP.NET ListView的一个常见特性,我来给你拆解下原因和解决办法:
为什么DataItems会是null?
DataItems集合仅在数据绑定的过程中(比如调用DataBind()方法后的短时间窗口内)有效。当页面完成渲染、或者发生回发后,这个集合就会被清空变成null。而你需要的是遍历ListView实际渲染出来的控件项,也就是Items集合,它才是页面上真实存在的控件容器。
两种解决方案
方案一:直接复用原始数据源(最简单)
如果可以的话,在绑定ListView的时候,把原始的DataTable或者List存在ViewState里,之后要还原数据时直接从这里取,不用从控件里逐个提取值:
// 修改你的createLvwTable方法,把DataTable存到ViewState private void createLvwTable(List<string> table) { int index = 0; DataTable dt = new DataTable(); foreach (string row in table) { string[] cells = row.Split('|'); if (index == 0) // 处理表头列 { for (int j = 0; j < cells.Length; j++) { dt.Columns.Add(cells[j]); } } else { DataRow dr = dt.NewRow(); for (int j = 0; j < cells.Length; j++) { dr[j] = cells[j]; } dt.Rows.Add(dr); } index++; } // 把DataTable存入ViewState,方便后续还原 ViewState["ListViewSourceData"] = dt; lvwOutput.DataSource = dt; lvwOutput.DataBind(); } // 还原成List<string>的方法 private List<string> RestoreListViewDataFromViewState() { List<string> restoredList = new List<string>(); if (ViewState["ListViewSourceData"] is DataTable dt) { // 先添加表头 string header = string.Join("|", dt.Columns.Cast<DataColumn>().Select(col => col.ColumnName)); restoredList.Add(header); // 遍历数据行,转换成|分隔的字符串 foreach (DataRow row in dt.Rows) { string rowStr = string.Join("|", row.ItemArray); restoredList.Add(rowStr); } } return restoredList; }
方案二:从ListView的Items集合提取数据
如果没办法保存原始数据源,那就直接遍历Items集合,从每个数据项的控件里提取值。这里需要注意你ListView的ItemTemplate结构,比如如果是用Table布局,或者用Label等控件显示数据:
private List<string> RestoreListViewDataFromItems() { List<string> restoredList = new List<string>(); // 先提取表头(如果ListView有HeaderTemplate的话) if (lvwOutput.HeaderRow != null) { List<string> headerCells = new List<string>(); foreach (TableCell cell in lvwOutput.HeaderRow.Cells) { headerCells.Add(cell.Text.Trim()); } restoredList.Add(string.Join("|", headerCells)); } // 遍历所有数据项 foreach (ListViewItem item in lvwOutput.Items) { if (item.ItemType == ListViewItemType.DataItem) { List<string> rowCells = new List<string>(); // 情况1:如果是Table布局的ListView,直接遍历单元格 var tableRow = item.Controls.OfType<Table>().FirstOrDefault()?.Rows[0]; if (tableRow != null) { foreach (TableCell cell in tableRow.Cells) { rowCells.Add(cell.Text.Trim()); } } // 情况2:如果是用Label等控件绑定数据,通过FindControl获取 // 比如你的ItemTemplate里有多个Label,ID分别是lblCol1、lblCol2... // rowCells.Add(((Label)item.FindControl("lblCol1")).Text.Trim()); // rowCells.Add(((Label)item.FindControl("lblCol2")).Text.Trim()); restoredList.Add(string.Join("|", rowCells)); } } return restoredList; }
注意事项
- 确保ListView的
ViewStateMode设置为Enabled(默认是开启的),否则回发时Items集合也会是空的。 - 如果你的ListView是动态生成的模板,调用
FindControl时要注意控件的层级结构,可能需要递归查找。
你提供的原始绑定代码:
private void createLvwTable(List<string> table) { int index = 0; DataTable dt = new DataTable(); foreach (string row in table) { string[] cells = row.Split('|'); if (index == 0) // header column { for (int j = 0; j < cells.Length; j++) { dt.Columns.Add(cells[j]); //dt.Rows.Add(); } } else { DataRow dr = dt.NewRow(); for (int j = 0; j < cells.Length; j++) { dr[j] = cells[j]; } dt.Rows.Add(dr); } index++; } lvwOutput.DataSource = dt; lvwOutput.DataBind(); }
内容的提问来源于stack exchange,提问作者Bbb
相关产品推荐
相关产品推荐

