ASP.net的PDF打印(水晶报表)[摘]

如何部署ASP.NET Crystal Report
(1) CRRedist2005_x86.msi 報表套件 (必要安裝)
取得方法在安裝有VS2005的機器上
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\CrystalReports\CRRedist2005_x86.msi

(2) CRREdist2005_x86_cht.msi 中文語言套件(非必要安裝)
取得方法在安裝有VS2005的機器上
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\CrystalReports\zh-cht\CRREdist2005_x86_cht.msi

ASP.net的PDF打印(水晶报表)(表里含有多行数据,而且分页,带图片)(都是自己写的不是网上互相抄来抄去的)
     这个需求其实很普遍,首先打印用PDF的确要比excel要方便的多,至少格式不需要用户再处理了。但是pdf的打印如果用一种画图的方法,就太太麻烦了。最后尝试了用水晶报表转,的确很方便很方便,不应该说太简单了。所以我把做的最复杂的报表给做个小总结。
     首先数据集:在App_Code里(适合net2005)新建一个数据集*.xcd(其实在哪建都可以),在服务器资源管理器里面,拉下来一个表到数据集里,如果你要改变字段或添加字段都可以,这样一个页面你要显示的所有的数据都在这个数据集里面。如果你要多行多列,而且分好页面,就把所有的字段都贴上去吧,水晶报表是有可以多行分组显示的,但为了页面好看,只能这样了。名字可以按数组来,比如name1,name2等等。
     然后水晶报表:做一个rpt的文件,在字段管理器里点数据库字段,在数据库专家里选择ADO.net数据集下面的一个数据集。可以把刚才的数据集拉过来。把每个字段摆在何时的地方。表格我是右键,插入,OLE对象,由文件创建,我在word里面将这个表事先画好了。这样摆在Section3(详细资料里),然后调节里面的字段正好在表格下面。把Section2里面的删除掉,因为不需要上面有个头了。
    页面转成PDF方法:加一个button,在事件里加入如下的代码:
                ReportDocument rptdoc = new ReportDocument();
                rptdoc.Load(MapPath("rpt/YeWuChuLi.rpt"));//水晶报表的相对地址
                string filename = T_ProcessID.Text + ".pdf";//生成PDF的文件名
                string Fname = MapPath("rpt/" + filename);//生成PDF地址
                rptdoc.SetDataSource(dtable);//得到数据源,这个table会在sql语句里把所有的数据都读出来。
                DiskFileDestinationOptions crDiskFileDestinationOptions = new DiskFileDestinationOptions();
                crDiskFileDestinationOptions.DiskFileName = Fname;
                ExportOptions crExportOptions = rptdoc.ExportOptions;
               
                crExportOptions.ExportDestinationOptions = crDiskFileDestinationOptions;
                crExportOptions.ExportDestinationType = ExportDestinationType.DiskFile;
                crExportOptions.ExportFormatType = ExportFormatType.PortableDocFormat;
                rptdoc.Export();//上面代码是将水晶报表转化成PDF
                Response.ClearContent();//下面的代码是弹出这个转换好的pdf文件
                Response.ClearHeaders();
                Response.ContentType = "application/pdf";
                Response.WriteFile(@"rpt/" + filename);
                Response.Redirect(@"rpt/" + filename);
                Response.Flush();
                Response.Close();
 
      注意要加引用在最上面
      using CrystalDecisions.CrystalReports.Engine;
      using CrystalDecisions.Shared;
 
      那么这个数据源看怎么做了,当然,最简单的就是一个查询语句付给这个DataTable里就完成了。
      当表里还有表的时候,就要首先把所有的表都查询出来,放在不同的DataTable里,例如我这个表里,首先有一个总体的介绍设备,一个表的数据,管道是一个表里要显示5个管道信息,阀门一个表里有3个管道的信息等等,整压器里面要显示2个整压器,而如果管道多于5个要第二个表里显示。这样打印的时候,就都看到了。
      因为水晶报表是按表的列来填入数据的,无法把行读出来,所以这里面有一个关于把行转化成列的sql语句。比较有意思。
      举例 一个数据库的表
          Name   sex    birthday
            aa     bb      cc
            dd     ee      ff
            gg     hh      ii
            jj       kk      ll
            mm    nn      oo
  要变成:
       Name1  sex1   birthday1 Name2  sex2 birthday2 Name3 sex3 birthday3
          aa     bb        cc         dd       ee     ff           gg      hh   ii
          jj      kk         ll            mm     nn     oo          Null    Null  Null
