应用场景:大量变化且不规律的数据需要实现连续打印输出
需求:Bartender 10.0专业版以上,注意:商业使用请使用正版软件
安装避坑:电脑如果安装过某些条码打印机附送的免费版的Bartender(不带SDK版本),可能会出现无法成功安装更高版本的情况,即卡在安装界面,解决办法目前只有重装系统,直接安装高版本
Bartender API引用有两种方式,一种是引用其自带的.NET SDK,路径是Bartender安装目录\SDK\Assemblies\Seagull.BarTender.Print.dll
该方法优点是操作友好度高,有完整的示例程序,自带了例如生成标签模板的thumbnail缩略图等封装好的功能,缺点是只支持.NET Framework,无法支持.NET Core
另一种方式是引用Bartender COM文件,方法是工程中添加COM引用,搜索Bartender,勾选引用即可。该方法优点是适用性强,可以支持.NET版本调用,缺点定制度较低,几乎所有方法都需要自己进行设置,本例中推荐使用此方法,因为其适用性更强。
思路:
通过创建数据实体类的列表,序列化成JSON文件,在Bartender模板中映射数据库字段,再将数据库字段连接到具名数据源,各类Bartender对象(例如文本,条码,二维码等)就可以引用具名数据源,建立数据实体类列表到Bartender对象的映射关系,调用Bartender打印功能就会自动将列表中的数据全部打印出来,从而实现批量打印。
重点:Bartender模板引用的Json数据文件必须由数据实体类列表构成,例如创建如下的实体类
/// <summary>
/// 用于示例的实体类
/// </summary>
public class ExampleJsonEntity
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime JoinDate { get; set; }
public SubExample SubExample { get; set; }
}
/// <summary>
/// 用于测试实体类中多层数据结构的次实体类
/// </summary>
public class SubExample
{
public int Number { get; set; }
public string BookName { get; set; }
}
通过System.Text.Json库将其序列化并保存到文件:
using System.Text.Json;
var entity = new ExampleJsonEntity();
entity.Name = "张三";
entity.Age = 15;
entity.JoinDate = DateTime.Now;
entity.SubExample = new SubExample() { BookName = "西游记", Number = 1 };
var entityList = new List<ExampleJsonEntity> { entity };
var jsonString = JsonSerializer.Serialize(entityList);
var path = Path.Join(Directory.GetCurrentDirectory(), "TestEntity.Json");
File.WriteAllText(path, jsonString);
运行代码会在程序文件夹下生成一个TestEntity.Json文件。
运行Bartender Designer,新建一个空白项目模板
数据库类型选择JSON,下一步选择“数据库文件”,接着在文件夹中选择TestEntity.Json文件,下一步到最后一个页面:
在可用节点选择框内把你要用到的数据库字段名称勾上,默认子类型中的字段并未勾选,如果要使用到就需要手动进行勾选 ,点击完成
接下来需要对应数据库字段创建具名数据源:
点击创建具名数据源,给一个名称(方便起见通常可以和数据库字段同名) ,下一步类型选择“数据库字段”,再下一步,在字段名下拉框中选择你要关联的字段,可以输入样本数据(未加载时显示的填充数据),点击完成。依次创建具名数据源,关联全部数据库字段。
接下来可以试验Bartender对象对数据源的引用了,选择创建一个基本文本对象:
创建完成后右键选择属性,数据源下会有一个默认的样本文本,选择这个样本文本,点击名称框右边的小按钮
选择“链接到现有的具名数据源” ,右边列表框中可以选择具名数据源的名称,确定即可实现对数据源的映射。(注意如果上一步没创建需要使用的具名数据源,这里也可以进行创建,但需要手动修改类型为数据库字段,并关联相应字段)
至此已实现Bartender模板对数据实体类的映射,接下来可以测试填充数据并打印,我已经对打印方法进行了封装,参照说明可以直接使用进行打印:
using BarTender;
public static class BartenderPrintUtil
{
private static Application? _btdApp;
private static Format? _btdFormat;
/// <summary>
/// 读取Bartender模板和Json文件并进行打印
/// </summary>
/// <param name="templatePath">Bartender模板.btw文件存放路径</param>
/// <param name="jsonPath">Json实体类序列化文件存放路径</param>
/// <param name="printerName">使用的打印机名称</param>
/// <param name="exactlySameCopies">复制打印的份数</param>
/// <param name="printTimeOutMs">打印超时的时间(毫秒),-1为一直等待</param>
/// <returns>Bartender错误列表</returns>
public static async Task<List<string>> PrintFromJsonAsync(
string templatePath,
string jsonPath,
string printerName,
int exactlySameCopies = 1,
int numberSerializedLabels = 1,
int printTimeOutMs = -1
)
{
return await Task.Run(() =>
{
try
{
OpenBtwFile(templatePath);
try
{
//验证给定的Json路径是否合法
var checkFile = new FileInfo(jsonPath);
//指定Json数据库路径
_btdFormat!.Databases.GetDatabase(1).JSONDatabase.FileName = jsonPath;
_btdFormat.Save();
}
catch
{
//如果给定的Json路径不合法则返回错误信息
throw new FileNotFoundException("InValid Json Path");
}
//将要使用的打印机名称
_btdFormat.PrintSetup.Printer = printerName;
//拷贝份数,即完全一样内容打印的数量
_btdFormat.IdenticalCopiesOfLabel = exactlySameCopies;
//模板中自增序列号的自增数量,默认为1
_btdFormat.NumberSerializedLabels = numberSerializedLabels;
//定义字符串列表准备接受Bartender产生的错误信息
var errorList = new List<string>();
//定义一个Bartender错误信息集合变量
Messages errorMsg;
//进行打印作业,产生的错误信息会归集到errorList中
_btdFormat.Print("PrintFromJson", true, printTimeOutMs, out errorMsg);
if (errorMsg.Count > 0)
{
errorList.AddRange(from Message msg in errorMsg select msg.Message);
}
return errorList;
}
catch (Exception ex)
{
return [ex.Message];
}
});
}
private static void StartApp()
{
if (_btdApp is null)
{
_btdApp = new BarTender.Application();
}
}
private static void CloseApp()
{
if (_btdApp is not null)
{
_btdApp.Quit(BarTender.BtSaveOptions.btDoNotSaveChanges);
_btdApp = null;
}
}
private static bool OpenBtwFile(string templatePath)
{
try
{
StartApp();
var checkFile = new FileInfo(templatePath);
if (_btdFormat is null)
{
_btdFormat = _btdApp!.Formats.Open(templatePath);
return true;
}
if (_btdFormat.FileName == templatePath)
return true;
_btdFormat.Close(BtSaveOptions.btDoNotSaveChanges);
_btdFormat = _btdApp!.Formats.Open(templatePath);
return true;
}
catch
{
return false;
}
}
}
本方法的特点:
这个方法利用Bartender内部实现的机制对实体类列表进行连续打印,具体表现来说就是打印机不需要每次都初始化,而是进行连续输出,对大量数据来说极大提高了打印效率,而如果你在C#内部实现一个打印循环,则每次都需要初始化打印机序列,效率较低。这个方法的关键在于Bartender模板的创建上,只要模板做好了数据库映射,接下来的工作会非常简单。