WPF打印票据

WPF打印票据或者是打印普通纸张区别不大,只是说打印票据要把需要打的内容摆放好位置,搞定缩放比例,就可以放入票据直接打印了。
那么关键点就是3个:
1、使用WPF提供的什么类、什么方法来执行打印
2、如何摆放位置
3、如何搞定缩放比例

1、使用WPF提供的什么类、什么方法来执行打印

这个问题很容易解决,搜索下WPF打印或WPF Print,就能找到示例代码。
那么我用的是PrintDialog的PrintVisual方法。PrintDialog从名字中可以看出是个对话框,让用户手动选择打印机。如果不想弹出对话框和选择打印机,则可以读取默认打印机或者在配置文件里配置打印机名称,然后找到它。这就需要用到另外的两个类:PrintQueue和LocalPrintServer。
使用PrintDialog打印:

 
  1. var printDialog = new PrintDialog();

  2. printDialog.PrintQueue = GetPrinter();

  3. printDialog.PrintVisual(visual, visual.Name);

获取打印机任务队列:

 
  1. public static PrintQueue GetPrinter(string printerName = null)

  2. {

  3. try

  4. {

  5. PrintQueue selectedPrinter = null;

  6. if (!string.IsNullOrEmpty(printerName))

  7. {

  8. var printers = new LocalPrintServer().GetPrintQueues();

  9. selectedPrinter = printers.FirstOrDefault(p => p.Name == printerName);

  10. }

  11. else

  12. {

  13. selectedPrinter = LocalPrintServer.GetDefaultPrintQueue();

  14. }

  15. return selectedPrinter;

  16. }

  17. catch

  18. {

  19. return null;

  20. }

  21. }

2、如何摆放位置

注意到我们上面的打印代码是使用的PrintVisual,参数是Visual,那么这个Visual是什么?
我举个WPF Grid类的继承关系:Grid : Panel : FrameworkElement : UIElement : Visual,所以WPF的控件都是继承自UIElement的,也是继承Visual的。
那么我们把Grid看作是一张票据或一张纸,在这张纸上布置好需要打印的内容,不就OK了吗。
你可以创建一个用户控件来鼠标拖拽摆放,传入实体对象绑定值,也可以动态生成一个Grid。

3、如何搞定缩放比例

仅仅摆放好,打印出来未必是我们想要的结果。因为票据的大小不同,特别是银行那种身份证或金额的小格子,打歪了只能说明技术不到家啊。
所以摆放是要有依据的,依据就是扫描票据,然后在扫描的底图上摆放,样位置就不会错位。然后缩放就是DPI(DPI是Dots Per Inch(每英寸所打印的点数)的缩写)的概念。我们扫描的图是像素的,而实际的纸张不能用像素这个单位。这个之间的换算需要依赖DPI。
具体缩放的方法:

 
  1. //注意,我这里DPI写死的是150,实际中你的DPI是多少要看扫描件怎么扫的。

  2. var settings = new PrintSettings { Width = visual.Width, Height = visual.Height, DPI = 150 };

  3. var renderTarget = new RenderTargetBitmap((int)settings.Width, (int)settings.Height, settings.DPI, settings.DPI, PixelFormats.Default);

  4. printDialog.PrintTicket = new PrintTicket();

  5. printDialog.PrintTicket.PageMediaSize = new PageMediaSize(renderTarget.Width, renderTarget.Height);

  6. var capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);

  7. var scale = Math.Max(capabilities.PageImageableArea.ExtentWidth / visual.Width, capabilities.PageImageableArea.ExtentHeight / visual.Height);

  8. visual.LayoutTransform = new ScaleTransform(scale, scale);

  9. var sz = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);

  10. visual.Measure(sz);

  11. visual.Arrange(new Rect(new Point(0, 0), sz));

 

这样我们就达到了缩放的目的,你可以查看MSDN看看具体的类和方法的含义。

其他的需求:

1、竖打

有些单据比较窄,但是宽度还可以,所以希望可以竖着打印,满足这个需求也是一句话的事情。
在visual.Measure(sz);语句之前增加下面两行代码即可。

 
  1. printDialog.PrintTicket.PageOrientation = PageOrientation.Landscape;

  2. printDialog.PrintTicket.PageMediaSize = new PageMediaSize(renderTarget.Height, renderTarget.Width);

2、退纸(针式打印机)

