MS 的DataGrid 在数据呈现上非常好用,可在WEB打印时,无法在分页时每页都能显示表头,造成诸多不便。
经过一段时间的研究和资料搜索,找到一种解决办法:
要使打印时,每页都可显示表头,需要将 table 改造成 thead ,tbody,tfoot 分组。
现改造如下:
在WEB 应用程序项目中添加 WEB自定义控件,
代码如下:
其中的 namespace 名改为你当前项目的 namespace
namespace FullDataGridControl
{
using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Web.UI;
/// <summary>
/// FullDataGrid 的摘要说明。
/// </summary>
public class FullDataGrid : System.Web.UI.WebControls.DataGrid
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
writer.Write(this.ParsMarkupWithPrintStyle(ParseMarkup()));
}
/// <summary>
/// 去除 table 的 border 和 rules
/// </summary>
/// <param name="oldMarkup"></param>
/// <returns></returns>
private string ParsMarkupWithPrintStyle(string markup)
{
markup = markup.Replace("<td","<td style=\"BORDER-RIGHT:black 1px solid;BORDER-TOP:black 1px solid;BORDER-LEFT:black 1px solid;BORDER-BOTTOM:black 1px solid\"");
markup = markup.Replace("rules=\"all\"","");
markup = markup.Replace("border=\"1\"","border=\"0\"");
return markup;
}
/// <summary>
/// 插入 thead,tbody 元素
/// </summary>
/// <returns></returns>
private string ParseMarkup()
{
StringWriter writer = new StringWriter();
HtmlTextWriter buffer = new HtmlTextWriter(writer);
base.Render(buffer);
string markup = writer.ToString() ;
// <THEAD> 标签的位置 插在第一个 > 之后,即 <table> 之后
int theadStarPos = markup.IndexOf(">")+">".Length;
markup = markup.Insert(theadStarPos,"<thead style=\"DISPLAY:table-header-group;\">");
// </THEAD><TBODY> 标签的位置, 插在第一个 </tr> 之后
int theadEndPos = markup.IndexOf("</tr>")+"</tr>".Length;
markup = markup.Insert(theadEndPos,"</thead><tbody>");
// </TBODY> 插在原先的 </TABLE> 之前
int tbodyEndPos = markup.IndexOf("</table>");
markup = markup.Insert(tbodyEndPos,"</tbody><TFOOT style=\"DISPLAY: table-footer-group; FONT-WEIGHT: bold\">"+
"<tr><TD style=\"BORDER-TOP:black 1px solid\""+
" ></TD></TR></TFOOT>");
return markup;
}
}
}
{
using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Web.UI;
/// <summary>
/// FullDataGrid 的摘要说明。
/// </summary>
public class FullDataGrid : System.Web.UI.WebControls.DataGrid
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
writer.Write(this.ParsMarkupWithPrintStyle(ParseMarkup()));
}
/// <summary>
/// 去除 table 的 border 和 rules
/// </summary>
/// <param name="oldMarkup"></param>
/// <returns></returns>
private string ParsMarkupWithPrintStyle(string markup)
{
markup = markup.Replace("<td","<td style=\"BORDER-RIGHT:black 1px solid;BORDER-TOP:black 1px solid;BORDER-LEFT:black 1px solid;BORDER-BOTTOM:black 1px solid\"");
markup = markup.Replace("rules=\"all\"","");
markup = markup.Replace("border=\"1\"","border=\"0\"");
return markup;
}
/// <summary>
/// 插入 thead,tbody 元素
/// </summary>
/// <returns></returns>
private string ParseMarkup()
{
StringWriter writer = new StringWriter();
HtmlTextWriter buffer = new HtmlTextWriter(writer);
base.Render(buffer);
string markup = writer.ToString() ;
// <THEAD> 标签的位置 插在第一个 > 之后,即 <table> 之后
int theadStarPos = markup.IndexOf(">")+">".Length;
markup = markup.Insert(theadStarPos,"<thead style=\"DISPLAY:table-header-group;\">");
// </THEAD><TBODY> 标签的位置, 插在第一个 </tr> 之后
int theadEndPos = markup.IndexOf("</tr>")+"</tr>".Length;
markup = markup.Insert(theadEndPos,"</thead><tbody>");
// </TBODY> 插在原先的 </TABLE> 之前
int tbodyEndPos = markup.IndexOf("</table>");
markup = markup.Insert(tbodyEndPos,"</tbody><TFOOT style=\"DISPLAY: table-footer-group; FONT-WEIGHT: bold\">"+
"<tr><TD style=\"BORDER-TOP:black 1px solid\""+
" ></TD></TR></TFOOT>");
return markup;
}
}
}
简单改造完毕。
为何要去掉 原来系统自动生成的 rules="all" 而且将 border=1 改为0 呢?
rules="all" 表示全部显示线框(上下左右)
如果不去掉,在打印第一页之后的页面时,表头的顶部线条会消失,效果自然不理想。
所以干脆去掉原先表格的线条,自己添加每个 td 的 border . 也就是这行:
markup = markup.Replace("<td","<td style=\"BORDER-RIGHT:black 1px solid;BORDER-TOP:black 1px solid;BORDER-LEFT:black 1px solid;BORDER-BOTTOM:black 1px solid\"");
现做测试:
添加一个 WEBFORM,名为 FullDataGridTest.aspx
HTML 页代码如下:
<%@ Register TagPrefix="FullDataGridControl" Assembly="FullDataGridControl" Namespace="FullDataGridControl"%>
<%@ Page language="c#" Codebehind="FullDataGridTest.aspx.cs" AutoEventWireup="false" Inherits="FullDataGridControl.FullDataGridTest" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>FullDataGridTest</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
<style media="print">
.noprint{display:none;}
}
.nextpage {
PAGE-BREAK-AFTER: always
}
</style>
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<FullDataGridControl:FullDataGrid id="FullDataGrid1" runat="Server">
</FullDataGridControl:FullDataGrid>
</form>
</body>
</HTML>
<%@ Page language="c#" Codebehind="FullDataGridTest.aspx.cs" AutoEventWireup="false" Inherits="FullDataGridControl.FullDataGridTest" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>FullDataGridTest</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
<style media="print">
.noprint{display:none;}
}
.nextpage {
PAGE-BREAK-AFTER: always
}
</style>
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<FullDataGridControl:FullDataGrid id="FullDataGrid1" runat="Server">
</FullDataGridControl:FullDataGrid>
</form>
</body>
</HTML>
HTML代码很简单,只是要注意下 style media="print" ,该样式只在打印时有用。
noprint 即不打印输出, nextpage 为分页点
后台 cs 代码如下:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace FullDataGridControl
{
/// <summary>
/// FullDataGridTest 的摘要说明。
/// </summary>
public class FullDataGridTest : System.Web.UI.Page
{
protected FullDataGrid FullDataGrid1;
private void Page_Load(object sender, System.EventArgs e)
{
string[] strArr = new string[80];
for(int i=0;i<strArr.Length;i++)
{
strArr[i] = "a";
}
FullDataGrid1.DataSource = strArr;
FullDataGrid1.DataBind();
for(int i=30;i<FullDataGrid1.Items.Count;i+=30)
{
FullDataGrid1.Items[i].CssClass = "nextpage";
}
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace FullDataGridControl
{
/// <summary>
/// FullDataGridTest 的摘要说明。
/// </summary>
public class FullDataGridTest : System.Web.UI.Page
{
protected FullDataGrid FullDataGrid1;
private void Page_Load(object sender, System.EventArgs e)
{
string[] strArr = new string[80];
for(int i=0;i<strArr.Length;i++)
{
strArr[i] = "a";
}
FullDataGrid1.DataSource = strArr;
FullDataGrid1.DataBind();
for(int i=30;i<FullDataGrid1.Items.Count;i+=30)
{
FullDataGrid1.Items[i].CssClass = "nextpage";
}
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}