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

0. 背景说明

  • 产品快递箱 包装箱需要贴一张箱标,标注产品的如下一些信息

    • 产品检验信息
    • 产品公司信息
    • 产品SKU集小程序商城二维码链接
  • 最终测试Demo效果


1. 条形码生成

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

  1. using ZXing;
  2. using ZXing.Common;
  3. public static class BarCodeHelper
  4. {
  5. /// <summary>
  6. /// 创建条形码
  7. /// </summary>
  8. /// <param name="barCodeNo">条码</param>
  9. /// <param name="height">高度</param>
  10. /// <param name="width">宽度</param>
  11. /// <returns>图片字节数组</returns>
  12. public static byte[] CreateBarCode(string barCodeNo, int height = 120, int width = 310)
  13. {
  14. EncodingOptions encoding = new EncodingOptions()
  15. {
  16. Height = height,
  17. Width = width,
  18. Margin = 1,
  19. PureBarcode = false//在条码下显示条码,true则不显示
  20. };
  21. BarcodeWriter wr = new BarcodeWriter()
  22. {
  23. Options = encoding,
  24. Format = BarcodeFormat.CODE_128,
  25. };
  26. Bitmap img = wr.Write(barCodeNo);
  27. //保存在当前项目路径下
  28. // string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\" + barCodeNo + ".jpg";
  29. // img.Save(filepath, ImageFormat.Jpeg);
  30. return BitmapToBytes(img);
  31. }
  32. /// <summary>
  33. /// 位图转为字节数组
  34. /// </summary>
  35. /// <param name="bitmap">位图</param>
  36. /// <returns></returns>
  37. private static byte[] BitmapToBytes(Bitmap bitmap)
  38. {
  39. using (MemoryStream ms = new MemoryStream())
  40. {
  41. bitmap.Save(ms, ImageFormat.Gif);
  42. byte[] byteImage = new byte[ms.Length];
  43. byteImage = ms.ToArray();
  44. return byteImage;
  45. }
  46. }
  47. }

2. 获取产品的小程序码

  • 根据当前产品的SKU,动态的获取当前产品的微信小程序商城中页面的小程序码

  • 获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制

    • POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
    • 具体参数及返回值参考:微信小程序接口文档
  • WebRequest发送POST请求到微信小程序接口,接受返回的图片butter

    1. /// <summary>
    2. /// 发送http Post请求图片
    3. /// </summary>
    4. /// <param name="url">请求地址</param>
    5. /// <param name="messsage">请求参数</param>
    6. /// <returns>图片的字节数组</returns>
    7. public static byte[] PostRequestReturnImage(string url, string messsage)
    8. {
    9. byte[] byteData = Encoding.UTF8.GetBytes(messsage);
    10. HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
    11. webRequest.Method = "POST";
    12. webRequest.ContentType = "image/jpeg";
    13. webRequest.ContentLength = byteData.Length;
    14. webRequest.AddRange(0, 10000000);
    15. using (Stream stream = webRequest.GetRequestStream())
    16. {
    17. stream.Write(byteData, 0, byteData.Length);
    18. }
    19. using (Stream stream = webRequest.GetResponse().GetResponseStream())
    20. {
    21. using (BinaryReader br = new BinaryReader(stream))
    22. {
    23. byte[] butter = br.ReadBytes(10000000);
    24. return butter;
    25. }
    26. }
    27. }

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

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

  • NuGet:PM>Install-Package Microsoft.ReportingServices.ReportViewerControl.WinForms -Pre

    • 注意ReportView有许多依赖,执行上述命令执行安装,不要在在NuGet管理界面搜索安装,减少不必要的麻烦
  • 安装后,在winform工具箱 Micsoft SQL Server选项卡下有ReportView 控件

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

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

  • 扩展-->管理扩展-->联机搜索:Microsoft Rdlc Report Designer

  • 之后右键项目-->添加 会显示:报表

