目录
关于 HtmlTable
数据感应也即数据捆绑,是一种动态的,Web控件与数据源之间的交互,HtmlTable 控件表示为一个服务器控件,隶属于 System.Web.UI.HtmlControls 集合,对于客户端输出即 table 标签元素,table 表格的主要作用就是数据输出 ,本文将介绍 C# 实现操作 HtmlTable 服务器控件实现数据集表数据的轻量化输出与显示。
HtmlTable与BaseDataList的区别
HtmlTable 与诸如 DataGrid、GridView 都可用于数据输出 ,主要区别在于:
(1)前者以属于System.Web.UI.HtmlControls 集合,后者 Microsoft.Web.UI.WebControls 集合
(2)HtmlTable 可实现 table 元素的一些操作,如行、列、单元格及样式设置,而 BaseDataList 除可实现 HtmlTable 的基本控制外,还可以绑定数据源、绑定事件、绑定列控件等更加强大的功能。
(3)对于数据集合访问 HtmlTable 通过 Rows ,列集合为 Cells;而 BaseDataList 通过 Items ,列集合为 Colums。
准备数据源
我们在 MS SQL Server 创建 pub_ChinaPay(支付状态代码表),其结构如下表:
序号 | 字段名 | 类型 | 说明 |
---|---|---|---|
1 | value | char(4) | 支付状态代码,唯一键 |
2 | text | nvarchar(14) | 状态名称 |
3 | sortid | smallint | 排序号 |
执行如下 创建表的 SQL 语句:
CREATE TABLE [dbo].[pub_ChinaPay]( [value] [char](4) NOT NULL, [text] [nvarchar](14) NOT NULL, [sortid] [smallint] NULL, CONSTRAINT [PK_pub_ChinaPay] PRIMARY KEY CLUSTERED ( [value] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
执行如下SQL语句,创建一些数据:
insert into pub_ChinaPay(value,text,sortid) values('****','默认状态',1) insert into pub_ChinaPay(value,text,sortid) values(' ','待支付',2) insert into pub_ChinaPay(value,text,sortid) values('1001','消费交易成功',3) insert into pub_ChinaPay(value,text,sortid) values('1003','退款提交成功',4) insert into pub_ChinaPay(value,text,sortid) values('1005','退款撤销成功',5) insert into pub_ChinaPay(value,text,sortid) values('0003','交易失败',6) insert into pub_ChinaPay(value,text,sortid) values('6666','微信退款申请成功',7)
通过查询分析器,执行查询SQL语句,显示如下图:
最后我们将数据填充到 DataReader ,并生成对应的二维数组。
范例运行环境
操作系统: Windows Server 2019 DataCenter
数据库:Microsoft SQL Server 2016
.net版本: .netFramework4.0 或以上
开发工具:VS2019 C#
FillTable 方法
设计与实现
FillTable 方法主要是通过 object[,] 二维对象数组数据源进行提取并呈现在 HtmlTable 表格控件上,其参数设置见下表:
序号 | 参数名 | 类型 | 说明 |
---|---|---|---|
1 | tb | System.Web.UI.HtmlControls.HtmlTable | 要输出的 HtmlTable 对象 |
2 | ft | FillType | 填充模式枚举: public enum FillType StaticRows 后续将讲解这些模式的区别 |
3 | SpaceInEmptyCell | bool | 对于空字符串输出,是否替换为  输出以达到更好的显示效果 |
4 | MinClearRowsCount | int | 当输出数据行为空时,清除模板表格行的阀值,设为0,则表示全部清空,不显示输出表格的任何元素 |
5 | refStartRowId | int | 指定数据输出的起始行 |
6 | refCopyRowId | int | 指定要复制哪一行的格式进行输出 |
7 | allowToHTML | bool | 是否允许将数据解析为HTML样式输出,默认为 false |
GetReaderData 方法可以访问数据库数据表进行查询结果的提取,并转化为 object[,] 二维数组,其参数设置见下表:
序号 | 参数名 | 类型 | 说明 |
---|---|---|---|
1 | DbServerType | string | 目前支持 "oracle"、 "dm8",其它字符串均视为 MS SQL Server |
strConn | string | 对应数据库的连接字符串 | |
2 | _sql | string | 要执行的SQL语句命令行 |
3 | paras | ArrayList | 要赋值的参数对象,逐个添加到ArrayList里,请注意参数为实体数据参数对象,如 MS SQL Server ,请传递如下代码: ArrayList.Add(new SqlParameter("参数名",参数值)); |
4 | hastitle | bool | 输出是否包含字段列标题 |
5 | ct | CommandType | System.Data.CommandType 枚举,可包括: StoredProcedure(存储过程) |
GetReaderData 方法实现代码如下:
int RowsCount = 0; int ErrorNum = 0; string ErrorMessage = ""; public object[,] GetReaderData(string DbServerType,string strConn,string _sql,ArrayList paras,bool hastitle,CommandType ct) { if((DbServerType.ToLower()=="")||(DbServerType.ToLower()=="sqlserver")) { SqlConnection Conn = new SqlConnection(strConn ); SqlCommand Cmd = new SqlCommand(); Cmd.CommandType=ct; Cmd.Connection = Conn; SqlDataReader myDr; Cmd.CommandText =_sql; if(paras!=null) { for(int i=0;i<paras.Count;i++) { Cmd.Parameters.Add((SqlParameter)paras[i]); } } try { Conn.Open(); myDr = Cmd.ExecuteReader(); ArrayList rowdata = new ArrayList(); int _fieldcount=myDr.FieldCount; Object[] colvalues = new Object[_fieldcount]; for(int i=0;i<_fieldcount;i++) { colvalues[i]=myDr.GetName(i); } if(hastitle) rowdata.Add(colvalues); while(myDr.Read()) { Object[] values = new Object[_fieldcount]; myDr.GetValues(values); rowdata.Add(values); RowsCount++; } myDr.Close(); object[,] rv=new object[rowdata.Count,_fieldcount]; for(int i=0;i<rowdata.Count;i++) { for(int j=0;j<_fieldcount;j++) { rv[i,j]=((object[])rowdata[i])[j]; } } return rv; } catch (SqlException e) { ErrorMessage=e.Message; return null; } finally { Conn.Close(); Conn.Dispose(); } }//sqlserver if(DbServerType.ToLower()=="oracle") { OracleConnection Conn = new OracleConnection(strConn ); OracleCommand Cmd = new OracleCommand(); Cmd.Connection = Conn; OracleDataReader myDr; Cmd.CommandText =_sql; if(paras!=null) { for(int i=0;i<paras.Count;i++) { Cmd.Parameters.Add((OracleParameter)paras[i]); } } try { Conn.Open(); myDr = Cmd.ExecuteReader(); ArrayList rowdata = new ArrayList(); int _fieldcount=myDr.FieldCount; Object[] colvalues = new Object[_fieldcount]; for(int i=0;i<_fieldcount;i++) { colvalues[i]=myDr.GetName(i); } if(hastitle) rowdata.Add(colvalues); while(myDr.Read()) { Object[] values = new Object[_fieldcount]; myDr.GetValues(values); rowdata.Add(values); RowsCount++; } myDr.Close(); object[,] rv=new object[rowdata.Count,_fieldcount]; for(int i=0;i<rowdata.Count;i++) { for(int j=0;j<_fieldcount;j++) { rv[i,j]=((object[])rowdata[i])[j]; } } return rv; } catch (OracleException e) { ErrorMessage=e.Message; return null; } finally { Conn.Close(); Conn.Dispose(); } }//oracle if (DbServerType.ToLower() == "dm8") { DmConnection Conn = new DmConnection(strConn); DmCommand Cmd = new DmCommand(); Cmd.CommandType = ct; Cmd.Connection = Conn; DmDataReader myDr; Cmd.CommandText = _sql; if (paras != null) { for (int i = 0; i < paras.Count; i++) { Cmd.Parameters.Add((DmParameter)paras[i]); } } try { Conn.Open(); myDr = Cmd.ExecuteReader() as DmDataReader; ArrayList rowdata = new ArrayList(); int _fieldcount = myDr.FieldCount; Object[] colvalues = new Object[_fieldcount]; for (int i = 0; i < _fieldcount; i++) { colvalues[i] = myDr.GetName(i); } if (hastitle) rowdata.Add(colvalues); while (myDr.Read()) { Object[] values = new Object[_fieldcount]; myDr.GetValues(values); rowdata.Add(values); RowsCount++; } myDr.Close(); object[,] rv = new object[rowdata.Count, _fieldcount]; for (int i = 0; i < rowdata.Count; i++) { for (int j = 0; j < _fieldcount; j++) { rv[i, j] = ((object[])rowdata[i])[j]; } } return rv; } catch (DmException e) { ErrorMessage = e.Message; return null; } finally { Conn.Close(); Conn.Dispose(); } }//dm8 return null; }//getreaddata
FillTable 方法实现代码如下:
ArrayList paras=new ArrayList(); string refSql=""; bool hastitle=false; System.Data.CommandType ct=System.Data.CommandType.Text; public void FillTable(HtmlTable tb, FillType ft, bool SpaceInEmptyCell, int MinClearRowsCount, int refStartRowId,int refCopyRowId,bool allowToHTML) { object[,] ReaderData = GetReaderData("SqlServer","您的连接串","",paras,hastitle,ct); if (ReaderData == null && RowsCount==0) { while (tb.Rows.Count > MinClearRowsCount) { tb.Rows.RemoveAt(tb.Rows.Count - 1); } return; } if (ft == FillType.Automatic || ft==FillType.DynamicRows || ft==FillType.StaticRows) { if (ft == FillType.Automatic) { int addcells = ReaderData.GetLength(1) - tb.Rows[0].Cells.Count; for (int i = 0; i < tb.Rows.Count; i++) { for (int j = 0; j < addcells; j++) { HtmlTableCell tc = new HtmlTableCell(); if (allowToHTML == true) { tc.Attributes.Add("ByHTML", "true"); } tb.Rows[i].Cells.Add(tc); } } if (tb.Rows.Count == 2) { for (int j = 0; j < ReaderData.GetLength(1); j++) { string _fieldname = ReaderData[0, j].ToString(); tb.Rows[0].Cells[j].InnerText = _fieldname; } } } int startRowID = tb.Rows.Count - 1; int copyRowID = 0; if (ft == FillType.StaticRows) { if (HasTitle == true) { startRowID = tb.Rows.Count > 1 ? 1 : 0; } else { startRowID = 0; } } if (refStartRowId != -1) startRowID = refStartRowId; if (refCopyRowId != -1) copyRowID = refCopyRowId; for (int i = (HasTitle == true ? 1 : 0); i < ReaderData.GetLength(0); i++) { if (startRowID>tb.Rows.Count-1) break; for (int j = 0; j < ReaderData.GetLength(1); j++) { if (j > tb.Rows[copyRowID].Cells.Count - 1) break; HtmlTableCell td = tb.Rows[startRowID].Cells[j]; if (td.Attributes["ByHTML"] == null) { td.InnerText = ReaderData[i, j].ToString(); } else { td.InnerHtml = allowToHTML == true ? (ReaderData[i, j].ToString()) : ReaderData[i, j].ToString();; } if (td.InnerText == "" && SpaceInEmptyCell == true) td.InnerHtml=" "; } if (i == ReaderData.GetLength(0)-1) break; if (ft == FillType.Automatic || ft == FillType.DynamicRows) { HtmlTableRow tr = new HtmlTableRow(); tb.Rows.Add(tr); for (int k = 0; k < tb.Rows[copyRowID].Cells.Count; k++) { HtmlTableCell prv_tc = tb.Rows[startRowID].Cells[k]; HtmlTableCell tc = new HtmlTableCell(); tr.Cells.Add(tc); CloneStyles(prv_tc, tc); } } startRowID ++; } } }//fill table void CloneStyles(HtmlControl obj, HtmlControl newobj) { IEnumerator keys = obj.Style.Keys.GetEnumerator(); while (keys.MoveNext()) { String key = (String)keys.Current; newobj.Style[key] = obj.Style[key]; } IEnumerator keys2 = obj.Attributes.Keys.GetEnumerator(); while (keys2.MoveNext()) { String key = (String)keys2.Current; newobj.Attributes[key] = obj.Attributes[key]; } }
模板样例输出
在方法设计的章节里介绍了 FillType (即填充类型的枚举)
Automatic 模式填充
全自动填充,表示行、列均不固定,全由SQL查询结果动态输出,仅设置首行首列的样式即可,如下图:
前端代码示例 :
<table id="tjTable" runat="server" align="center" border="1" style="width: 700px; border:1px solid #000000;border-collapse:collapse"> <tr><td>标题</td></tr> <tr> <td> </td> </tr> </table>
调用示例如下代码:
string refSQL = "select value,text,sortid from pub_chinaPay order by sortid"; FillTable(tjTable, FillType.Automatic, true, 0, 1, 1);
输出结果如下图
可以看到行列完全由SQL语句决定进行原始输出,行与列均为动态输出 。
DynamicRows 模式填充
动态行填充,表示行输出不固定,已预知列的输出,仅需要设置首行标题列和数据行的样式即可,如下图:
前端代码示例 :
<table id="tjTable" runat="server" align="center" border="1" style="width: 700px; border:1px solid #000000;border-collapse:collapse"> <tr> <td> 状态代码</td> <td> 状态名称</td> <td> 排序号</td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> </table>
调用示例如下代码:
string refSQL = "select value,text,sortid from pub_chinaPay order by sortid"; FillTable(tjTable, FillType.DynamicRows, true, 0, 1, 1);
输出结果如下图
可以看到行为动态输出,标题列为预期的设置 。
StaticRows 模式填充
静态填充,表示行、列均固定,由SQL查询结果根据预设输出,可设置每行每列的样式,如下图:
前端代码示例 :
<table id="tjTable" runat="server" align="center" border="1" style="width: 700px; border:1px solid #000000;border-collapse:collapse"> <tr> <td> 状态代码</td> <td> 状态名称</td> <td> 排序号</td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> </table>
调用示例如下代码:
string refSQL = "select value,text,sortid from pub_chinaPay order by sortid"; FillTable(tjTable,FillType.StaticRows, true, 0, 1, 1);
输出结果如下图
可以看到行有冗余,因此静态行模式仅输出列和行的可见区域,即溢出和不足均不显示 。
小结
关于 HtmlTable 的其它详细操作和介绍,可参照如下链接:
关于填充模式,是在实际的应用场景里进行输出 ,比如全动态适合于依赖SQL语句控制度较高的场景,而动态行则是比较常见的一种输出方式,静态行输出则比如我们提供一种填写表格,已经预设好最大行数,为体现整体统一的输出风格而应用。所以,我们可以根据自己的实际需要改造输出 的模式,本示例代码仅供您参考。
感谢您的阅读,希望本文能够对您有所帮助。