星期四, 3月 17, 2016

[RV] 列印本機報表而不進行預覽

實務上有列印報表要直接輸出至印表機,不需要預覽、也不需要出現列印視窗,找到這篇文章 逐步解說:列印本機報表而不進行預覽 來學習,基本上就是 LocalReport 搭配 PrintDocument 來進行列印

該練習需要參考下面三個 dll
  • System.Drawing
  • System.Windows.Forms
  • Microsoft.ReportViewer.Winforms
[RV] 列印本機報表而不進行預覽-2

該練習中使用的報表(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;
              }
          }
      }
  }
}
列印結果

[RV] 列印本機報表而不進行預覽-1

學到很多的一個議題,>.<

沒有留言:

張貼留言