Visual Studio自带的报表文件(rdlc,后面提到的报表,都指rdlc报表文件)虽然功能相对不是十分强大,但应付一般的报表要求也是绰绰有余了。关于rdlc报表的使用和设计方法,这里就不做讲解了,本文主要介绍一下如何不使用报表预览控件(ReportViewer),直接将报表的内容在打印机上打印出来。
一般情况下,我们设计好报表后,在程序运行的时候,会将其加载到ReprotViewer控件中进行预览并打印,但有些情况下,我们不想预览报表的内容,而直接将其在打印机上打印出来,又该怎么做呢?要想实现直接打印的功能,我们需要用到.Net提供的2个对象,LocalReport和PrintDocument。LocalReport对象负责加载一个报表文件生成实际的报表并将报表按照知道的格式输出,PrintDocument对象负责将LocalReport的输出内容发送到打印机打印。具体的实现步骤如下:
Step 1: 声明一个LocalReport对象并加载一个报表文件(假定我们已经设计好一个报表文件,名称为PrintMe.rdlc)。
1: LocalReport report = new LocalReport();
2: //设置需要打印的报表的文件名称。
3: report.ReportPath = @"c:\PrintMe.rdlc";
4: //创建要打印的数据源
5: ReportDataSource source = new ReportDataSource(SourceTalbe.TableName, SourceTalbe);
6: report.DataSources.Add(source);
7: //刷新报表中的需要呈现的数据
8: report.Refresh();
Step 2: 将报表的内容输出为指定格式的数据流。
1: string deviceInfo =
2: "" +
3: "EMF " +
4: "8.5in " +
5: "11in " +
6: "0.25in " +
7: "0.25in " +
8: "0.25in " +
9: "0.25in " +
10: "";
11: Warning[] warnings;
12: //将报表的内容按照deviceInfo指定的格式输出到CreateStream函数提供的Stream中。
13: report.Render("Image", deviceInfo, CreateStream, out warnings);
这里使用LocalReport对象的Render方法,将报表的内容输出到指定的数据流(Stream)中。Render方法的第一个参数指定输出的流的格式,这里指定为Image格式(图形格式);第二个参数为一个XML格式的字符串,用来描述输出格式的详细信息;第三个参数是一个回调函数(CreateStreamCallback委托类型),你需要为这个参数声明一个函数,Render方法会将报表的内容输出到这个函数返回的Stream对象的实例中,这个函数看上去类似下面的声明
1: //声明一个Stream对象的列表用来保存报表的输出数据
2: //LocalReport对象的Render方法会将报表按页输出为多个Stream对象。
3: private List<Stream> m_streams;
4: //用来提供Stream对象的函数,用于LocalReport对象的Render方法的第三个参数。
5: private Stream CreateStream(string name, string fileNameExtension,
6: Encoding encoding, string mimeType, bool willSeek)
7: {
8: //如果需要将报表输出的数据保存为文件,请使用FileStream对象。
9: Stream stream = new MemoryStream();
10: m_streams.Add(stream);
11: return stream;
12: }
你可以使用这个函数的参数执行更多的操作,具体内容请参考CreateStreamCallback委托。
第四个参数用来输出报表处理过程中产生的警告信息。
Step 3: 使用PrintDocument对象执行打印操作。
1: //用来记录当前打印到第几页了
2: private int m_currentPageIndex;
3:
4: private void Print()
5: {
6: m_currentPageIndex = 0;
7:
8: if (m_streams == null || m_streams.Count == 0)
9: return;
10: //声明PrintDocument对象用于数据的打印
11: PrintDocument printDoc = new PrintDocument();
12: //指定需要使用的打印机的名称,使用空字符串""来指定默认打印机
13: printDoc.PrinterSettings.PrinterName = "";
14: //判断指定的打印机是否可用
15: if (!printDoc.PrinterSettings.IsValid)
16: {
17: MessageBox.Show("Can't find printer");
18: return;
19: }
20: //声明PrintDocument对象的PrintPage事件,具体的打印操作需要在这个事件中处理。
21: printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
22: //执行打印操作,Print方法将触发PrintPage事件。
23: printDoc.Print();
24: }
具体的PrintPage事件处理程序如下:
1: private void PrintPage(object sender, PrintPageEventArgs ev)
2: {
3: //Metafile对象用来保存EMF或WMF格式的图形,
4: //我们在前面将报表的内容输出为EMF图形格式的数据流。
m_streams[m_currentPageIndex].Position = 0;
5: Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
6: //指定是否横向打印
7: ev.PageSettings.Landscape = false;
8: //这里的Graphics对象实际指向了打印机
9: ev.Graphics.DrawImage(pageImage, 0, 0);
10: m_streams[m_currentPageIndex].Close();
11: m_currentPageIndex++;
12: //设置是否需要继续打印
13: ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
14: }
到此,我们的报表数据就已经打印出来了,在这个过程中,你可以根据需要添加自己的打印逻辑。
获取本地的打印机信息请参考PrinterSettings。