使用WPF在C#中静默打印HTML文件
编辑:完全重写问题并添加悬赏 根据许多教程和stackoverflow问题,我现在可以:使用WPF在C#中静默打印HTML文件,c#,html,wpf,printing,wpf-controls,C#,Html,Wpf,Printing,Wpf Controls,编辑:完全重写问题并添加悬赏 根据许多教程和stackoverflow问题,我现在可以: 将多个页面一起打印为一个文档 打印实际内容 正确对齐页面上的内容 打印大小正确的文档 解决方案要求HTML文档底部有一些空白,样式标记HTML{overflow:hidden;}-隐藏滚动条并允许滚动用于分页,但我可以接受这一点 剩下的唯一问题是WPF不会渲染webbrowser屏幕外的部分 这意味着,如果我倾斜我的电脑屏幕,我可以正确打印,但如果我不这样做的文件切断了较低的部分 我尝试渲染为位图,但当
- 将多个页面一起打印为一个文档
- 打印实际内容
- 正确对齐页面上的内容
- 打印大小正确的文档
public class WebPaginator : DocumentPaginator
{
private readonly WebBrowser webBrowser;
private readonly int pageScroll;
private Size pageSize;
public WebPaginator(WebBrowser webBrowser, int pageScroll, double pageHeight, double pageWidth)
{
this.webBrowser = webBrowser;
this.pageScroll = pageScroll;
pageSize = new Size(pageWidth, pageHeight);
}
public override DocumentPage GetPage(int pageNumber)
{
HTMLDocument htmlDoc = webBrowser.Document as HTMLDocument;
if (htmlDoc != null) htmlDoc.parentWindow.scrollTo(0, pageScroll * pageNumber);
Rect area = new Rect(pageSize);
return new DocumentPage(webBrowser, pageSize, area, area);
}
public override bool IsPageCountValid
{
get { return true; }
}
/// <summary>
/// Returns one less than actual length.
/// Last page should be whitespace, used for scrolling.
/// </summary>
public override int PageCount
{
get
{
var doc = (IHTMLDocument2)webBrowser.Document;
var height = ((IHTMLElement2)doc.body).scrollHeight;
int tempVal = height*10/pageScroll;
tempVal = tempVal%10 == 0
? Math.Max(height/pageScroll, 1)
: height/pageScroll + 1;
return tempVal > 1 ? tempVal-1 : tempVal;
}
}
public override Size PageSize
{
get
{
return pageSize;
}
set
{
pageSize = value;
}
}
/// <summary>
/// Can be null.
/// </summary>
public override IDocumentPaginatorSource Source
{
get
{
return null;
}
}
}
公共类WebPaginator:DocumentPaginator
{
专用只读网络浏览器;
私有只读int页面滚动;
私人大小页面大小;
公共网页导航器(WebBrowser WebBrowser、int pageScroll、双页高、双页宽)
{
this.webBrowser=webBrowser;
this.pageScroll=页面滚动;
pageSize=新大小(pageWidth、pageHeight);
}
公共覆盖文档页面GetPage(内部页码)
{
HTMLDocument htmlDoc=webBrowser.Document为HTMLDocument;
如果(htmlDoc!=null)htmlDoc.parentWindow.scrollTo(0,pageScroll*pageNumber);
Rect区域=新Rect(页面大小);
返回新文档页面(webBrowser、pageSize、area、area);
}
公共覆盖bool IsPageCountValid
{
获取{return true;}
}
///
///返回比实际长度小一个的值。
///最后一页应该是空白,用于滚动。
///
公共覆盖整页计数
{
得到
{
var doc=(IHTMLDocument2)webBrowser.Document;
变量高度=((IHTMLElement2)文档正文)。滚动高度;
int tempVal=高度*10/页滚动;
tempVal=tempVal%10==0
?数学最大值(高度/页面滚动,1)
:高度/页面滚动+1;
返回tempVal>1?tempVal-1:tempVal;
}
}
公共覆盖大小PageSize
{
得到
{
返回页面大小;
}
设置
{
pageSize=值;
}
}
///
///可以为空。
///
公共覆盖IDocumentPaginatorSource源
{
得到
{
返回null;
}
}
}
您可以使用标准IE的打印功能(通过),如下所示:
public partial class PrintWindow : Window
{
public PrintWindow()
{
InitializeComponent();
webBrowser.Navigate("http://www.google.com");
}
// I have added a button to demonstrate
private void Button_Click(object sender, RoutedEventArgs e)
{
// NOTE: this works only when the document as been loaded
IOleServiceProvider sp = webBrowser.Document as IOleServiceProvider;
if (sp != null)
{
Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");
const int OLECMDID_PRINT = 6;
const int OLECMDEXECOPT_DONTPROMPTUSER = 2;
dynamic wb; // will be of IWebBrowser2 type, but dynamic is cool
sp.QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, out wb);
if (wb != null)
{
// note: this will send to the default printer, if any
wb.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, null, null);
}
}
}
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IOleServiceProvider
{
[PreserveSig]
int QueryService([MarshalAs(UnmanagedType.LPStruct)] Guid guidService, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
}
}
试试这个链接。使用IHTMLDocument2打印也会生成一个空文档并始终提示用户,即使在execCommand调用中将ShowUI设置为false。直接从UI打印是绝对要求吗?我是说从网络浏览器那里?您是否考虑过将相同的URL单独传递给为此目的而设计的更好的工具?也许吧?最终,从PDF打印将产生更一致的结果,一旦它击中纸张…嗯,不,我开始意识到,webbrowser控制方法是完全不可能的。它不是一个真正的WPF控件,而是一个包装的COM控件。这意味着它不会做你让它做的事。我设法让它觉得屏幕比实际的要大,但由于它是一个COM控件,所以它没有渲染,只是黑色。我还尝试了RenderRotateTransform,但控件中的内容保持未旋转。我会考虑你的链接/解决方案,但我有点厌倦尝试随机的东西了。我可能会完全改变我的方法。我的投票,我认为这是一个很好的答案(可以直接从webBrowser_LoadCompleted中调用,根据您的说明),我也会建议在这种情况下使用IE的打印功能,即使我个人倾向于使用工具(如SharpDevelopmentPrePrinting)和从PDF打印(如上面评论中所述)这可以工作,但它会以双面/双面打印吗?(我现在没有访问打印机的权限,只有XPS文件打印机)它将使用默认打印机和默认设置进行打印,不管它们是什么。是的,开箱即用。复制粘贴此文件并检查打印机默认值-无问题:)如果无法更改默认打印机,并且所需打印机不是默认打印机,是否有这样的答案?
public class WebPaginator : DocumentPaginator
{
private readonly WebBrowser webBrowser;
private readonly int pageScroll;
private Size pageSize;
public WebPaginator(WebBrowser webBrowser, int pageScroll, double pageHeight, double pageWidth)
{
this.webBrowser = webBrowser;
this.pageScroll = pageScroll;
pageSize = new Size(pageWidth, pageHeight);
}
public override DocumentPage GetPage(int pageNumber)
{
HTMLDocument htmlDoc = webBrowser.Document as HTMLDocument;
if (htmlDoc != null) htmlDoc.parentWindow.scrollTo(0, pageScroll * pageNumber);
Rect area = new Rect(pageSize);
return new DocumentPage(webBrowser, pageSize, area, area);
}
public override bool IsPageCountValid
{
get { return true; }
}
/// <summary>
/// Returns one less than actual length.
/// Last page should be whitespace, used for scrolling.
/// </summary>
public override int PageCount
{
get
{
var doc = (IHTMLDocument2)webBrowser.Document;
var height = ((IHTMLElement2)doc.body).scrollHeight;
int tempVal = height*10/pageScroll;
tempVal = tempVal%10 == 0
? Math.Max(height/pageScroll, 1)
: height/pageScroll + 1;
return tempVal > 1 ? tempVal-1 : tempVal;
}
}
public override Size PageSize
{
get
{
return pageSize;
}
set
{
pageSize = value;
}
}
/// <summary>
/// Can be null.
/// </summary>
public override IDocumentPaginatorSource Source
{
get
{
return null;
}
}
}
public partial class PrintWindow : Window
{
public PrintWindow()
{
InitializeComponent();
webBrowser.Navigate("http://www.google.com");
}
// I have added a button to demonstrate
private void Button_Click(object sender, RoutedEventArgs e)
{
// NOTE: this works only when the document as been loaded
IOleServiceProvider sp = webBrowser.Document as IOleServiceProvider;
if (sp != null)
{
Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");
const int OLECMDID_PRINT = 6;
const int OLECMDEXECOPT_DONTPROMPTUSER = 2;
dynamic wb; // will be of IWebBrowser2 type, but dynamic is cool
sp.QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, out wb);
if (wb != null)
{
// note: this will send to the default printer, if any
wb.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, null, null);
}
}
}
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IOleServiceProvider
{
[PreserveSig]
int QueryService([MarshalAs(UnmanagedType.LPStruct)] Guid guidService, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
}
}