由于可用于此工作的组件非常复杂和/或许可功能有限,我决定从头开始编写此组件。这是我在 PHP 和 VB6 中的全部功能。但是我在尝试添加page
.
关于如何从文件打印或如何打印单个页面(所有图形等都是为 Print 事件中的页面硬编码)的很多很好的示例,但没有关于如何设置集合来保存页面数据的内容,以及然后发送那些要打印的。
在 vb6 中,您可以获取 pagebounds 并调用新页面,但在 .NET 中,似乎没有新页面方法。
以下是我到目前为止的来源,由于明显缺乏此基本功能,因此非常粗糙。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using PdfFileWriter;
using System.Drawing.Printing;
using System.ComponentModel;
using System.IO;
using System.Drawing.Printing;
class PDF : PrintDocument {
/// <summary>
/// Logo to display on invoice
/// </summary>
public Image Logo { get; set; }
/// <summary>
/// Pages drawn in document
/// </summary>
private List<Graphics> Pages;
private int CurrentPage;
private string directory;
private string file;
/// <summary>
/// Current X position
/// </summary>
public int X { get; set; }
/// <summary>
/// Current X position
/// </summary>
public int Y { get; set; }
/// <summary>
/// Set the folder where backups, downloads, etc will be stored or retrieved from
/// </summary>
[Editor( typeof( System.Windows.Forms.Design.FolderNameEditor ), typeof( System.Drawing.Design.UITypeEditor ) )]
public string Folder { get { return directory; } set { directory=value; } }
public PDF() {
file = (string)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds.ToString();
directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
CurrentPage = 0;
// initialize pages array
Pages = new List<Graphics>();
PrinterSettings = new PrinterSettings() {
PrinterName = "Microsoft Print to PDF",
PrintToFile = true,
PrintFileName = Path.Combine(directory, file + ".pdf"),
};
DefaultPageSettings = new PageSettings(PrinterSettings) {
PaperSize=new PaperSize("Letter", 850, 1100 ),
Landscape = false,
Margins = new Margins(left: 50, right: 50, top: 50, bottom: 50),
};
}
/// <summary>
/// Get specific page
/// </summary>
/// <param name="page">page number. 1 based array</param>
/// <returns></returns>
public Graphics GetPage( int page ) {
int p = page - 1;
if ( p<0||p>Pages.Count ) { return null; }
return Pages[p];
}
public Graphics GetCurrentPage() {
return GetPage(CurrentPage);
}
protected override void OnBeginPrint( PrintEventArgs e ) {
base.OnBeginPrint( e );
}
protected override void OnPrintPage( PrintPageEventArgs e ) {
base.OnPrintPage( e );
}
protected override void OnEndPrint( PrintEventArgs e ) {
base.OnEndPrint( e );
}
/// <summary>
/// Add a new page to the document
/// </summary>
public void NewPage() {
// Add a new page to the page collection and set it as the current page
Graphics g = Graphics.CreateCraphics(); // not sure if this works, but no CreateGraphics is available
Pages.Add( g );
}
/// <summary>
/// Add a new string to the current page
/// </summary>
/// <param name="text">The string to print</param>
/// <param name="align">Optional alignment of the string</param>
public void DrawString(string text, System.Windows.TextAlignment align = System.Windows.TextAlignment.Left ) {
// add string to document
Pages[CurrentPage].DrawString(text, new Font("Arial", 10), new SolidBrush(Color.Black), new PointF(X, Y));
}
/// <summary>
/// Save the contents to PDF
/// </summary>
/// <param name="FileName"></param>
public void Save( string FileName ) {
// Start the print job looping through pages.
foreach ( Graphics page in Pages ) {
// there doesn't seem to be an addpage method
}
/*
* From stackoverflow article on how to 'print' a pdf to filename as the poster complained
* that the PrinterSettings.PrintFileName property is ignored. Havn't tested yet. Also, no
* such function as 'PrintOut' so further research required.
*
PrintOut(
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
FileName,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value
);
*/
}
}
我不是在寻找一个关于如何编写 PDF 文档的非常冗长的大型项目,因为它们都非常严格,它们每个都有至少一个限制,这对于我打算设计的布局来说是一个问题(从 PHP 升级,这是一个从 VB6 升级)。最终结果布局如下所示 >
第一页(发票主页面)
第二页 [摘要]
此报告可能有更多页面,具体取决于付款和服务中的项目数量。如果有很多项目,则继续的子报表的标题将滚动到下一页。例如,如果客户有 200 项服务,这些项目将以类似的方式继续,在每个连续页面的开头使用相同的“付款”标题块。
详细报告
可能有多个详细报告,每个都从新页面的开头开始,并且为这些页面重置和打印页面计数器。因此,发票的第 6 页实际上可能是第二份详细报告的第 3 页。每个报告的开头和结尾如下所示(图片描述了字段数据的布局等)
报告第一页
报告最后一页
我在找什么?
使上述多报表发票布局在 Visual Studio .NET 中工作的可靠方法。我希望将代码从 php 和 vb6 移植出来,并且我对使用分布规模庞大或极其复杂/有限的许可证限制的库不感兴趣。微软提供了一些非常强大的内置工具,我并不反对使用内置的 PDF 打印驱动程序和假脱机数据,尽管这有点小技巧,但它似乎是最简单的制作方法此功能不受 3rd 方控件的限制或膨胀。(包括开源,因为我看到的那些倾向于对 char 进行一些非常奇怪的转换,然后可能是乳胶或其他东西,不完全确定所有转换的东西是关于什么的)。
笔记
了解上述报告样式的组合构成一张发票非常重要,因此每个客户只有一个 pdf 文件。如果有帮助,这里有一个 VB6 向后兼容方法,它揭示了传统的“打印”对象打印兼容性 vb6。这应该有助于阐明我希望创建/使用的本机功能。
我很难接受上述“没有直接等效”的陈述,因为在内存中创建文档时添加新页面似乎是创建打印文档的一个非常基本(也是必不可少的)功能。必须首先从文件中加载需要打印的所有内容是没有意义的。