其他分享
首页 > 其他分享> > 备忘录——基于rdlc报表实现打印产品标签

备忘录——基于rdlc报表实现打印产品标签

作者:互联网

目录

志铭-2022年1月13日 21:40:39

0. 背景说明



1. 条形码生成

使用ZXing.NET 生成产品的批次和SKU的条形码,简单的封装一个辅助类用于创建条形码

   using ZXing;
   using ZXing.Common;

   public static class BarCodeHelper
   {
       /// <summary>
       /// 创建条形码
       /// </summary>
       /// <param name="barCodeNo">条码</param>
       /// <param name="height">高度</param>
       /// <param name="width">宽度</param>
       /// <returns>图片字节数组</returns>
       public static byte[] CreateBarCode(string barCodeNo, int height = 120, int width = 310)
       {
           EncodingOptions encoding = new EncodingOptions()
           {
               Height = height,
               Width = width,
               Margin = 1,
               PureBarcode = false//在条码下显示条码,true则不显示
           };
           BarcodeWriter wr = new BarcodeWriter()
           {
               Options = encoding,
               Format = BarcodeFormat.CODE_128,

           };
           Bitmap img = wr.Write(barCodeNo);

           //保存在当前项目路径下
           // string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\" + barCodeNo + ".jpg";
           // img.Save(filepath, ImageFormat.Jpeg);

           return BitmapToBytes(img);
       }

       /// <summary>
       /// 位图转为字节数组
       /// </summary>
       /// <param name="bitmap">位图</param>
       /// <returns></returns>

       private static byte[] BitmapToBytes(Bitmap bitmap)
       {
           using (MemoryStream ms = new MemoryStream())
           {
               bitmap.Save(ms, ImageFormat.Gif);
               byte[] byteImage = new byte[ms.Length];
               byteImage = ms.ToArray();
               return byteImage;
           }
       }

   }


2. 获取产品的小程序码



3. 报表设计器设计标签模版

3.1 为WinForm控件工具箱添加ReportViewer控件

3.2 为VS2019安装RDLC报表项目模版

使用的VS2019默认没有报表项目,需要安装扩展:Microsoft Reporting Designer

3.3 创建报表文件

3.4 ReportView初始化

    private void InitReport()
    {
        myReportViewer.LocalReport.ReportPath = "MyReport.rdlc";//报表文件名称
        ReportDataSource rds = new ReportDataSource
        {
            Name = "ReportModelObject",
            Value = GetDataSource()
        };
        myReportViewer.LocalReport.DataSources.Add(rds);
        myReportViewer.RefreshReport();
    }

    /// <summary>
    /// 测试使用的数据源
    /// </summary>
    /// <returns></returns>
    private List<ReportModel> GetDataSource()
    {
        return new List<ReportModel>()
            {
                new ReportModel()
                {
                    //这里就是将图片的字节数组转为字符串,从而实现绑定在报表中
                    Image1=Convert.ToBase64String(BarCodeHelper.CreateBarCode("123456789012")),
                }
            };
    }


4. 直接打印ReportView中报表,不要弹出选择打印机窗口

ViewReport控件上自带的打印按钮,点击会弹出选择打印机的窗口,不希望如此

在配置文件中设置默认打印机

<configuration>
	<appSettings >
		<add key="printer" value ="打印机名称"/>
	</appSettings>	
</configuration>