SQL 语句      
select (id-1)/3,
Name1 =  max(case when id%3 = 1 then Name else null end),
Name1 =  max (case when id%3 = 2 then Name else null end),
Name1 =  max (case when id%3 = 0 then Name else null end),
Sex1 =  max(case when id%3 = 1 then Type else null end),
Sex2 =  max (case when id%3 = 2 then Type else null end),
Sex3 =  max (case when id%3 = 0 then Type else null end),
Birthday1 =  max(case when id%3 = 1 then Quantity else null end),
Birthday2 =  max (case when id%3 = 2 then Quantity else null end),
Birthday3 =  max (case when id%3 = 0 then Quantity else null end),
from (SELECT row_number() over(order by dbo.表名.Name) as id,表名.* FROM dbo.表名 where ID='" + processid + "') tt group by (id-1)/3";
 
然后解决分页的问题
     这三个表首先要看谁的表的行数多,就按照行数多的那个作为循环,将所有的数据都拼在一个表里面
例如:     
                DataTable dtable = new DataTable;
                //#region 用气设备
                DataTable gasdevicedt = getgasdevicebyprocessid(T_ProcessID.Text);
                //#region 报警设备
                DataTable Alertdevicedt = GetAlertdeviceByProcessID(T_ProcessID.Text);
                //#region 计量表
                DataTable meadevicedt = getmeadevice(T_ProcessID.Text);
                //#region 调压器
                DataTable boosterdt = getboosterbyprocessid(T_ProcessID.Text);
              
                int k = 最多行的表.Rows.Count;
               
                for (int i = 0; i <= k; i++)
                {
                    DataRow row = dtable.NewRow();
                    row["ProjectName"] = T_ProjectName.Text;
                    row["NodeEndTime"] = D_NodeEndTime.Text;
 
                    row["NameA"] = gasdevicedt.Rows[i]["NameA"].ToString();
                    row["NameB"] = gasdevicedt.Rows[i]["NameB"].ToString();
                    row["NameC"] = gasdevicedt.Rows[i]["NameC"].ToString();
                    row["NameD"] = gasdevicedt.Rows[i]["NameD"].ToString();
                    row["NameE"] = gasdevicedt.Rows[i]["NameE"].ToString();

                   
                   row["AlertDeNameA"] = Alertdevicedt.Rows[i]["AlertDeNameA"].ToString();
                    row["AlertDeNameB"] = Alertdevicedt.Rows[i]["AlertDeNameB"].ToString();
                    row["AlertDeNameC"] = Alertdevicedt.Rows[i]["AlertDeNameC"].ToString();
 
                    row["PipNameA"] = meadevicedt.Rows[i]["PipNameA"].ToString();
                    row["PipNameB"] = meadevicedt.Rows[i]["PipNameA"].ToString();
                    dtable.Rows.Add(row);
                }
                dtable.AcceptChanges();
这个Table的数据源就好了
这样就可以显示出来要的PDF了
 
水晶报表显示图片:
       ReportDocument rptdoc = new ReportDocument();
        rptdoc.Load(MapPath("PipelineHandover.rpt"));
        HandOverSet ds = _HandOver1.GetSingleHandOverByPHID(Convert.ToInt32(Request.QueryString["PHID"]));
        if (ds.HandOver.Rows[0]["PipelinePic"].ToString() == "")
            ds.HandOver.Rows[0]["PipelinePic"] = "nopic.gif";
        FileStream fs = new FileStream(MapPath("../images/pics/" + ds.HandOver.Rows[0]["PipelinePic"].ToString()), FileMode.Open); // 创建文件流
        BinaryReader br = new BinaryReader(fs);
        ds.HandOver.Rows[0]["img"] = br.ReadBytes((int)br.BaseStream.Length);
        rptdoc.SetDataSource(ds);
        crv.ReportSource = rptdoc;
 
打印的时候只要那个ds出来了,就都出来了,下面的字段是不弹出来pdf页面,直接就在打印机里出来了。
        System.Drawing.Printing.PrintDocument printDocument = new System.Drawing.Printing.PrintDocument();
        rptdoc.PrintOptions.PrinterName = printDocument.PrinterSettings.PrinterName;
        rptdoc.PrintToPrinter(1, true, 1, 1);
 
以上的方法,在ASP.net里应该足够用了吧,当然有更简单的方法也好,我也用过一个很牛的控件,感觉是“画”一个pdf很灵活,但过于复杂。呵呵。(itextsharp.dll)

posted @ 2010-06-10 16:03  jamin  阅读(1297)  评论(0编辑  收藏  举报