vs2017使用rdlc实现批量打印
接着上一篇:上一篇写了安装,这篇直接搞定批量打印,A4纸横版竖版页面设计,正式开始。(我的表达不怎么好,我尽量发图片都是程序员一点就通)
一、界面展示
忽略界面设计丑
查看预览界面,因为有数据就不截全屏了,盒号是我自己加的,我们自己的业务逻辑。
三、核心代码,批量打印(参考代码链接,放到文章结尾处)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class BillPrint : IDisposable 2 { 3 /// <summary> 4 /// 当前打印页号 5 /// </summary> 6 static int m_currentPageIndex; 7 8 /// <summary> 9 /// RDCL转换stream一页对应一个stream 10 /// </summary> 11 static List<Stream> m_streams; 12 13 /// <summary> 14 /// 把report输出成stream 15 /// </summary> 16 /// <param name="report">传入需要Export的report</param> 17 private void Export(LocalReport report) 18 { 19 string deviceInfo = 20 "<DeviceInfo>" + 21 " <OutputFormat>EMF</OutputFormat>" + 22 //" <PageWidth>2in</PageWidth>" + 23 //" <PageHeight>20in</PageHeight>" + 24 //" <MarginTop>0in</MarginTop>" + 25 //" <MarginLeft>0in</MarginLeft>" + 26 //" <MarginRight>0in</MarginRight>" + 27 //" <MarginBottom>0in</MarginBottom>" + 28 "</DeviceInfo>"; 29 m_streams = new List<Stream>(); 30 report.Render("Image", deviceInfo, CreateStream, out Warning[] warnings); 31 foreach (Stream stream in m_streams) 32 stream.Position = 0; 33 } 34 35 /// <summary> 36 /// 创建具有指定的名称和格式的流。 37 /// </summary> 38 private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek) 39 { 40 Stream stream = new FileStream(name + "." + fileNameExtension, 41 FileMode.Create); 42 m_streams.Add(stream); 43 return stream; 44 } 45 46 /// <summary> 47 /// 打印输出 48 /// </summary> 49 private void PrintPage(object sender, PrintPageEventArgs ev) 50 { 51 Metafile pageImage = 52 new Metafile(m_streams[m_currentPageIndex]); 53 ev.Graphics.DrawImage(pageImage, ev.PageBounds); 54 m_currentPageIndex++; 55 ev.HasMorePages = (m_currentPageIndex < m_streams.Count); 56 } 57 /// <summary> 58 /// 设置横版打印 59 /// </summary> 60 /// <param name="sender"></param> 61 /// <param name="e"></param> 62 void Document_QueryPageSettings(object sender, QueryPageSettingsEventArgs e) 63 { 64 e.PageSettings.Landscape = false; 65 int index = -1; 66 for (int i = 0; i < e.PageSettings.PrinterSettings.PaperSizes.Count; i++) 67 { 68 if (e.PageSettings.PrinterSettings.PaperSizes[i].PaperName == "A4") 69 { 70 index = i; 71 break; 72 } 73 } 74 if (index != -1) 75 { 76 e.PageSettings.PaperSize = e.PageSettings.PrinterSettings.PaperSizes[index]; 77 } 78 } 79 80 81 /// <summary> 82 /// 打印预处理 83 /// </summary> 84 private void Print(string printerName = null) 85 { 86 PrintDocument printDoc = new PrintDocument(); 87 if (string.IsNullOrEmpty(printerName)) 88 { 89 printerName = printDoc.PrinterSettings.PrinterName; 90 } 91 if (m_streams == null || m_streams.Count == 0) 92 return; 93 printDoc.PrinterSettings.PrinterName = printerName; 94 if (!printDoc.PrinterSettings.IsValid) 95 { 96 string msg = String.Format("Can't find printer \"{0}\".", printerName); 97 throw new Exception(msg); 98 } 99 printDoc.PrintPage += new PrintPageEventHandler(PrintPage); 100 101 //设置横版打印 102 printDoc.QueryPageSettings += new QueryPageSettingsEventHandler(Document_QueryPageSettings); 103 104 StandardPrintController spc = new StandardPrintController(); 105 printDoc.PrintController = spc; 106 printDoc.Print(); 107 } 108 109 /// <summary> 110 /// 对外接口,启动打印 111 /// </summary> 112 /// <param name="report"></param> 113 /// <param name="printerName">默认打印机</param> 114 public static void Run(LocalReport report, string printerName = null) 115 { 116 m_currentPageIndex = 0; 117 BillPrint billPrint = new BillPrint(); 118 billPrint.Export(report); 119 billPrint.Print(); 120 billPrint.Dispose(); 121 } 122 123 124 /// <summary> 125 /// 获取打印机状态 126 /// </summary> 127 /// <param name="printerName">打印机名称</param> 128 /// <param name="status">输出打印机状态</param> 129 private static void GetPrinterStatus2(string printerName, ref uint status) 130 { 131 try 132 { 133 string lcPrinterName = printerName; 134 IntPtr liHandle = IntPtr.Zero; 135 if (!Win32.OpenPrinter(lcPrinterName, out liHandle, IntPtr.Zero)) 136 { 137 Console.WriteLine("print is close"); 138 return; 139 } 140 UInt32 level = 2; 141 IntPtr buffer = IntPtr.Zero; 142 Win32.GetPrinter(liHandle, level, buffer, 0, out uint sizeNeeded); 143 buffer = Marshal.AllocHGlobal((int)sizeNeeded); 144 if (!Win32.GetPrinter(liHandle, level, buffer, sizeNeeded, out sizeNeeded)) 145 { 146 Console.WriteLine(Environment.NewLine + "Fail GetPrinter:" + Marshal.GetLastWin32Error()); 147 return; 148 } 149 150 Win32.PRINTER_INFO_2 info = (Win32.PRINTER_INFO_2)Marshal.PtrToStructure(buffer, typeof(Win32.PRINTER_INFO_2)); 151 status = info.Status; 152 Marshal.FreeHGlobal(buffer); 153 Win32.ClosePrinter(liHandle); 154 } 155 catch (Exception ex) 156 { 157 throw ex; 158 } 159 } 160 161 /// <summary> 162 /// 对外接口,调去打印机信息 163 /// </summary> 164 /// <param name="printerName">打印机名称</param> 165 /// <returns>返回打印机当前状态</returns> 166 public static string GetPrinterStatus(string printerName) 167 { 168 uint intValue = 0; 169 PrintDocument pd = new PrintDocument(); 170 printerName = printerName == "" ? pd.PrinterSettings.PrinterName : printerName; 171 GetPrinterStatus2(printerName, ref intValue); 172 string strRet = string.Empty; 173 switch (intValue) 174 { 175 case 0: 176 strRet = "准备就绪(Ready)"; 177 break; 178 case 4194432: 179 strRet = "被打开(Lid Open)"; 180 break; 181 case 144: 182 strRet = "打印纸用完(Out of Paper)"; 183 break; 184 case 4194448: 185 strRet = "被打开并且打印纸用完(Out of Paper && Lid Open)"; 186 break; 187 case 1024: 188 strRet = "打印中(Printing)"; 189 break; 190 case 32768: 191 strRet = "初始化(Initializing)"; 192 break; 193 case 160: 194 strRet = "手工送纸(Manual Feed in Progress)"; 195 break; 196 case 4096: 197 strRet = "脱机(Offline)"; 198 break; 199 default: 200 strRet = "未知状态(unknown state)"; 201 break; 202 } 203 return strRet; 204 } 205 206 207 public void Dispose() 208 { 209 if (m_streams != null) 210 { 211 foreach (Stream stream in m_streams) 212 stream.Close(); 213 m_streams = null; 214 } 215 } 216 } 217 218 public class Win32 219 { 220 [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] 221 public static extern bool OpenPrinter(string printer, out IntPtr handle, IntPtr printerDefaults); 222 [DllImport("winspool.drv")] 223 public static extern bool ClosePrinter(IntPtr handle); 224 [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] 225 public static extern bool GetPrinter(IntPtr handle, UInt32 level, IntPtr buffer, UInt32 size, out UInt32 sizeNeeded); 226 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 227 public struct PRINTER_INFO_2 228 { 229 public string pServerName; 230 public string pPrinterName; 231 public string pShareName; 232 public string pPortName; 233 public string pDriverName; 234 public string pComment; 235 public string pLocation; 236 public IntPtr pDevMode; 237 public string pSepFile; 238 public string pPrintProcessor; 239 public string pDatatype; 240 public string pParameters; 241 public IntPtr pSecurityDescriptor; 242 public UInt32 Attributes; 243 public UInt32 Priority; 244 public UInt32 DefaultPriority; 245 public UInt32 StartTime; 246 public UInt32 UntilTime; 247 public UInt32 Status; 248 public UInt32 cJobs; 249 public UInt32 AveragePPM; 250 } 251 }
代码使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using (ReportViewer rvDoc = new ReportViewer()) 2 { 3 rvDoc.LocalReport.DataSources.Add(new ReportDataSource("DataSet1", 你的数据)); 4 //注意自己的路径,这块我写到配置文件,来区分测试跟线上路径。 5 if (PublicProperty.RdlcPath == "Debug") 6 { 7 rvDoc.LocalReport.ReportPath = @"..\..\ReportForm\GTTKWenShuArchives.rdlc"; 8 } 9 else 10 { 11 rvDoc.LocalReport.ReportPath = Application.StartupPath + "\\ReportForm\\GTTKWenShuArchives.rdlc"; 12 } 13 //开始打印,第二个参数是选择打印机名称 14 BillPrint.Run(rvDoc.LocalReport, (string)printerList.Invoke(new obj_delegate(() => { return printerList.SelectedItem.ToString(); }))); 15 } 16 }
四、设计报表一些注意事项(可以用差之毫厘失之千里来形容)
- A4竖版打印,标头设计宽
,长只能小于等于宽,要是大于就会出现空白页情况。
- A4横版打印,标头设计宽
,长度跟竖版一样,注意这个数字是我一点点试出来的,多一点就会出现表的列显示不全,会跑到第二页里面,大家也可以自己试试。
- 要想每一页都显示标题,只能把标题加入到页眉之中,注意
页眉的底部一定要跟表重合否则到第二页跟上边距会跟第一页不一样,具体什么样自己试一下就知道了,
- 表要是想加实线,注意设计的时候
,这个大家一试便知。
- 要想每一页都显示表的标题部分可以这么设计
-
剩下的内容的字体啊间距啊,就根据自己需求自己调吧,注意设计的时候尽量表要与两边重合,标题要与顶部重合,因为他默认是上下左右间距都是2CM,你要是有距离你打印出来就不好看了,这个自己试试就知道了。
五、结尾
把一些我参考的链接放出来,大家可以自行参考。
https://blog.csdn.net/nuptsv_ice/article/details/41821611
有个批量打印代码链接找不到了,要是找到会补上去的。