ReportViewer下的RDLC(二)


今天,分享下ReportViewer"后台打印"的实现方法!

至于,怎么自定义批量打印,我后面仅提供下我自己的实现方法.不过,可实现的方法很多!

首先,给出微软官方的解决方案:

http://msdn.microsoft.com/zh-cn/library/ms252091%28v=vs.100%29.aspx

而且,如果有这方面需求的朋友,应该都这网上搜索过,网上的帖子,基本都是复制粘贴的微软源码,有的把注释翻译了一下!

是不是不好用啊,格式错乱有木有?

其实,微软给出的解决方案,确实能解决这个后台打印的问题.

而且,我也是用的这个方案.不过,我稍微做了点修改!

咱们先看这部分代码:

 1     private void Export(LocalReport report)
 2     {
 3         string deviceInfo =
 4           @"<DeviceInfo>
 5                 <OutputFormat>EMF</OutputFormat>
 6                 <PageWidth>8.5in</PageWidth>
 7                 <PageHeight>11in</PageHeight>
 8                 <MarginTop>0.25in</MarginTop>
 9                 <MarginLeft>0.25in</MarginLeft>
10                 <MarginRight>0.25in</MarginRight>
11                 <MarginBottom>0.25in</MarginBottom>
12             </DeviceInfo>";
13         Warning[] warnings;
14         m_streams = new List<Stream>();
15         report.Render("Image", deviceInfo, CreateStream,
16            out warnings);
17         foreach (Stream stream in m_streams)
18             stream.Position = 0;
19     }

这个强行做了报表的页宽,页高和上下左右的边距设置.

然后,将报表的内容按照deviceInfo指定的格式输出到CreateStream函数提供的Stream中。

这里就有了个小问题,我们自己实现的报表,上面的这些边距设置,都是早就固定好的.

所以,只要和上面代码不同边距设置的,打印后,格式就全乱套了.

当然,也可以手动编码为和报表一样的设置,但是你要是有几十张报表,累死你,而且,也不便于维护.

直接给大家,看我修改后的代码:

 1 private void Export(LocalReport report)
 2 {
 3     string deviceInfo =
 4     @"<DeviceInfo>
 5         <OutputFormat>EMF</OutputFormat>
 6     </DeviceInfo>";
 7     Warning[] warnings;
 8     m_streams = new List<Stream>();
 9     //将报表的内容按照deviceInfo指定的格式输出到CreateStream函数提供的Stream中。
10     report.Render("Image", deviceInfo, CreateStream, out warnings);
11     foreach (Stream stream in m_streams)
12         stream.Position = 0;
13 }

 

这下通用了!其中,"EMF"可以理解为,文件后缀名.

这样就解决了报表的设置问题.

但是,微软给出的解决方案里,还有个问题,可能有朋友实验的时候,碰到了!

就是,微软给出的这个方案,只能打印纵向单据,打不了横向的(或者说,报表的第一页,打不了横向的).

大家看这里:

 1     private void Print()
 2     {
 3         if (m_streams == null || m_streams.Count == 0)
 4             throw new Exception("Error: no stream to print.");
 5         PrintDocument printDoc = new PrintDocument();
 6         if (!printDoc.PrinterSettings.IsValid)
 7         {
 8             throw new Exception("Error: cannot find the default printer.");
 9         }
10         else
11         {
12             printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
13             m_currentPageIndex = 0;
14             printDoc.Print();
15         }
16     }

这里的"printDoc"没有相关的打印设置(或者说,没有提高可操作的参数).

下面是我修改后的,能自动识别是否需要横向打印的方案.

 1 private void PrintSetting()
 2 {
 3     if (m_streams == null || m_streams.Count == 0)
 4         throw new Exception("错误:没有检测到打印数据流");
 5     //声明PrintDocument对象用于数据的打印
 6     PrintDocument printDoc = new PrintDocument();
 7     //判断指定的打印机是否可用
 8     if (!printDoc.PrinterSettings.IsValid)
 9     {
10         throw new Exception("错误:找不到打印机");
11     }
12     else
13     {
14         //设置打印机方向遵从报表方向
15         printDoc.DefaultPageSettings.Landscape = isLandSapces;
16         //声明PrintDocument对象的PrintPage事件,具体的打印操作需要在这个事件中处理。
17         printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
18         m_currentPageIndex = 0;
19         //执行打印操作,Print方法将触发PrintPage事件。
20         printDoc.Print();
21     }
22 }

 

//设置打印机方向遵从报表方向
printDoc.DefaultPageSettings.Landscape = isLandSapces;

 

其中"isLandSapces"是我这个类中,定义的一个全局bool值.

问题就来了,这个isLandSapces是根据什么取得值?

 1 /// <summary>
 2 /// 为Report.rdlc创建本地报告加载数据,输出报告到.emf文件,并打印,同时释放资源
 3 /// </summary>
 4 /// <param name="rv">参数:ReportViewer.LocalReport</param>
 5 public void PrintStream(LocalReport lr)
 6 {
 7      //获取LocalReport中的报表页面方向
 8      isLandSapces = lr.GetDefaultPageSettings().IsLandscape;
 9      Export(lr);
10     PrintSetting();
11     Dispose();
12 }

 

这是我在类中添加的一个方法!

对,这个isLandSapces,就是取自ReportViewer.LocalReport,这个bool值,你用来加载报表的ReportViewer控件是肯定知道的,把它传递进来,就OK了!

下面给出完整的后台打印代码:

