asp.net中进行客户端打印

时间:2006/6/20 17:58:11      阅读:5915          

      大家在一直都在关心Asp.net中是如何进行客户端打印的,比如报表、发票什么的。俺找了一些资料,没来得及详细研究,只是试用了一下,值得收藏,拿出来跟大家一起分享

<!--语言无关 保存成 .HTML 看看-->
<html>
<head>
<meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
<title>web3.cn——asp.net中进行客户端打印</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<!--media=print 这个属性可以在打印时有效-->
<style media=print>
.Noprint{display:none;}
.PageNext{page-break-after: always;}
</style>

<style>
.tdp
{
    border-bottom: 1 solid #000000;
    border-left:  1 solid #000000;
    border-right:  0 solid #ffffff;
    border-top: 0 solid #ffffff;
}
.tabp
{
    border-color: #000000 #000000 #000000 #000000;
    border-style: solid;
    border-top-width: 2px;
    border-right-width: 2px;
    border-bottom-width: 1px;
    border-left-width: 1px;
}
.NOPRINT {
font-family: "宋体";
font-size: 9pt;
}

</style>

</head>

<body >
<center class="Noprint" >
  <p>
  <OBJECT  id=WebBrowser  classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2  height=0  width=0>
  </OBJECT>
  <input  type=button  value=打印 onclick=document.all.WebBrowser.ExecWB(6,1)>
  <input  type=button  value=直接打印 onclick=document.all.WebBrowser.ExecWB(6,6)>
  <input  type=button  value=页面设置 onclick=document.all.WebBrowser.ExecWB(8,1)>
</p>
  <p>    <input  type=button  value=打印预览  onclick=document.all.WebBrowser.ExecWB(7,1)>
    <br/>
    </p>
  <hr align="center" width="90%" size="1" noshade>
</center>

<table width="90%" border="0" align="center" cellpadding="2" cellspacing="0"  class="tabp">
<tr>
  <td colspan="3" class="tdp">第1页</td>
    </tr>
<tr>
   <td width="29%" class="tdp">&nbsp;</td>
   <td width="28%" class="tdp">&nbsp;</td>
      <td width="43%" class="tdp">&nbsp;</td>
  </tr>
<tr>
   <td colspan="3" class="tdp">&nbsp;</td>
  </tr>
<tr>
   <td colspan="3" class="tdp"><table width="100%"  border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td width="50%" class="tdp"><p>这样的报表</p>
          <p>对一般的要求就够了。</p></td>
          <td>&nbsp;</td>
        </tr>
      </table></td>
  </tr>
</table>
<hr align="center" width="90%" size="1" noshade class="NOPRINT" >
<!--分页-->
<div class="PageNext"></div>
<table width="90%" border="0" align="center" cellpadding="2" cellspacing="0"  class="tabp">
  <tr>
    <td class="tdp">第2页</td>
  </tr>
  <tr>
    <td class="tdp">看到分页了吧</td>
  </tr>
  <tr>
    <td class="tdp">&nbsp;</td>
  </tr>
  <tr>
    <td class="tdp">&nbsp;</td>
  </tr>
  <tr>
    <td class="tdp"><table width="100%"  border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td width="50%" class="tdp"><p>这样的报表</p>
              <p>对一般的要求就够了。</p></td>
          <td>&nbsp;</td>
        </tr>
    </table></td>
  </tr>
</table>
</body>
</html>

简单懂得 HTML CSS 即可。
1.下面样式只在打印时有用<style media=print>

<style media=print>
.Noprint
{display:none;}
.PageNext
{page-break-after: always;}
</style>

WebBrowser 控件对象。只要是 win98 以上版本都有。
其实配合“分页样式表”,和 HTML表格 一般的打印都可以实现的。

如果想对 非Windows平台用户使用。
请去掉下面这些:

<center class="Noprint" >
  <p>
