前言
本文主要是关于PDF文件的打印。
这里大体分为三种方案
调用系统支持文件所对应的软件打印。
这种方式可以支持所有可打印的文件,只要安装打开对应文件的软件即可。
当软件需要支持多种文件打印的时候使用。
使用特定的软件打印。
这种方式只能打印特定格式,不会出现同样的文件打开方式被更改而导致打印效果不好的情况。
当打印格式固定,但是要求效果精细的时候使用。
使用DLL打印。
这种方式在打印普通文件没问题,但是打印点阵的时候,因为内部会把点阵转为图片,所以会占用很大的内存,效果也不好。
打印格式固定,文件效果不要求特别精细,但是不需要用户设置打印属性,自动打印的时候使用。
Aspose.PDF、Spire.Pdf、PDFRender4NET都是这种形式,优缺点也都一样。
调用打印命令打印
这种方法会使用文件在系统中默认的打开工具打开进行打印。
这种方式
缺点在于
- 需要下载PDF阅读器,并且将其设置文件的默认打开方式。
- 必须设置默认的打印机(可以代码中设置)。
- 不能同时打印多份。
- 没有设置默认PDF的打开软件的时候会报错。
优点
- 不用安装额外的库。
- 如果打印的精度较高的情况下,调用其他库打印的效果没有这种调用专门软件打印的效果好。
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| namespace z_pdf_printer.Utils { using System.Collections.Generic; using System.Drawing.Printing; using System.Runtime.InteropServices;
class ZPrintUtils { private static readonly PrintDocument FPrintDocument = new PrintDocument();
public static string DefaultPrinter() { return FPrintDocument.PrinterSettings.PrinterName; }
public static List<string> GetLocalPrinters() { List<string> fPrinters = new List<string>(); fPrinters.Add(DefaultPrinter()); foreach (string fPrinterName in PrinterSettings.InstalledPrinters) { if (!fPrinters.Contains(fPrinterName)) { fPrinters.Add(fPrinterName); } } return fPrinters; }
[DllImport("winspool.drv")] public static extern bool SetDefaultPrinter(string name);
public static void Print ( string pdfPath, string printerName ) { SetDefaultPrinter(printerName); System.Diagnostics.Process p = new System.Diagnostics.Process(); p.StartInfo.ErrorDialog = true; p.StartInfo.CreateNoWindow = true; p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; p.StartInfo.UseShellExecute = true; p.StartInfo.FileName = pdfPath; p.StartInfo.Verb = "print"; p.Start(); p.WaitForExit(15000); } } }
|
下载PDF查看软件
系统默认浏览器下载
1 2
| string fileurl="https://xhkjedu.oss-cn-huhehaote.aliyuncs.com/runtime/AcroRdrDC1900820071_zh_CN.exe"; System.Diagnostics.Process.Start("explorer.exe", fileurl);
|
IE下载
1 2
| string fileurl="https://xhkjedu.oss-cn-huhehaote.aliyuncs.com/runtime/readerdc_cn_ha_crd_install.exe"; System.Diagnostics.Process.Start("iexplore.exe", fileurl);
|
这里上传了两个安装包地址如下
在线安装包地址
https://xhkjedu.oss-cn-huhehaote.aliyuncs.com/runtime/readerdc_cn_ha_crd_install.exe
离线安装包地址
https://xhkjedu.oss-cn-huhehaote.aliyuncs.com/runtime/AcroRdrDC1900820071_zh_CN.exe
调用AcroRdrDC打印
上面的方式有个弊端,就是我们设置的默认软件可能被其他软件更换,就导致高精度打印的时候,使用的并不是我们设置的软件。
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
public static bool IsExistAcroRd32() { RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe"); return key != null; }
public static bool Print(string pdfPath, string printerName) { try { RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe"); if (key != null) { string acroRd32Path = key.GetValue("").ToString(); string args = string.Format ( "/t \"{0}\" \"{1}\" /p", pdfPath, printerName ); Process.Start(acroRd32Path, args); return true; } return false; } catch { } return false; }
|
自动下载安装和重启
这种方式能自动下载AcroRd32并安装,但是部分软件会拦截应用自动安装软件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
public static async void InstallAcroRd32Async() { ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; var webClient = new WebClient(); bool isDownload = false; string downloadUrl = "https://xhkjedu.oss-cn-huhehaote.aliyuncs.com/runtime/AcroRdrDC1900820071_zh_CN.exe"; string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); string acroRd32Setup = System.IO.Path.Combine(desktopPath, "AcroRd32Install.exe"); try { webClient.DownloadFileCompleted += (s, e) => { if (e.Error != null) { Console.WriteLine(@"下载失败:" + e.Error.Message); } else if (e.Cancelled) { Console.WriteLine(@"下载取消"); } else { Console.WriteLine(@"下载成功"); isDownload = true; } }; await webClient.DownloadFileTaskAsync(downloadUrl, acroRd32Setup); } catch (Exception) { } if (!isDownload) { return; } await Task.Delay(300); await Task.Run ( () => { Process.Start(acroRd32Setup, " /install")?.WaitForExit(); } ); if (!IsExistAcroRd32()) { return; } Process.Start(Application.ResourceAssembly.Location); Application.Current.Shutdown(); }
|
只下载
这种方式只下载,让用户安装。
1 2 3 4 5
| public static void InstallAcroRd32ByUser() { string downloadUrl = "https://xhkjedu.oss-cn-huhehaote.aliyuncs.com/runtime/AcroRdrDC1900820071_zh_CN.exe"; Process.Start(downloadUrl); }
|
命令行
命令行文档
https://www.robvanderwoude.com/commandlineswitches.php#Acrobat
关闭GUI
1
| taskkill /IM "acrord32.exe" /F
|
打印命令
1
| AcroRd32.exe /t "C:\Path\To\Your\File.pdf" "PrinterName"
|
所有参数
以下是AcroRd32.exe打印的所有参数:
1
| acrord32.exe /t path printername drivername monitorname [options]
|
其中:
path:要打印的文件的路径。
printername:指定要使用的打印机的名称。
drivername:指定要使用的驱动程序的名称。
monitorname:指定所使用的端口监视器的名称。
options:可选参数,用于设置打印作业的其他选项。可以使用以下任意一个选项:
/h:隐藏Acrobat Reader窗口。
/n:禁止Acrobat Reader显示打印对话框。
/s:打印作业无需确认。
/o:打印作业完成后退出Acrobat Reader。
/p:打印作业完成后立即退出Acrobat Reader。
静默打印
后边的第一个是文件路径 第二个是打印机名称
1
| AcroRd32.exe /N /T "D:\Tools\微课打印PDF\空白.pdf" "Microsoft Print to PDF"
|
只打开文件
1
| AcroRd32.exe "D:\Tools\微课打印PDF\空白.pdf"
|
弹出打印窗口(推荐)
这种方式能够打印多份和设置各种其他属性。
1
| AcroRd32.exe /P "D:\Tools\微课打印PDF\空白.pdf"
|
使用Aspose.PDF打印
这种方式在打印高精度的PDF时直接崩溃了。其他PDF没问题。
安装
1
| Install-Package Aspose.PDF -Version 19.1.0
|
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| using System.IO; using System; using Aspose.Pdf; using Aspose.Pdf.Facades;
namespace z_pdf_printer.Utils { public class ZPrintAspose { public static void Print(string pdfPath, string printerName) { byte[] license = Convert.FromBase64String ( "PExpY2Vuc2U+CiAgPERhdGE+CiAgICA8TGljZW5zZWRUbz5TdXpob3UgQXVuYm94IFNvZnR3YXJlIENvLiwgTHRkLjwvTGljZW5zZWRUbz4KICAgIDxFbWFpbFRvPnNhbGVzQGF1bnRlYy5jb208L0VtYWlsVG8+CiAgICA8TGljZW5zZVR5cGU+RGV2ZWxvcGVyIE9FTTwvTGljZW5zZVR5cGU+CiAgICA8TGljZW5zZU5vdGU+TGltaXRlZCB0byAxIGRldmVsb3BlciwgdW5saW1pdGVkIHBoeXNpY2FsIGxvY2F0aW9uczwvTGljZW5zZU5vdGU+CiAgICA8T3JkZXJJRD4xOTA4MjYwODA3NTM8L09yZGVySUQ+CiAgICA8VXNlcklEPjEzNDk3NjAwNjwvVXNlcklEPgogICAgPE9FTT5UaGlzIGlzIGEgcmVkaXN0cmlidXRhYmxlIGxpY2Vuc2U8L09FTT4KICAgIDxQcm9kdWN0cz4KICAgICAgPFByb2R1Y3Q+QXNwb3NlLlRvdGFsIGZvciAuTkVUPC9Qcm9kdWN0PgogICAgPC9Qcm9kdWN0cz4KICAgIDxFZGl0aW9uVHlwZT5FbnRlcnByaXNlPC9FZGl0aW9uVHlwZT4KICAgIDxTZXJpYWxOdW1iZXI+M2U0NGRlMzAtZmNkMi00MTA2LWIzNWQtNDZjNmEzNzE1ZmMyPC9TZXJpYWxOdW1iZXI+CiAgICA8U3Vic2NyaXB0aW9uRXhwaXJ5PjIwMjAwODI3PC9TdWJzY3JpcHRpb25FeHBpcnk+CiAgICA8TGljZW5zZVZlcnNpb24+My4wPC9MaWNlbnNlVmVyc2lvbj4KICAgIDxMaWNlbnNlSW5zdHJ1Y3Rpb25zPmh0dHBzOi8vcHVyY2hhc2UuYXNwb3NlLmNvbS9wb2xpY2llcy91c2UtbGljZW5zZTwvTGljZW5zZUluc3RydWN0aW9ucz4KICA8L0RhdGE+CiAgPFNpZ25hdHVyZT53UGJtNUt3ZTYvRFZXWFNIY1o4d2FiVEFQQXlSR0pEOGI3L00zVkV4YWZpQnd5U2h3YWtrNGI5N2c2eGtnTjhtbUFGY3J0c0cwd1ZDcnp6MytVYk9iQjRYUndTZWxsTFdXeXNDL0haTDNpN01SMC9jZUFxaVZFOU0rWndOQkR4RnlRbE9uYTFQajhQMzhzR1grQ3ZsemJLZFZPZXk1S3A2dDN5c0dqYWtaL1E9PC9TaWduYXR1cmU+CjwvTGljZW5zZT4=" ); new License().SetLicense(new MemoryStream(license)); Document doc = new Document(pdfPath); PdfViewer viewer = new PdfViewer(); viewer.BindPdf(doc); viewer.PrinterJobName = System.IO.Path.GetFileName(doc.FileName); viewer.Resolution = 600; viewer.AutoResize = false; viewer.AutoRotate = false; viewer.PrintPageDialog = true; viewer.RenderingOptions.UseNewImagingEngine = false; System.Drawing.Printing.PrinterSettings ps = new System.Drawing.Printing.PrinterSettings(); System.Drawing.Printing.PageSettings pgs = new System.Drawing.Printing.PageSettings(); ps.PrinterName = printerName; pgs.PaperSize = new System.Drawing.Printing.PaperSize ( "A4", 827, 1169 ); pgs.Margins = new System.Drawing.Printing.Margins ( 0, 0, 0, 0 );
viewer.PrintDocumentWithSettings(pgs, ps); viewer.Close(); } } }
|
使用Spire.Pdf库打印
这种方式
缺点
- 需要引用库。
- 精度较高的文件打印的效果不好。
- 进度较高的文件在打印机队列里数据量太大,达到200-300多M。
优点
- 可以设置打印的数量及其他打印参数。
添加依赖
1
| Install-Package Spire.PDF -Version 9.6.0
|
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public static void Print(string pdfPath, string printerName) { Spire.Pdf.PdfDocument doc = new Spire.Pdf.PdfDocument(); doc.LoadFromFile(pdfPath);
SizeF size = doc.Pages[0].Size;
PaperSize paper = new PaperSize ( "Custom", (int)size.Width / 72 * 100, (int)size.Height / 72 * 100 ) { RawKind = (int)PaperKind.Custom };
doc.PrintSettings.PaperSize = paper; doc.PrintSettings.PrinterName = printerName;
doc.PrintSettings.Copies = 1;
doc.PrintSettings.SelectSinglePageLayout(PdfSinglePageScalingMode.ActualSize, true); doc.Print(); }
|
设置自适应方式
按实际尺寸打印
1
| doc.PrintSettings.SelectSinglePageLayout(PdfSinglePageScalingMode.ActualSize, true);
|
自适应
1 2
| doc.PrintSettings.SelectSinglePageLayout(PdfSinglePageScalingMode.FitSize, true);
|
设置打印页面范围
1
| doc.PrintSettings.SelectPageRange(1, 5);
|
打印不连续的页面
1
| doc.PrintSettings.SelectSomePages(new int[] { 1, 3, 5, 7 });
|
静默打印
1
| doc.PrintSettings.PrintController = new StandardPrintController();
|
双面打印
1 2 3 4 5 6 7 8
| if (doc.PrintSettings.CanDuplex) { doc.PrintSettings.Duplex = Duplex.Default; }
doc.Print();
|
黑白打印
1 2
| pdf.PrintSettings.Color = false;
|
打印多份
1 2
| doc.PrintSettings.Copies = 2;
|
一页为多页/多页为一页
调用PdfPrintSettings类的SelectMultiPageLayout方法将一个PDF文档的多张页面打印到一张纸上。
1 2
| pdf.PrintSettings.SelectMultiPageLayout(1, 2);
|
PdfPrintSettings类的SelectSplitPageLayout方法支持将一个PDF文档的单张页面打印到多张纸上。
该方法是根据A4纸的标准尺寸595pt*842pt对PDF页面进行拆分,超过该大小的页面,打印时其超过部分将会被打印到下一张纸。
1 2
| pdf.PrintSettings.SelectSplitPageLayout();
|
自定义纸张大小
保持原来页面大小打印到PDF
1 2 3 4 5 6 7 8 9 10
| SizeF size = doc.Pages[0].Size;
PaperSize paper = new PaperSize("Custom", (int)size.Width/72*100, (int)size.Height/72*100); paper.RawKind = (int)PaperKind.Custom;
doc.PrintSettings.PaperSize = paper;
|
将原来A4的文档打印成A3的大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| Spire.Pdf.PdfDocument doc = new Spire.Pdf.PdfDocument(); doc.LoadFromFile(FileName);
PaperSize p = null;
PrintDocument printDoc = new PrintDocument();
foreach (PaperSize ps in printDoc.PrinterSettings.PaperSizes) { if (ps.PaperName.Equals("A3")) { p = ps; break; } }
doc.PrintSettings.PaperSize = p;
doc.PrintSettings.SelectSinglePageLayout(PdfSinglePageScalingMode.FitSize, true); doc.Print();
|
使用PDFRender4NET打印
这一种和前面的方式优缺点一致
需要引用O2S.Components.PDFRender4NET.dll
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| using O2S.Components.PDFRender4NET; private void Print3(string PDFPath, string PrinterName, short PrinterNum = 1) { PDFFile file = PDFFile.Open(PDFPath); PrinterSettings settings = new PrinterSettings();
settings.PrinterName = PrinterName; settings.PrintToFile = false;
PaperSize ps = new PaperSize("test", 4, 9);
ps.RawKind = 9;
O2S.Components.PDFRender4NET.Printing.PDFPrintSettings pdfPrintSettings = new O2S.Components.PDFRender4NET.Printing.PDFPrintSettings(settings) { PaperSize = ps, PageScaling = O2S.Components.PDFRender4NET.Printing.PageScaling.FitToPrinterMarginsProportional };
pdfPrintSettings.PrinterSettings.Copies = PrinterNum;
try { file.Print(pdfPrintSettings); } catch (Exception) { } finally { file.Dispose(); } }
|
ComboBox数据源及事件
在C#中,可以通过以下步骤将数据源绑定到ComboBox控件:
定义数据源,可以是列表、数组或其他集合:
创建ComboBox并设置数据源:
1 2
| List<string> dataSource = new List<string> { "Item1", "Item2", "Item3" }; MyCb.ItemsSource = dataSource;
|
这时选中的值和显示的值一样
1 2 3 4
| Console.WriteLine(MyCb.SelectedValue.ToString());
Console.WriteLine(MyCb.Text);
|
也可以设置显示字段和值字段,如果数据源是对象列表:
1 2 3 4 5 6 7
| List<Product> products = new List<Product> { new Product { Name = "Apple", Id = 1 }, new Product { Name = "Orange", Id = 2 } }; MyCb.ItemsSource = products; MyCb.DisplayMemberPath = "Name"; MyCb.SelectedValuePath = "Id";
|
绑定SelectionChanged事件来获取选择的值:
1 2 3 4 5 6 7 8 9
| MyCb.SelectionChanged += ( s, e ) => { string text = MyCb.Text; };
|
也可以在代码中设置选中项:
1 2
| MyCb.SelectedIndex = 0; MyCb.SelectedValue = 2;
|
以上就是在C#中将数据源绑定到ComboBox并获取选择值的主要步骤。除此之外,也可以设置ComboBox的各种属性,如是否可编辑、是否下拉显示选项列表等。
总结一下主要的属性和事件:
- ItemsSource: 设置数据源
- DisplayMemberPath: 显示字段
- SelectedValuePath: 值字段
- SelectedIndex/SelectedValue: 获取或设置选中项