3.3 创建报表文件

  • 创建报表文件MyReport.rdlc,注意事项

    • 打开报表文件,会自动显示报表数据窗口,没有在重新打开VS
    • 报表数据窗口-->数据集-->添加数据集
      • 定义数据对象:ReportModel类
      • 设置数据源名称:ReportModelObject
      • 数据源:选择对象ReportModel
  • 布局:我使用列表布局,右键插入列表

  • 数据:绑定数据源ReportModelObject的字段

  • 关于图像:首先右键插入图像,图像属性设置:

    • 工具提示:value=System.Convert.FromBase64String(Fields!Image1.Value)
    • 数据源:数据库
    • 使用字段:ReportModel中的图像字段,比如我这里是Image1字段(string 类型)
    • MIME类型:image/jpeg

3.4 ReportView初始化

  1. private void InitReport()
  2. {
  3. myReportViewer.LocalReport.ReportPath = "MyReport.rdlc";//报表文件名称
  4. ReportDataSource rds = new ReportDataSource
  5. {
  6. Name = "ReportModelObject",
  7. Value = GetDataSource()
  8. };
  9. myReportViewer.LocalReport.DataSources.Add(rds);
  10. myReportViewer.RefreshReport();
  11. }
  12. /// <summary>
  13. /// 测试使用的数据源
  14. /// </summary>
  15. /// <returns></returns>
  16. private List<ReportModel> GetDataSource()
  17. {
  18. return new List<ReportModel>()
  19. {
  20. new ReportModel()
  21. {
  22. //这里就是将图片的字节数组转为字符串,从而实现绑定在报表中
  23. Image1=Convert.ToBase64String(BarCodeHelper.CreateBarCode("123456789012")),
  24. }
  25. };
  26. }

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

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

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

  1. <configuration>
  2. <appSettings >
  3. <add key="printer" value ="打印机名称"/>
  4. </appSettings>
  5. </configuration>

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

  1. public class PrintHelper
  2. {
  3. /// <summary>
  4. /// 用来记录当前打印到第几页了
  5. /// </summary>
  6. private int m_currentPageIndex;
  7. /// <summary>
  8. /// 声明一个Stream对象的列表用来保存报表的输出数据,LocalReport对象的Render方法会将报表按页输出为多个Stream对象。
  9. /// </summary>
  10. private IList<Stream> m_streams;
  11. private bool isLandSapces = false;
  12. /// <summary>
  13. /// 用来提供Stream对象的函数,用于LocalReport对象的Render方法的第三个参数。
  14. /// </summary>
  15. /// <param name="name"></param>
  16. /// <param name="fileNameExtension"></param>
  17. /// <param name="encoding"></param>
  18. /// <param name="mimeType"></param>
  19. /// <param name="willSeek"></param>
  20. /// <returns></returns>
  21. private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
  22. {
  23. //如果需要将报表输出的数据保存为文件,请使用FileStream对象。
  24. Stream stream = new MemoryStream();
  25. m_streams.Add(stream);
  26. return stream;
  27. }
  28. /// <summary>
  29. /// 为Report.rdlc创建本地报告加载数据,输出报告到.emf文件,并打印,同时释放资源
  30. /// </summary>
  31. /// <param name="rv">参数:ReportViewer.LocalReport</param>
  32. public void PrintStream(LocalReport rvDoc)
  33. {
  34. //获取LocalReport中的报表页面方向
  35. isLandSapces = rvDoc.GetDefaultPageSettings().IsLandscape;
  36. Export(rvDoc);
  37. PrintSetting();
  38. Dispose();
  39. }
  40. private void Export(LocalReport report)
  41. {
  42. string deviceInfo =
  43. @"<DeviceInfo>
  44. <OutputFormat>EMF</OutputFormat>
  45. </DeviceInfo>";
  46. m_streams = new List<Stream>();
  47. //将报表的内容按照deviceInfo指定的格式输出到CreateStream函数提供的Stream中。
  48. report.Render("Image", deviceInfo, CreateStream, out Warning[] warnings);
  49. foreach (Stream stream in m_streams)
  50. {
  51. stream.Position = 0;
  52. }
  53. }
  54. private void PrintSetting()
  55. {
  56. if (m_streams == null || m_streams.Count == 0)
  57. {
  58. throw new Exception("错误:没有检测到打印数据流");
  59. }
  60. //声明PrintDocument对象用于数据的打印
  61. PrintDocument printDoc = new PrintDocument();
  62. //获取配置文件的清单打印机名称
  63. System.Configuration.AppSettingsReader appSettings = new System.Configuration.AppSettingsReader();
  64. printDoc.PrinterSettings.PrinterName = appSettings.GetValue("printer", Type.GetType("System.String")).ToString();
  65. printDoc.PrintController = new StandardPrintController();//指定打印机不显示页码
  66. //判断指定的打印机是否可用
  67. if (!printDoc.PrinterSettings.IsValid)
  68. {
  69. throw new Exception("错误:找不到打印机");
  70. }
  71. else
  72. {
  73. //设置打印机方向遵从报表方向
  74. printDoc.DefaultPageSettings.Landscape = isLandSapces;
  75. //声明PrintDocument对象的PrintPage事件,具体的打印操作需要在这个事件中处理。
  76. printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
  77. m_currentPageIndex = 0;
  78. //设置打印机打印份数
  79. printDoc.PrinterSettings.Copies = 1;
  80. //执行打印操作,Print方法将触发PrintPage事件。
  81. printDoc.Print();
  82. }
  83. }
  84. /// <summary>
  85. /// 处理程序PrintPageEvents
  86. /// </summary>
  87. /// <param name="sender"></param>
  88. /// <param name="ev"></param>
  89. private void PrintPage(object sender, PrintPageEventArgs ev)
  90. {
  91. //Metafile对象用来保存EMF或WMF格式的图形,
  92. //我们在前面将报表的内容输出为EMF图形格式的数据流。
  93. Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
  94. //调整打印机区域的边距
  95. System.Drawing.Rectangle adjustedRect = new System.Drawing.Rectangle(
  96. ev.PageBounds.Left - (int)ev.PageSettings.HardMarginX,
  97. ev.PageBounds.Top - (int)ev.PageSettings.HardMarginY,
  98. ev.PageBounds.Width,
  99. ev.PageBounds.Height);
  100. //绘制一个白色背景的报告
  101. //ev.Graphics.FillRectangle(Brushes.White, adjustedRect);
  102. //获取报告内容
  103. //这里的Graphics对象实际指向了打印机
  104. ev.Graphics.DrawImage(pageImage, adjustedRect);
  105. //ev.Graphics.DrawImage(pageImage, ev.PageBounds);
  106. // 准备下一个页,已确定操作尚未结束
  107. m_currentPageIndex++;
  108. //设置是否需要继续打印
  109. ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
  110. }
  111. public void Dispose()
  112. {
  113. if (m_streams != null)
  114. {
  115. foreach (Stream stream in m_streams)
  116. {
  117. stream.Close();
  118. }
  119. m_streams = null;
  120. }
  121. }
  122. }

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

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

5. 参考

备忘录——基于rdlc报表实现打印产品标签的更多相关文章

  1. rdlc报表的导出及预览时表头

    感谢各路大神的博客,总结rdlc报表中目前用到的知识,积累. 一.rdlc报表PDF打印出现空白页 1.先至Report.rdlc報表設計的頁面,選擇功能表上的[報表]->[報表屬性],在[配置 ...

  2. 关闭rdlc报表打印预览后,关闭客户端,抛出异常“发生了应用程序级的异常 将退出”

    问题:关闭rdlc报表打印预览后,关闭客户端,抛出异常“发生了应用程序级的异常 将退出” 办法:在容纳ReportViewer的窗体后台代码中,添加如下代码即可 protected override ...

  3. 基于MVC4+EasyUI的Web开发框架经验总结(15)--在MVC项目中使用RDLC报表

    RDLC是一个不错的报表,有着比较不错的设计模式和展现效果,在我的Winform开发里面,使用RDLC也是一个比较方便操作,如可以参考文章<DevExpress的XtraReport和微软RDL ...

  4. 关于微软RDLC报表打印时文字拉伸问题(Windows server 2003 sp2)

    最近我们开发的打印服务频频出现打印文字拉伸问题,客户意见络绎不绝,最为明显的是使用黑体加粗后 “2.0份” 打印出来后小数点几乎看不见了,用户很容易误认为 “ 20份” .所以问题达到了不得不停下手上 ...

  5. 微软RDLC报表打印

    关于微软RDLC报表打印时文字拉伸问题(Windows server 2003 sp2) 最近我们开发的打印服务频频出现打印文字拉伸问题,客户意见络绎不绝,最为明显的是使用黑体加粗后 “2.0份” 打 ...

  6. 基于vs2015的rdlc报表运行环境部署

    先说明一下,rdlc报表是由visual studio来支持的,不是FM. 本次项目采用的是vs2015开发的,当中使用了ReportViewer报表. 两种方式可以支持开发rdlc报表环境: 1)在 ...

  7. C# 条码标签打印程序,RDLC报表动态显示多条码标签的方法

    初学c#,因最近公司客户要求原出货标签需实现条码化,练手的机会来了,遂动手做这个程序,开始都是一些增删改查操作一直很顺利,但到RDLC报表将条码显示到报表上犯难了,因为初学未接触过报表,上网查资料均一 ...

  8. DevExpress的XtraReport和微软RDLC报表的使用和对比

    我们开发程序的时候,经常会碰到一些报表,如果是Winform的报表,一般可以采用DevExpress控件组的XtraReport,或者微软的RDLC报表,当然还有一些其他的,在此不再赘述.由于本人在W ...

  9. 会员管理系统的设计和开发(2)-- RDLC报表的设计及动态加载

    在上篇<会员管理系统的设计和开发(1)>介绍了关于会员系统的一些总体设计思路和要点,经过一段时间开发,软件终于完成并发布.在这期间,碰到了不少技术难点,并积累了不少开发心得和经验,本篇继续 ...

随机推荐

  1. LR常见报错

    转:https://blog.csdn.net/yoyo_sunny/article/details/43406503

  2. 多个工作簿拆分(Excel代码集团)

    一个文件夹里有N个工作簿,每个工作簿中包括N个工作表,将各个工作表拆分成工作簿,命名为每个工作簿里第一个工作表的A列和B列. 工作簿.工作表数量不定,表内内容不限,拆分后保存于当前文件夹下的" ...

  3. 异步FIFO总结+Verilog实现

    异步FIFO简介 异步FIFO(First In First Out)可以很好解决多比特数据跨时钟域的数据传输与同步问题.异步FIFO的作用就像一个蓄水池,用于调节上下游水量. FIFO FIFO是一 ...

  4. Landsat 现有 Analysis Ready Data (ARD) 数据介绍

    Global Web-Enabled Landsat Data (GWELD)[1] NASA 原先的 Web-Enabled Landsat Data Conterminous U.S. Seaso ...

  5. 背水一战——CSP2021/NOIP2021 游记

    洛谷 version 转载本文章的其他链接: 1(S00021 提供) 2(Ew_Cors 提供) \[\texttt{2021.9.10} \] 终于开坑了. 笑死,初赛根本还没开始复习,反正初赛也 ...

  6. Java的垃圾回收机制:强制回收System.gc() Runtime.getTime().gc()

    垃圾回收 当引用类型的实体,如对象.数组等不再被任何变量引用的时候.这块占用的内存就成为了垃圾.JVM会根据自己的策略决定是回收内存 注意: 垃圾回收只回收内存中的对象,无法回收物理资源(数据库连接, ...

  7. 更换vue项目中标签页icon

    问题:在vue项目中, 需要将标签上的icon换成自己所需的,发现在更换了public/favicon.ico后,没有生效,依旧是原来Vue的icon. 解决办法:在vue.config.js中,修改 ...

  8. 【LeetCode】1150. Check If a Number Is Majority Element in a Sorted Array 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 字典 二分查找 日期 题目地址:https://lee ...

  9. 【LeetCode】729. My Calendar I 解题报告

    [LeetCode]729. My Calendar I 解题报告 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problems/my-calendar- ...

  10. 1269 - Consecutive Sum

    1269 - Consecutive Sum    PDF (English) Statistics Forum Time Limit: 3 second(s) Memory Limit: 64 MB ...