退纸并不是常用的功能,但是放错了纸张想拿出来也要费一番力气,所以想让打印机自动吐出纸来。我也搜索了很多问答和文章,也没试出来一个成功的,可能是方法不正确。最终采用了一个比较鸡贼的办法,就是打印一个空白页,然后自动退纸。每种针式打印机可能不同,所以退纸的空白页的大小要调整好。

 
  1. var printer = GetPrinter();

  2. var visual = new Grid()

  3. {

  4. Width = 1000,

  5. Height = 1500,

  6. VerticalAlignment = VerticalAlignment.Top,

  7. HorizontalAlignment = HorizontalAlignment.Left

  8. };

  9. PrintVisual(printer, visual);

 3、监控打印任务状态

打印的时候肯定想知道任务有没有被打印,提醒用户放入纸张,打印完毕后提醒用户打印完成。我这里写了一个PrintJobChecker类,Start后就会根据timer的间隔时间检查任务队列,和打印时间。
但是.NET提供的方法并不能很好的做到理想的效果,只能获取到任务还有没有,这是很郁闷的事情。一旦打印机开始打印(注意还没完成),job就是null了。这无法判断纸张是不是还在打印中。如果有朋友知道怎么处理还望评论告知。

 
  1. public class PrintJobChecker

  2. {

  3. private DispatcherTimer _timer;

  4. private PrintQueue _printer;

  5.  
  6. private Action<string> _checkingAction;

  7.  
  8. public DateTime? StartPrintTime { get; set; }

  9.  
  10. private int _interval = 100;

  11. public int TimerInterval

  12. {

  13. get { return _interval; }

  14. set

  15. {

  16. _interval = value;

  17. _timer.Interval = TimeSpan.FromMilliseconds(value);

  18. }

  19. }

  20.  
  21. public PrintJobChecker(PrintQueue printer, Action<string> checkingAction)

  22. {

  23. if (printer == null || checkingAction == null)

  24. {

  25. return;

  26. }

  27.  
  28. _printer = printer;

  29. _checkingAction = checkingAction;

  30.  
  31. _timer = new DispatcherTimer

  32. {

  33. Interval = TimeSpan.FromMilliseconds(TimerInterval),

  34. };

  35.  
  36. _timer.Tick += CheckJobStatus;

  37.  
  38. PrintingStatus = "正在打印";

  39. PrintErrorStatus = "打印出错";

  40. PrintOfflineStatus = "请连接打印机";

  41. PrintWaittingStatus = "请放入相应的表单至打印机";

  42. PrintUnknownStatus = "未知错误";

  43. }

  44.  
  45. public void Start()

  46. {

  47. _timer.Start();

  48. }

  49.  
  50. public void Stop()

  51. {

  52. _timer.Stop();

  53. }

  54.  
  55. private void CheckJobStatus(object sender, EventArgs e)

  56. {

  57. if (_printer == null)

  58. {

  59. return;

  60. }

  61.  
  62. var job = _printer.GetLastJob();

  63. if (job == null)

  64. {

  65. if (!StartPrintTime.HasValue)

  66. {

  67. StartPrintTime = DateTime.Now;

  68. }

  69. _checkingAction(PrintingStatus);

  70. }

  71. else

  72. {

  73. var statusText = GetJobStatus(job);

  74. _checkingAction(statusText);

  75. }

  76. }

  77.  
  78. public string PrintingStatus { get; set; }

  79.  
  80. public string PrintErrorStatus { get; set; }

  81.  
  82. public string PrintOfflineStatus { get; set; }

  83.  
  84. public string PrintWaittingStatus { get; set; }

  85.  
  86. public string PrintUnknownStatus { get; set; }

  87.  
  88. private string GetJobStatus(PrintSystemJobInfo job)

  89. {

  90. if (job == null) return null;

  91.  
  92. if (((job.JobStatus & PrintJobStatus.Completed) == PrintJobStatus.Completed)

  93. ||

  94. ((job.JobStatus & PrintJobStatus.Printed) == PrintJobStatus.Printed))

  95. {

  96. StartPrintTime = DateTime.Now;

  97. return PrintingStatus;

  98. }

  99. if ((job.JobStatus & PrintJobStatus.Error) == PrintJobStatus.Error)

  100. {

  101. _timer.Stop();

  102. return PrintErrorStatus;

  103. }

  104. if ((job.JobStatus & PrintJobStatus.Offline) == PrintJobStatus.Offline

  105. ||

  106. job.JobStatus == PrintJobStatus.None)

  107. {

  108. return PrintOfflineStatus;

  109. }

  110. if ((job.JobStatus & PrintJobStatus.Printing) == PrintJobStatus.Printing)

  111. {

  112. if (job.TimeSinceStartedPrinting > 0)

  113. {

  114. return PrintingStatus;

  115. }

  116. else

  117. {

  118. return PrintWaittingStatus;

  119. }

  120. }

  121. return PrintUnknownStatus;

  122. }

  123. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值