2.<!--最主要是这个-->
  <OBJECT  id=WebBrowser  classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2  height=0  width=0>
  </OBJECT>
  <input  type=button  value=打印          onclick=document.all.WebBrowser.ExecWB(6,1)>
  <input  type=button  value=直接打印  onclick=document.all.WebBrowser.ExecWB(6,6)>
  <input  type=button  value=页面设置  onclick=document.all.WebBrowser.ExecWB(8,1)>
</p>
  <p>    <input  type=button  value=打印预览  onclick=document.all.WebBrowser.ExecWB(7,1)>
    <br/>
    </p>
  <hr align="center" width="90%" size="1" noshade>
</center>

  3.关于这个组件还有其他的用法,列举如下:  
WebBrowser.ExecWB(1,1) 打开  
Web.ExecWB(2,1) 关闭现在所有的IE窗口,并打开一个新窗口  
Web.ExecWB(4,1) 保存网页  
Web.ExecWB(6,1) 打印  
Web.ExecWB(7,1) 打印预览  
Web.ExecWB(8,1) 打印页面设置  
Web.ExecWB(10,1) 查看页面属性  
Web.ExecWB(15,1) 好像是撤销,有待确认  
Web.ExecWB(17,1) 全选  
Web.ExecWB(22,1) 刷新  
Web.ExecWB(45,1) 关闭窗体无提示  

WEB打印精确控制:IE6.0打印机制解析

二.LayoutRect ,定义页面内容风格:

跟 DeviceRect 一样,不同的页面,要进行 LayoutRect 引用时都需要添加 LayoutRect 标记,其智能添加方法将在后面介绍; LayoutRect 与 DeviceRect 如果在同一个页面中同时出现,则前者需放在后者之内;另外, LayoutRect 对内容风格的设定,也通过 Style 得以实现。

例二:我们来定制如下的内容风格的打印模板:(详情见 2.htm)

5.5 inches 宽
8 inches 高
与打印纸张边缘,四边保持 1 inch 的宽度(加上页面本身的边缘宽度,为实际的打印边缘宽度)
白色背景
1 inch 宽的虚线边界

先定制名为 contentstyle 的风格:

<STYLE TYPE="text/css">
.contentstyle
{
width:5.5in;
height:8in;
margin:1in;
background:white;
border:1 dashed gray;
}
</STYLE>

然后下面是进行引用的完整网页代码:

<HTML>
<HEAD>
<IMPORT NAMESPACE="IE" IMPLEMENTATION="#default">
<STYLE TYPE="text/css">
.contentstyle
{
width:5.5in;
height:8in;
margin:1in;
background:white;
border:1 dashed gray;
}
</STYLE>
</HEAD>

<BODY>
<IE:LAYOUTRECT ID="layoutrect1" CONTENTSRC="2.html" CLASS="contentstyle" NEXTRECT="layoutrect2"/>

<IE:LAYOUTRECT ID="layoutrect2" CLASS="contentstyle"/>
</BODY>
</HTML>

跟例一中的源代码相比,例二中只是以 LayoutRect 代替了原来的 DeviceRect 标记;DeviceRect 定制的是模板整体风格,而 LayoutRect 定制的是具体内容的版面风格;LayoutRect 的 ID 属性也具有唯一性; CONTENTSRC 属性则指明了具体的将起作用网页文件;CLASS 指明了风格的引用对象;跟 DeviceRect 不同,在进行 LayoutRect 引用时,必须在每个页面指定 NEXTREC ,即依次排列的下一个内容风格,这里的"下一个内容"用其页面的相应 ID 进行标识,如本例中的 LayoutRect2 。

三.DeviceRect 与 LayoutRect 的协同作战:

上面我们分别讨论了 DeviceRect 与 LayoutRect 的作用与引用方法,现在我们来看一下,如何在同一个打印模板中进行定制与引用。

在每一个打印模板上,必然包含两方面的内容,一个是整体的模板风格(DeviceRect),另一个是内容风格(LayoutRect);第一个打印页面跟其他页面是不同的,因为第一个页面中必须指明 CONTENTSRC 属性,而同一打印任务中的其他页面不再需要进行 CONTENTSRC 的指定。

