1. はじめに
- C#でMicrosoft RDLC reportをプレビューなしに直接印刷したい
- 印刷処理に時間がかかることを想定して、非同期で印刷したい
2. 開発環境
- C#
- .NET 6
- Visual Studio 2022
- Microsoft RDLC Report Desinger 2022
- ReportViewerCore.WinForms (NuGet)
3. 事前準備
4. LocalReportExtensions
クラスの作成
- 参考文献のソースコードをそのまま活用させてもらった
LocalReportExtensions.cs
using Microsoft.Reporting.WinForms;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.IO;
public static class LocalReportExtensions
{
public static void Print(this LocalReport report, string printerName)
{
var pageSettings = new PageSettings();
pageSettings.PaperSize = report.GetDefaultPageSettings().PaperSize;
pageSettings.Landscape = report.GetDefaultPageSettings().IsLandscape;
pageSettings.Margins = report.GetDefaultPageSettings().Margins;
Print(report, pageSettings, printerName);
}
public static void Print(this LocalReport report, PageSettings pageSettings, string printerName)
{
string deviceInfo =
$@"<DeviceInfo>
<OutputFormat>EMF</OutputFormat>
<PageWidth>{pageSettings.PaperSize.Width * 100}in</PageWidth>
<PageHeight>{pageSettings.PaperSize.Height * 100}in</PageHeight>
<MarginTop>{pageSettings.Margins.Top * 100}in</MarginTop>
<MarginLeft>{pageSettings.Margins.Left * 100}in</MarginLeft>
<MarginRight>{pageSettings.Margins.Right * 100}in</MarginRight>
<MarginBottom>{pageSettings.Margins.Bottom * 100}in</MarginBottom>
</DeviceInfo>";
Warning[] warnings;
var streams = new List<Stream>();
var currentPageIndex = 0;
report.Render("Image", deviceInfo,
(name, fileNameExtension, encoding, mimeType, willSeek) =>
{
var stream = new MemoryStream();
streams.Add(stream);
return stream;
}, out warnings);
foreach (Stream stream in streams)
stream.Position = 0;
if (streams == null || streams.Count == 0)
throw new Exception("Error: no stream to print.");
var printDocument = new PrintDocument();
printDocument.DefaultPageSettings = pageSettings;
if (!printDocument.PrinterSettings.IsValid)
throw new Exception("Error: cannot find the default printer.");
else
{
printDocument.PrintPage += (sender, e) =>
{
Metafile pageImage = new Metafile(streams[currentPageIndex]);
Rectangle adjustedRect = new Rectangle(
e.PageBounds.Left - (int)e.PageSettings.HardMarginX,
e.PageBounds.Top - (int)e.PageSettings.HardMarginY,
e.PageBounds.Width,
e.PageBounds.Height);
e.Graphics.FillRectangle(Brushes.White, adjustedRect);
e.Graphics.DrawImage(pageImage, adjustedRect);
currentPageIndex++;
e.HasMorePages = (currentPageIndex < streams.Count);
e.Graphics.DrawRectangle(Pens.Red, adjustedRect);
};
printDocument.EndPrint += (Sender, e) =>
{
if (streams != null)
{
foreach (Stream stream in streams)
stream.Close();
streams = null;
}
};
printDocument.PrinterSettings.PrinterName = printerName;
printDocument.Print();
}
}
}
5. WinFormクライアントの作成
Form1.cs
using Microsoft.Reporting.WinForms;
using System.Diagnostics;
namespace WinFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void ButtonStart_Click(object sender, EventArgs e)
{
// 非同期で印刷処理を実行する
await ReportPrintAsync();
}
private async Task ReportPrintAsync()
{
Debug.Print("非同期処理開始");
// 確認用にSleepする
await Task.Delay(10000);
// ReportViewerコントロールを追加する
this.Controls.Add(this.reportViewer1);
// ReportViewerコントロールを非表示にする
reportViewer1.Visible = false;
// ReportViewerコントロールにレポートを設定する
reportViewer1.LocalReport.ReportPath = @"C:\XXXX\Report.rdlc";
// レポートをプリンタを指定して直接印刷する
reportViewer1.LocalReport.Print("Microsoft Print to PDF");
Debug.Print("非同期処理終了");
}
}
}
6. 参考文献