【发布时间】:2016-07-25 10:37:31
【问题描述】:
由于可用于此作业的组件极其复杂和/或许可功能有限,我决定从头开始编写此组件。这是我在 PHP 和 VB6 中的全部功能。但我在尝试添加 page 时碰壁了。
关于如何从文件打印或如何打印单个页面(所有图形等都是为 Print 事件中的页面硬编码)的很多很好的示例,但没有关于如何设置一个集合来保存页面数据,然后发送要打印的数据。
在vb6中可以获取pagebounds并调用new page,但是在.NET中好像没有new page方法。
以下是我到目前为止的来源,由于明显缺乏此基本功能,因此非常粗糙。
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 向后兼容方法,它公开了传统的“打印”对象printing compatability vb6。这应该有助于阐明我希望创建/使用的本机功能。
我很难接受上述“没有直接等效”的说法,因为在内存中创建文档时添加新页面似乎是创建打印文档的一个非常基本(也是必不可少的)功能。必须先从文件中加载所有需要打印的内容是没有意义的。
【问题讨论】:
-
我们没有直接创建 PDF,而是通过在 html 中创建文档,然后使用 TuesPechkin 将 html 转换为 PDF 来解决类似的问题。需要一些工作才能使页面边界正常播放,但效果很好
-
@Paddy - 似乎需要wkhtmltopdf.org/downloads.html 来构建控件,那么为什么不直接使用他们提供的命令行工具呢?不知道有什么好处。只是为了澄清;我已经考虑将 html 转换为 pdf 作为上述问题的解决方法,该库确实看起来有点过于复杂,但是他们所做的一些事情(例如,页面类型实际上直接工作)很好。我只是很难咀嚼这在 c#/.net 中还没有完成,因为即使是 VB6 也可以轻松地处理这个微不足道的任务。
-
using PdfFileWriter;行非常具有误导性,因为代码中没有使用该库... -
@VojtěchDohnal - 我试过那个,如果我打印一张表格,我不能在那个页面上添加任何其他数据。
-
那么你的问题是关于那个库还是关于没有那个库的打印?
标签: c# pdf printing system.drawing system.printing