例三:(详细情况见 3.htm)

下面是第一个页面中的 DeviceRect 代码:

<IE:DEVICERECT ID="page1" CLASS="masterstyle" MEDIA="print">
<IE:LAYOUTRECT ID="layoutrect1" CONTENTSRC="2.html" CLASS="contentstyle" NEXTRECT="layoutrect2"/>
</IE:DEVICERECT>

下面是其他页面中的 DeviceRect 代码:

<IE:DEVICERECT ID="page2" CLASS="masterstyle" MEDIA="print">
<IE:LAYOUTRECT ID="layoutrect2" CLASS="contentstyle"/>
</IE:DEVICERECT> 

下面我们将 DeviceRect 与 LayoutRect 结合起来使用,页面情况见 3.htm ,其源代码如下:

<HTML XMLNS:IE>
<HEAD>
<IMPORT NAMESPACE="IE" IMPLEMENTATION="#default">
<STYLE TYPE="text/css">
.contentstyle
{
width:5.5in;
height:8in;
margin:1in;
background:white;
border:1 dashed gray;
}
.Mystyle1
{
width:8.5in;
height:11in;
background:#FFFF99;
border-left:1 solid black;
border-top:1 solid black;
border-right:4 solid black;
border-bottom:4 solid black;
margin:10px;
}
</STYLE>
</HEAD>

<BODY>
<IE:DEVICERECT ID="page1" CLASS="Mystyle1" MEDIA="print">
<IE:LAYOUTRECT ID="layoutrect1" CONTENTSRC="2.html" CLASS="contentstyle" NEXTRECT="layoutrect2"/>
</IE:DEVICERECT>

<IE:DEVICERECT ID="page2" CLASS="Mystyle1" MEDIA="print">
<IE:LAYOUTRECT ID="layoutrect2" CLASS="contentstyle"/>
</IE:DEVICERECT>

</BODY>
</HTML> 

四.DeviceRect 与 LayoutRect 标记的动态自动添加:

前面我们说到,每个单独的打印页面都需要各自的 DeviceRect 与 LayoutRect 标记,那么,如果我们有 1000 个页面需要打印,是否就要在每个页面上重复繁琐的 Copy & Paste 操作?

答案是否定的,我们完全可以通过 JavaScript 脚本来完成这一繁琐的工作。

要实现 HTML 声明的动态创建,关键在于 <DIV> 标记的定义,下面是其定义规则。

<DIV ID="devicecontainer">
......
</DIV>

<DIV>与</DIV>之间,采用 insertAdjacentHTML() 方式,并主要利用了其 afterBegin 与 BeforeEnd 两个变量,现在我们将第一个页面"插入"到<DIV></DIV>之间:

devicecontainer.insertAdjacentHTML("afterBegin", newHTML);

具有继承属性的后续页面,调用 beforeEnd 变量:

devicecontainer.insertAdjacentHTML("beforeEnd", newHTML);

要装载 devicecontainer 页面,还需在 <Body>中添加:

<BODY ONLOAD="addFirstPage()">

现在我们在 JavaScript 中添加包含前面详细介绍的 LayoutRect 与 DeviceRect 元素,用到的命令是 addFirstPage() 。需要注意的是,newHTML 标记后使用的是双引号,而 LayoutRect 与 DeviceRect 标记后的变量使用单引号。如下:

function addFirstPage() {
newHTML = "<IE:DEVICERECT ID='devicerect1' MEDIA='print' CLASS='mystyle1'>";
newHTML += "<IE:LAYOUTRECT ID='layoutrect1' CONTENTSRC='2.html'" + "ONLAYOUTCOMPLETE
='onPageComplete()' NEXTRECT='layoutrect2'" + "CLASS='contentstyle'/>";
newHTML += "</IE:DEVICERECT>";

devicecontainer.insertAdjacentHTML("afterBegin", newHTML);
} 