封装一个单独打印的辅助类,这个解放方法非我原创,是参考博文空白画映:C# WinForm RDLC报表不预览直接连续打印

    public class PrintHelper
    {
        /// <summary>
        /// 用来记录当前打印到第几页了
        /// </summary>
        private int m_currentPageIndex;

        /// <summary>
        /// 声明一个Stream对象的列表用来保存报表的输出数据,LocalReport对象的Render方法会将报表按页输出为多个Stream对象。
        /// </summary>
        private IList<Stream> m_streams;

        private bool isLandSapces = false;

        /// <summary>
        /// 用来提供Stream对象的函数,用于LocalReport对象的Render方法的第三个参数。
        /// </summary>
        /// <param name="name"></param>
        /// <param name="fileNameExtension"></param>
        /// <param name="encoding"></param>
        /// <param name="mimeType"></param>
        /// <param name="willSeek"></param>
        /// <returns></returns>
        private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
        {
            //如果需要将报表输出的数据保存为文件,请使用FileStream对象。
            Stream stream = new MemoryStream();
            m_streams.Add(stream);
            return stream;
        }

        /// <summary>
        /// 为Report.rdlc创建本地报告加载数据,输出报告到.emf文件,并打印,同时释放资源
        /// </summary>
        /// <param name="rv">参数:ReportViewer.LocalReport</param>
        public void PrintStream(LocalReport rvDoc)
        {
            //获取LocalReport中的报表页面方向
            isLandSapces = rvDoc.GetDefaultPageSettings().IsLandscape;
            Export(rvDoc);
            PrintSetting();
            Dispose();
        }

        private void Export(LocalReport report)
        {
            string deviceInfo =
            @"<DeviceInfo>
                 <OutputFormat>EMF</OutputFormat>
             </DeviceInfo>";
            m_streams = new List<Stream>();
            //将报表的内容按照deviceInfo指定的格式输出到CreateStream函数提供的Stream中。
            report.Render("Image", deviceInfo, CreateStream, out Warning[] warnings);
            foreach (Stream stream in m_streams)
            {
                stream.Position = 0;
            }
        }

        private void PrintSetting()
        {
            if (m_streams == null || m_streams.Count == 0)
            {
                throw new Exception("错误:没有检测到打印数据流");
            }
            //声明PrintDocument对象用于数据的打印
            PrintDocument printDoc = new PrintDocument();
            //获取配置文件的清单打印机名称
            System.Configuration.AppSettingsReader appSettings = new System.Configuration.AppSettingsReader();
            printDoc.PrinterSettings.PrinterName = appSettings.GetValue("printer", Type.GetType("System.String")).ToString();
            printDoc.PrintController = new StandardPrintController();//指定打印机不显示页码 
            //判断指定的打印机是否可用
            if (!printDoc.PrinterSettings.IsValid)
            {
                throw new Exception("错误:找不到打印机");
            }
            else
            {
                //设置打印机方向遵从报表方向
                printDoc.DefaultPageSettings.Landscape = isLandSapces;
                //声明PrintDocument对象的PrintPage事件,具体的打印操作需要在这个事件中处理。
                printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
                m_currentPageIndex = 0;
                //设置打印机打印份数
                printDoc.PrinterSettings.Copies = 1;
                //执行打印操作,Print方法将触发PrintPage事件。
                printDoc.Print();
            }
        }

        /// <summary>
        /// 处理程序PrintPageEvents
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ev"></param>
        private void PrintPage(object sender, PrintPageEventArgs ev)
        {
            //Metafile对象用来保存EMF或WMF格式的图形,
            //我们在前面将报表的内容输出为EMF图形格式的数据流。
            Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);

            //调整打印机区域的边距
            System.Drawing.Rectangle adjustedRect = new System.Drawing.Rectangle(
                ev.PageBounds.Left - (int)ev.PageSettings.HardMarginX,
                ev.PageBounds.Top - (int)ev.PageSettings.HardMarginY,
                ev.PageBounds.Width,
                ev.PageBounds.Height);

            //绘制一个白色背景的报告
            //ev.Graphics.FillRectangle(Brushes.White, adjustedRect);

            //获取报告内容
            //这里的Graphics对象实际指向了打印机
            ev.Graphics.DrawImage(pageImage, adjustedRect);
            //ev.Graphics.DrawImage(pageImage, ev.PageBounds);

            // 准备下一个页,已确定操作尚未结束
            m_currentPageIndex++;

            //设置是否需要继续打印
            ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
        }

        public void Dispose()
        {
            if (m_streams != null)
            {
                foreach (Stream stream in m_streams)
                {
                    stream.Close();
                }

                m_streams = null;
            }
        }
    }

自定义打印按钮:btnPrint,添加其点击事件

    private void btnPrint_Click(object sender, EventArgs e)
    {
        PrintHelper printHelper = new PrintHelper();
        printHelper.PrintStream(myReportViewer.LocalReport);//myReportViewer是当前的ReportViewk控件名称
    }


5. 参考

标签:报表,stream,rdlc,private,备忘录,streams,标签,new,ev
来源: https://www.cnblogs.com/shanzhiming/p/15798341.html