該練習需要參考下面三個 dll
- System.Drawing
- System.Windows.Forms
- Microsoft.ReportViewer.Winforms
該練習中使用的報表(Report.rdlc)請參考這篇 [RV] 使用 WinForms ReportViewer 控制項 內容,資料來源為 AdventureWorks2014 內的員工資料表,只抓出 10 筆來列印,避免實際練習要印出一堆紙
CREATE PROCEDURE [dbo].[GetEmployData]
AS
SELECT TOP 10
E.BusinessEntityID ,
P.LastName ,
P.FirstName ,
E.JobTitle ,
E.Birthdate ,
E.HireDate
FROM [HumanResources].[Employee] AS E
JOIN Person.Person AS P ON E.BusinessEntityID = P.BusinessEntityID
下面 Code,基本上就是從文章中 copy 再加上說明和註解
using System.IO;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Reporting.WinForms;
using System.Drawing;
using System.Drawing.Printing;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace PrinterNoPreview
{
class Program
{
static void Main(string[] args)
{
// 確保會執行 IDispose
using (Demo demo = new Demo())
{
demo.Run();
}
}
}
public class Demo : IDisposable
{
private int m_currentPageIndex;
private IList<stream> m_streams;
private string ConnectionString = @"Data Source=.\SQL2014;Initial Catalog=AdventureWorks2014;Integrated Security=True";
// Create a local report for Report.rdlc, load the data,
// export the report to an .emf file, and print it.
public void Run()
{
LocalReport report = new LocalReport();
report.ReportPath = @"..\..\Report.rdlc";
report.DataSources.Add(new ReportDataSource("dsEmployee", LoadData()));
Export(report);
Print();
}
// Export the given report as an EMF (Enhanced Metafile) file.
private void Export(LocalReport report)
{
string deviceInfo =
@"<DeviceInfo>
<OutputFormat>EMF</OutputFormat>
<PageWidth>8.5in</PageWidth>
<PageHeight>11in</PageHeight>
<MarginTop>0.25in</MarginTop>
<MarginLeft>0.25in</MarginLeft>
<MarginRight>0.25in</MarginRight>
<MarginBottom>0.25in</MarginBottom>
</DeviceInfo>";
m_streams = new List<stream>();
// Report 有幾頁,就會 Render 幾次,EX:Report 內有 3 頁,Render 就會被觸發 3 次,每一頁產生一個 Stream
Warning[] warnings;
report.Render("Image", deviceInfo, CreateStream,out warnings);
foreach (Stream stream in m_streams)
stream.Position = 0;
}
// Routine to provide to the report renderer, in order to
// save an image for each page of the report.
private Stream CreateStream(string name,
string fileNameExtension, Encoding encoding,
string mimeType, bool willSeek)
{
Stream stream = new MemoryStream();
m_streams.Add(stream);
return stream;
}
private void Print()
{
if (m_streams == null || m_streams.Count == 0)
throw new Exception("Error: no stream to print.");
PrintDocument printDoc = new PrintDocument();
if (!printDoc.PrinterSettings.IsValid)
throw new Exception("Error: cannot find the default printer.");
printDoc.PrintPage += printDoc_PrintPage;
m_currentPageIndex = 0;
/* 參考用設定
// 版面設定
PageSetupDialog psd = new PageSetupDialog();
psd.Document = printDoc;
psd.ShowDialog();
// 列印設定
PrintDialog pd = new PrintDialog();
pd.Document = printDoc;
pd.ShowDialog();
// 預覽設定
PrintPreviewDialog ppd = new PrintPreviewDialog();
ppd.Document = printDoc;
ppd.ShowDialog();
*/
// 進行列印,Print() 會呼叫 PrintPage 來進行列印,有幾頁就呼叫幾次
printDoc.Print();
}
// Handler for PrintPageEvents
// PrintPageEventArgs 在 System.Drawing.Printing namespace 內
void printDoc_PrintPage(object sender, PrintPageEventArgs e)
{
// Metafile 在 System.Drawing.Imaging namespace 內
Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
// Adjust rectangular area with printer margins.
// Rectangle 在 System.Drawing 內
Rectangle adjustedRect = new Rectangle(
e.PageBounds.Left - (int)e.PageSettings.HardMarginX,
e.PageBounds.Top - (int)e.PageSettings.HardMarginY,
e.PageBounds.Width,
e.PageBounds.Height);
// Draw a white background for the report
e.Graphics.FillRectangle(Brushes.White, adjustedRect);
// Draw the report content
e.Graphics.DrawImage(pageImage, adjustedRect);
// Prepare for the next page. Make sure we haven't hit the end.
m_currentPageIndex++;
/*
* 該段說明是從參考資料內 copy 出來
* PrintPageEventArgs類的HaeMorePages屬性為True時,通知控件器,必須再次調用OnPrintPage()方法,打印一個頁面。
* PrintLoopI()有一個用於每個要打印的頁面的序例。如果HasMorePages是False,PrintLoop()就會停止。
*/
// 列印多頁的關鍵
e.HasMorePages = (m_currentPageIndex < m_streams.Count);
}
public void Dispose()
{
if (m_streams != null)
{
foreach (Stream stream in m_streams)
stream.Close();
m_streams = null;
}
}
public DataTable LoadData()
{
using (SqlConnection conn = new SqlConnection(this.ConnectionString))
{
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandText = "GetEmployData";
cmd.CommandType = CommandType.StoredProcedure;
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
return dt;
}
catch (Exception)
{
throw;
}
}
}
}
}
列印結果學到很多的一個議題,>.<
- 參考資料
- 逐步解說:列印本機報表而不進行預覽
- LocalReport.Render 方法 (String, String, CreateStreamCallback, Warning[])
- 影像裝置資訊設定
- Metafile 建構函式 (Stream)
- 如何:載入和顯示中繼檔
- PrintPageEventArgs 類別
- 學習.Net(c#)打印--打印結構 - 推薦閱讀這篇,可以了解 PrintDocumnet 列印原理,對於理解文章內的 Code 會很有幫助
- 學習.Net(c#)打印--多頁打印
- 學習.Net(c#)打印--頁面設置
- 學習.Net(c#)打印--調用打印界面
- 學習.Net(c#)打印--打印預覽
- C# Tutorial - How to Print RDLC Report without Report Viewer | FoxLearn
沒有留言:
張貼留言