细心的读者一定会发现,LayoutRect 后出现了一个新的属性:LayoutRect:onLayoutComplete ,这个属性主要指定了 LayoutRect 停止响应的后续事件,如系统资源消耗殆尽而停止响应,或者 LayoutRect 指定的变量溢出。

好了,有了上面的原理,下面我们来编写具有自动"插入"功能的 JavaScript 代码:

function onPageComplete() {
if (event.contentOverflow) {
newHTML = "<IE:DEVICERECT ID='devicerect" + (lastPage + 1) + "' MEDIA='print' CLASS='mystyle1'>";
newHTML += "<IE:LAYOUTRECT ID='layoutrect" + (lastPage + 1) + "' ONLAYOUTCOMPLETE
='onPageComplete()' NEXTRECT='layoutrect" + (lastPage + 2) + "' CLASS='contentstyle'/>";
newHTML += "</IE:DEVICERECT>";

devicecontainer.insertAdjacentHTML("beforeEnd", newHTML);
lastPage++;
} 

在上面的代码中,contentOverflow 代表的是由于页面信息过长,本页的 LayoutRect 停止响应,则直接跳到下一个页面,让 LayoutRect 重新定义下一个页面的版面;onPageComplete() 则不管页面是否过长,LayoutRect 是否停止响应,只要到了页面尾部则自动跳到下一页,这也是最常见的情况。

在编写本脚本时,关键处在于保持清醒,不能让任意一个变量出错。其中,ID 不仅针对 DeviceRect 与 LayoutRect ,还为 NextRect 所引用,页面指向不能出错;当前页面的页码应该是 lastPage+1 ,下一个页面的页码应该是 lastPage+2 ;NextRect 标记需要下一个页面的 LayoutRect 属性支持,因此它的值应该为 "layoutRect"+(lastPage+2);打开第一个页面时,这个 LastPage 初始值为 1 。

评论
  • Re:asp.net中进行客户端打印  (2006/6/20 18:42:01) by 王丹 
    前几天提了建议,建议版主把代码的行号去除,果真去除了,真棒,可是我的经验怎么一下子又少了这么许多啊?
  • Re:asp.net中进行客户端打印  (2006/6/20 19:02:28) by 踢西 
    经验的问题是您有可能进行了类似灌水形式的回复,帖子被删除了。
  • Re:asp.net中进行客户端打印  (2006/7/31 18:29:13) by 华 
    我用这个程序,打印出来怎么有那4个按钮的啊,不是说打印的时候按钮不打出来的吗?
  • Re:asp.net中进行客户端打印  (2006/11/18 12:41:34) by LGC 
    东西是好哈
    但是,请注意,对于固定标题和固定页脚是不具备有通用的处理方式,而且必须提供有对应的页面哈
  • Re:asp.net中进行客户端打印  (2007/4/17 14:50:54) by jdsbj 
    好东西,收藏一下!
  • Re:asp.net中进行客户端打印  (2008/1/17 16:28:39) by ZhouFuqiang 
    打印出来那4个按钮??
     
    應該是 <OBJECT  id=WebBrowser  classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2  height=0  width=0>
    帶出來的,沒辦法,IE的模塊

  • Re:asp.net中进行客户端打印  (2008/5/4 13:05:59) by gsoosg 
    是一种解决方法
  • Re:asp.net中进行客户端打印  (2009/5/14 12:24:17) by 何羽凡 
    很不错,支持下是一种解决方法
  • Re:asp.net中进行客户端打印  (2009/12/23 15:14:00) by cooling0609 

    不错!学习中!!

  • Re:asp.net中进行客户端打印  (2010/1/14 15:39:54) by PekingLin 

    不错,支持下是一种解决方法

  • Re:asp.net中进行客户端打印  (2010/2/25 16:09:37) by shawn111 

    页眉和页脚可不可以直接通过代码设置?

标 题:
 
姓 名:
 
主 页:

验证码:

评论:
 

Because of the cache,you may see your comments several minutes later.