GridView合并表头与行的反思
ASP.NET的GRIDVIEW确实很强大,任何一个入门的人绝对不可能忽视它。只需要指定一个数据源然后绑定,数据就呈现出来了。如果数据量不大,连分页都省了。曾几何时,我也觉得GRIDVIEW是多么的完美,于是乎网上到处学习GRIDVIEW的种种技巧。自然而然的就接触到了XX月儿的“GRIDVIEW七十二般技巧”,不得不佩服作者的研究功底还是很牛x的。但是最近遇到一个需求就是合并表头和一列中内容相同的行。由于数据呈现用的是GRIDVIEW,于是本能地在BAIDU搜索“GRIDVIEW合并表头”、“GRIDVIEW合并行”。虽然最终找到了答案,但是我却很失望。为什么这样一个功能需要在服务器端编写大量的代码?我不知道有多少人为了实现这个功能而去真正的研究了解GRIDVIEW的各种属性、方法、事件,但是我可以肯定的是如果下次作为面试题出现了,我反正仍然不会。后来思索了一段时间,觉得,这个功能用JS不是很方便很快捷吗?如果呈现数据使用REPEATER那就更加方便了,几行简单的JS代码就搞定了,为什么要搞的这么复杂?
于是乎我开始反思,GRIDVIEW真的那么好吗?为什么它令我们变得更加愚钝?它又是如何阻碍了我们编程思维的发展?下面就关于GRIDVIEW合并行(这个答案我就不提供了,网上很多),给出我实际中的解决方案(稍微懂点Javascript就行了),依此来解释之。
于是乎我开始反思,GRIDVIEW真的那么好吗?为什么它令我们变得更加愚钝?它又是如何阻碍了我们编程思维的发展?下面就关于GRIDVIEW合并行(这个答案我就不提供了,网上很多),给出我实际中的解决方案(稍微懂点Javascript就行了),依此来解释之。
我的思路:找到表格待合并的那一列(TD元素),如果它们的内容相同,就把这些TD合并(设置其属性rowSpan)。现在的关键就是如何找到这一列。我采用给td同时设置id和name的方法(当然VS会提示你name不是td的有效属性,不过不用管它),设置相同的id是为了兼容IE,因为IE的document.getElementByName()仍然是使用id去查找元素,而FireFox则不是。
后台代码:
代码
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class MergeCell : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Repeater1.DataSource = RetriveData();
Repeater1.DataBind();
}
}
private DataTable RetriveData()
{
var dt = new DataTable();
dt.Columns.Add("country");
dt.Columns.Add("city");
dt.Columns.Add("address");
AddRow("中国", "武汉", "武汉大学", ref dt);
AddRow("中国", "武汉", "华中科技大学", ref dt);
AddRow("美国", "波士顿", "哈佛大学", ref dt);
AddRow("美国", "波士顿", "麻省理工大学", ref dt);
AddRow("英国", "牛津", "牛津大学", ref dt);
return dt;
}
private void AddRow(string country, string city, string address,ref DataTable dt)
{
var row = dt.NewRow();
row[0] = country;
row[1] = city;
row[2] = address;
dt.Rows.Add(row);
}
}
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class MergeCell : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Repeater1.DataSource = RetriveData();
Repeater1.DataBind();
}
}
private DataTable RetriveData()
{
var dt = new DataTable();
dt.Columns.Add("country");
dt.Columns.Add("city");
dt.Columns.Add("address");
AddRow("中国", "武汉", "武汉大学", ref dt);
AddRow("中国", "武汉", "华中科技大学", ref dt);
AddRow("美国", "波士顿", "哈佛大学", ref dt);
AddRow("美国", "波士顿", "麻省理工大学", ref dt);
AddRow("英国", "牛津", "牛津大学", ref dt);
return dt;
}
private void AddRow(string country, string city, string address,ref DataTable dt)
{
var row = dt.NewRow();
row[0] = country;
row[1] = city;
row[2] = address;
dt.Rows.Add(row);
}
}
前台代码:
代码
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="MergeCell.aspx.cs" Inherits="MergeCell" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>
<style type="text/css">
BODY {
background: #e6eae9
}
TABLE
{
padding:0px 0px 0px 0px;
margin:0px;
width:800px;
}
TH {
BORDER-BOTTOM: #c1dad7 1px solid; TEXT-ALIGN: center; PADDING-BOTTOM: 6px; TEXT-TRANSFORM: uppercase; PADDING-LEFT: 12px; PADDING-RIGHT: 6px; FONT: bold 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; BACKGROUND: url(images/bg_header.jpg) #cae8ea no-repeat; LETTER-SPACING: 2px; COLOR: #4f6b72; BORDER-TOP: #c1dad7 1px solid; BORDER-RIGHT: #c1dad7 1px solid; PADDING-TOP: 6px
}
TD {
BORDER-BOTTOM: #c1dad7 1px solid; PADDING-BOTTOM: 6px; PADDING-LEFT: 12px; PADDING-RIGHT: 6px; BACKGROUND: #fff; COLOR: #4f6b72; FONT-SIZE: 11px; BORDER-RIGHT: #c1dad7 1px solid; PADDING-TOP: 6px
}
</style>
<script language="javascript" type="text/javascript">
function mergeCell(column)
{
var tds=document.getElementsByName(column);
for(var i=tds.length-1;i>0;i--)
{
var current=tds[i];
var pre=tds[i-1];
if(current.innerHTML==pre.innerHTML)
{pre.rowSpan=current.rowSpan+1;current.parentNode.removeChild(current);}
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater ID="Repeater1" runat="server">
<HeaderTemplate>
<table>
<tr>
<th>国籍</th>
<th>城市</th>
<th>地址</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr><td id="column1" name="column1"> <%#Eval("country") %></td>
<td id="column2" name="column2"> <%#Eval("city") %></td>
<td id="column3" name="column3"> <%#Eval("address") %></td> </tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</div>
<input id="Button1" type="button" value="开始合并行" onclick="mergeCell('column1');mergeCell('column2');" />
</form>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>
<style type="text/css">
BODY {
background: #e6eae9
}
TABLE
{
padding:0px 0px 0px 0px;
margin:0px;
width:800px;
}
TH {
BORDER-BOTTOM: #c1dad7 1px solid; TEXT-ALIGN: center; PADDING-BOTTOM: 6px; TEXT-TRANSFORM: uppercase; PADDING-LEFT: 12px; PADDING-RIGHT: 6px; FONT: bold 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; BACKGROUND: url(images/bg_header.jpg) #cae8ea no-repeat; LETTER-SPACING: 2px; COLOR: #4f6b72; BORDER-TOP: #c1dad7 1px solid; BORDER-RIGHT: #c1dad7 1px solid; PADDING-TOP: 6px
}
TD {
BORDER-BOTTOM: #c1dad7 1px solid; PADDING-BOTTOM: 6px; PADDING-LEFT: 12px; PADDING-RIGHT: 6px; BACKGROUND: #fff; COLOR: #4f6b72; FONT-SIZE: 11px; BORDER-RIGHT: #c1dad7 1px solid; PADDING-TOP: 6px
}
</style>
<script language="javascript" type="text/javascript">
function mergeCell(column)
{
var tds=document.getElementsByName(column);
for(var i=tds.length-1;i>0;i--)
{
var current=tds[i];
var pre=tds[i-1];
if(current.innerHTML==pre.innerHTML)
{pre.rowSpan=current.rowSpan+1;current.parentNode.removeChild(current);}
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater ID="Repeater1" runat="server">
<HeaderTemplate>
<table>
<tr>
<th>国籍</th>
<th>城市</th>
<th>地址</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr><td id="column1" name="column1"> <%#Eval("country") %></td>
<td id="column2" name="column2"> <%#Eval("city") %></td>
<td id="column3" name="column3"> <%#Eval("address") %></td> </tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</div>
<input id="Button1" type="button" value="开始合并行" onclick="mergeCell('column1');mergeCell('column2');" />
</form>
</body>
</html>
合并前效果:
合并后效果:
个人觉得使用GridView最大的坏处就是阻碍了ASP.NET程序员AJAX的学习步伐,大家花费了大量时间去研究GRIDVIEW的复杂属性和复杂事件,最后得到的很可能却是效率极端低下的解决方案。ASP.NET程序员属于Web程序员的子集,HTML和JavaScript是必须要熟悉的(想想如果有天你去做JSP或者PHP),很多需求其实换一种思路更加简洁,不要把你的编程思路和精力局限在复杂的服务器控件上,使用最原始的方法往往是最通用和最易于掌握的方法。