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