View Code
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Drawing;
  4 using System.Drawing.Imaging;
  5 using System.Drawing.Printing;
  6 using System.IO;
  7 using System.Text;
  8 using Microsoft.Reporting.WinForms;
  9 
 10 namespace HYC.RDLC
 11 {
 12     public class ReportViewer_Stream_Print : IDisposable
 13     {
 14         /// <summary>
 15         /// 用来记录当前打印到第几页了
 16         /// </summary>
 17         private int m_currentPageIndex;
 18 
 19         /// <summary>
 20         /// 声明一个Stream对象的列表用来保存报表的输出数据,LocalReport对象的Render方法会将报表按页输出为多个Stream对象。
 21         /// </summary>
 22         private IList<Stream> m_streams;
 23 
 24         private bool isLandSapces = false;
 25 
 26         /// <summary>
 27         /// 用来提供Stream对象的函数,用于LocalReport对象的Render方法的第三个参数。
 28         /// </summary>
 29         /// <param name="name"></param>
 30         /// <param name="fileNameExtension"></param>
 31         /// <param name="encoding"></param>
 32         /// <param name="mimeType"></param>
 33         /// <param name="willSeek"></param>
 34         /// <returns></returns>
 35         private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
 36         {
 37             //如果需要将报表输出的数据保存为文件,请使用FileStream对象。
 38             Stream stream = new MemoryStream();
 39             m_streams.Add(stream);
 40             return stream;
 41         }
 42 
 43         /// <summary>
 44         /// 为Report.rdlc创建本地报告加载数据,输出报告到.emf文件,并打印,同时释放资源
 45         /// </summary>
 46         /// <param name="rv">参数:ReportViewer.LocalReport</param>
 47         public void PrintStream(LocalReport rvDoc)
 48         {
 49             //获取LocalReport中的报表页面方向
 50             isLandSapces = rvDoc.GetDefaultPageSettings().IsLandscape;
 51             Export(rvDoc);
 52             PrintSetting();
 53             Dispose();
 54         }
 55 
 56         private void Export(LocalReport report)
 57         {
 58             string deviceInfo =
 59             @"<DeviceInfo>
 60                 <OutputFormat>EMF</OutputFormat>
 61             </DeviceInfo>";
 62             Warning[] warnings;
 63             m_streams = new List<Stream>();
 64             //将报表的内容按照deviceInfo指定的格式输出到CreateStream函数提供的Stream中。
 65             report.Render("Image", deviceInfo, CreateStream, out warnings);
 66             foreach (Stream stream in m_streams)
 67                 stream.Position = 0;
 68         }
 69 
 70         private void PrintSetting()
 71         {
 72             if (m_streams == null || m_streams.Count == 0)
 73                 throw new Exception("错误:没有检测到打印数据流");
 74             //声明PrintDocument对象用于数据的打印
 75             PrintDocument printDoc = new PrintDocument();
 76             //判断指定的打印机是否可用
 77             if (!printDoc.PrinterSettings.IsValid)
 78             {
 79                 throw new Exception("错误:找不到打印机");
 80             }
 81             else
 82             {
 83                 //设置打印机方向遵从报表方向
 84                 printDoc.DefaultPageSettings.Landscape = isLandSapces;
 85                 //声明PrintDocument对象的PrintPage事件,具体的打印操作需要在这个事件中处理。
 86                 printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
 87                 m_currentPageIndex = 0;
 88                 //执行打印操作,Print方法将触发PrintPage事件。
 89                 printDoc.Print();
 90             }
 91         }
 92 
 93         /// <summary>
 94         /// 处理程序PrintPageEvents
 95         /// </summary>
 96         /// <param name="sender"></param>
 97         /// <param name="ev"></param>
 98         private void PrintPage(object sender, PrintPageEventArgs ev)
 99         {
100             //Metafile对象用来保存EMF或WMF格式的图形,
101             //我们在前面将报表的内容输出为EMF图形格式的数据流。
102             Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
103 
104             //调整打印机区域的边距
105             Rectangle adjustedRect = new Rectangle(
106                 ev.PageBounds.Left - (int)ev.PageSettings.HardMarginX,
107                 ev.PageBounds.Top - (int)ev.PageSettings.HardMarginY,
108                 ev.PageBounds.Width,
109                 ev.PageBounds.Height);
110 
111             //绘制一个白色背景的报告
112             //ev.Graphics.FillRectangle(Brushes.White, adjustedRect);
113 
114             //获取报告内容
115             //这里的Graphics对象实际指向了打印机
116             ev.Graphics.DrawImage(pageImage, adjustedRect);
117             //ev.Graphics.DrawImage(pageImage, ev.PageBounds);
118 
119             // 准备下一个页,已确定操作尚未结束
120             m_currentPageIndex++;
121 
122             //设置是否需要继续打印
123             ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
124         }
125 
126         public void Dispose()
127         {
128             if (m_streams != null)
129             {
130                 foreach (Stream stream in m_streams)
131                     stream.Close();
132                 m_streams = null;
133             }
134         }
135     }
136 }

调用方法:

1 ReportViewer_Stream_Print rvsp = new ReportViewer_Stream_Print();
2 rvDoc.LocalReport.ReportEmbeddedResource = string.Format("项目名称.Report.{0}.rdlc", reportname);
3 rvsp.PrintStream(rvDoc.LocalReport);

 

后台打印完成!

自定义批量打印:

其实,这个就是用上面的调用方法,

然后,遍历一组报表名称,传递给其中的"reportname"参数!

这个组可以是一维数组,也可以是二维数组,[0]里记录报表名称,[1]里记录打印份数!

当然,也不一定非是数组,方法多多!

 


现在还没想好下篇写啥,或者大家有想交流的,欢迎拍砖,素质留言,恳请指教!


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM