备忘录——基于rdlc报表实现打印产品标签
目录
- 0. 背景说明
- 1. 条形码生成
- 2. 获取产品的小程序码
- 3. 报表设计器设计标签模版
- 3.1 为WinForm控件工具箱添加ReportViewer控件
- 3.2 为VS2019安装RDLC报表项目模版
- 3.3 创建报表文件
- 3.4 ReportView初始化
- 4. 直接打印ReportView中报表,不要弹出选择打印机窗口
- 5. 参考
0. 背景说明
-
产品快递箱 包装箱需要贴一张箱标,标注产品的如下一些信息
- 产品检验信息
- 产品公司信息
- 产品SKU集小程序商城二维码链接
-
最终测试Demo效果

1. 条形码生成
使用ZXing.NET 生成产品的批次和SKU的条形码,简单的封装一个辅助类用于创建条形码
using ZXing;
using ZXing.Common;
public static class BarCodeHelper
{
///
/// 创建条形码
///
/// 条码
/// 高度
/// 宽度
/// 图片字节数组
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);
}
///
/// 位图转为字节数组
///
/// 位图
///
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. 获取产品的小程序码
-
根据当前产品的SKU,动态的获取当前产品的微信小程序商城中页面的小程序码
-
获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制
POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN- 具体参数及返回值参考:微信小程序接口文档
-
WebRequest发送POST请求到微信小程序接口,接受返回的图片butter
////// 发送http Post请求图片 /// /// 请求地址 /// 请求参数 ///图片的字节数组 public static byte[] PostRequestReturnImage(string url, string messsage) { byte[] byteData = Encoding.UTF8.GetBytes(messsage); HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url); webRequest.Method = "POST"; webRequest.ContentType = "image/jpeg"; webRequest.ContentLength = byteData.Length; webRequest.AddRange(0, 10000000); using (Stream stream = webRequest.GetRequestStream()) { stream.Write(byteData, 0, byteData.Length); } using (Stream stream = webRequest.GetResponse().GetResponseStream()) { using (BinaryReader br = new BinaryReader(stream)) { byte[] butter = br.ReadBytes(10000000); return butter; } } }
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初始化
private void InitReport()
{
myReportViewer.LocalReport.ReportPath = "MyReport.rdlc";//报表文件名称
ReportDataSource rds = new ReportDataSource
{
Name = "ReportModelObject",
Value = GetDataSource()
};
myReportViewer.LocalReport.DataSources.Add(rds);
myReportViewer.RefreshReport();
}
///
/// 测试使用的数据源
///
///
private List GetDataSource()
{
return new List()
{
new ReportModel()
{
//这里就是将图片的字节数组转为字符串,从而实现绑定在报表中
Image1=Convert.ToBase64String(BarCodeHelper.CreateBarCode("123456789012")),
}
};
}
4. 直接打印ReportView中报表,不要弹出选择打印机窗口
ViewReport控件上自带的打印按钮,点击会弹出选择打印机的窗口,不希望如此
在配置文件中设置默认打印机
封装一个单独打印的辅助类,这个解放方法非我原创,是参考博文
public class PrintHelper
{
///
/// 用来记录当前打印到第几页了
///
private int m_currentPageIndex;
///
/// 声明一个Stream对象的列表用来保存报表的输出数据,LocalReport对象的Render方法会将报表按页输出为多个Stream对象。
///
private IList m_streams;
private bool isLandSapces = false;
///
/// 用来提供Stream对象的函数,用于LocalReport对象的Render方法的第三个参数。
///
///
///
///
///
///
///
private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
{
//如果需要将报表输出的数据保存为文件,请使用FileStream对象。
Stream stream = new MemoryStream();
m_streams.Add(stream);
return stream;
}
///
/// 为Report.rdlc创建本地报告加载数据,输出报告到.emf文件,并打印,同时释放资源
///
/// 参数:ReportViewer.LocalReport
public void PrintStream(LocalReport rvDoc)
{
//获取LocalReport中的报表页面方向
isLandSapces = rvDoc.GetDefaultPageSettings().IsLandscape;
Export(rvDoc);
PrintSetting();
Dispose();
}
private void Export(LocalReport report)
{
string deviceInfo =
@"
EMF
";
m_streams = new List();
//将报表的内容按照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();
}
}
///
/// 处理程序PrintPageEvents
///
///
///
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. 参考
-
RDLC报表显示图片
-
使用Visual Studio建立报表--C#