使用WPF在C#静音打印的HTML文件 [英] Silent print HTML file in C# using WPF

查看:411
本文介绍了使用WPF在C#静音打印的HTML文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:完全重写的问题,并添加赏金



根据许多教程和StackOverflow的问题,我现在可以:




  • 打印多页合为一个文档。

  • 打印实际内容。

  • 页面上正确对齐的内容。

  • 打印正确尺寸的文档。



该解决方案需要在HTML文档有一些空白在底部和样式标记HTML {溢出:隐藏; } - 隐藏滚动条,并允许用于分页滚动 - 但我可以接受这种



剩下的唯一问题是,WPF不渲染的部分在web浏览器是关闭屏幕。



这意味着,如果我翘起我的电脑屏幕,我可以正确打印,但如果我不把文档切断下部。



我试图渲染为位图,但是当我打印生成的图像作为我的视觉的页面都是空的。



如果你知道如何强制WPF完全呈现或如何正确地渲染为位图,请大家帮帮我。



打印窗口XAML:(打印WPF只能在UI线程,否则没有呈现...)

 <窗​​口x:类=CardLoader2000.PrintWindow
的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/presentation
的xmlns:X =htt​​p://schemas.microsoft.com/winfx/2006/xaml
标题=PrintWindowHEIGHT =1139WIDTH =820>
<电网X:名称=网格>
将;! - 对准和web浏览器的大小反映在打印。如果不是文件$ B $大一些的B将被削减。这里的宽度对应于一个小余量A4纸宽度 - >
< web浏览器X:NAME =web浏览器HEIGHT =1089WIDTH =770VerticalAlignment =评出的保证金=0,10,0,0/>
< /网格和GT;
< /窗GT;



打印窗口隐藏代码:

 公共部分类PrintWindow:窗口
{
公共PrintWindow(字符串路径)
{
的InitializeComponent();

的FileStream FS =新的FileStream(路径,FileMode.Open,FileAccess.Read);

webBrowser.NavigateToStream(FS);

ContentRendered + = OnContentRendered;
}

私人无效OnContentRendered(对象发件人,EventArgs EventArgs的)
{
PrintDialog类PD =新PrintDialog类
{
打印标签=新打印标签
{
双面= Duplexing.TwoSidedLongEd​​ge,
OutputColor = OutputColor.Monochrome,
PageOrientation = PageOrientation.Portrait,
PageMediaSize =新PageMediaSize(794,1122),
InputBin = InputBin.AutoSelect
}
};

//好,最后TODO:页面只呈现的是在电脑屏幕上......
WebPaginator分页程序=新WebPaginator(web浏览器,1089,1122,794);

pd.PrintDocument(分页程序,CustomerLetter);

关闭();
}
}



自定义分页程序:

 公共类WebPaginator:DocumentPaginator 
{
私人只读web浏览器web浏览器;
私人只读INT pageScroll;
私人尺寸pageSize的;

公共WebPaginator(web浏览器的浏览器,INT pageScroll,双pageHeight,双页宽)
{
this.webBrowser = web浏览器;
this.pageScroll = pageScroll;
的pageSize =新的大小(页宽,pageHeight);
}

公众覆盖DocumentPage GETPAGE(INT PAGENUMBER)
{
HTMLDocument的HTMLDOC = webBrowser.Document作为HTMLDocument的;
如果(!HTMLDOC = NULL)htmlDoc.parentWindow.scrollTo(0,pageScroll * PAGENUMBER);
矩形面积=新的矩形(pageSize的);

返回新DocumentPage(web浏览器,pageSize的,面积,区);
}

公众覆盖布尔IsPageCountValid
{
获得{返回true; }
}

///<总结>
///返回比实际长度少一个。
///最后一页应该是空白,用于滚动。
///< /总结>
公共覆盖INT页页次
{
得到
{
VAR DOC =(的IHTMLDocument2)webBrowser.Document;
VAR HEIGHT =((IHTMLElement2)doc.body).scrollHeight;
INT tempVal =身高* 10 / pageScroll;
tempVal = tempVal%10 == 0
? Math.Max​​(身高/ pageScroll,1)
:身高/ pageScroll + 1;
返回tempVal> 1? tempVal-1:tempVal;
}
}

公众覆盖面积每页
{
得到
{
返回pageSize的;
}

{
的pageSize =价值;
}
}

///<总结>
///可以为null。
///< /总结>
公众覆盖IDocumentPaginatorSource来源
{
得到
{
返回NULL;
}
}
}


解决方案

您可以使用标准的IE浏览器的打印功能(通过 ExecWB方法),就像这样:

 公共部分类PrintWindow:窗口
{
公共PrintWindow()
{
的InitializeComponent();
webBrowser.Navigate(http://www.google.com);
}

//我添加了一个按钮,以证明
私人无效Button_Click(对象发件人,RoutedEventArgs E)
{
//注:本仅当文档被载入
IOleServiceProvider SP = webBrowser.Document为IOleServiceProvider;
如果(SP!= NULL)
{
的Guid = IID_IWebBrowserApp新的GUID(0002DF05-0000-0000-C000-000000000046);
的Guid = IID_IWebBrowser2新的GUID(D30C1661-CDAF-11d0-8A3E-00C04FC9E26E);
const int的OLECMDID_PRINT = 6;
const int的OLECMDEXECOPT_DONTPROMPTUSER = 2;

动态WB; //将IWebBrowser2的类型的,而是动态的凉爽
sp.QueryService(IID_IWebBrowserApp,IID_IWebBrowser2,出WB);
如果(WB!= NULL)
{
//注意:这将发送到默认打印机,如果有的话
wb.ExecWB(OLECMDID_PRINT,OLECMDEXECOPT_DONTPROMPTUSER,NULL,NULL) ;
}
}
}

[ComImport,与GUID(6D5140C1-7436-11CE-8034-00AA006009FA),InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
专用接口IOleServiceProvider
{
[PreserveSig]
INT QueryService的([的MarshalAs(UnmanagedType.LPStruct)的Guid guidService,[的MarshalAs(UnmanagedType.LPStruct)的Guid RIID,[的MarshalAs(UnmanagedType .IDispatch)] out对象ppvObject);
}
}


EDIT: Completely rewrote question and added bounty.

Based on many tutorials and stackoverflow questions I can now:

  • Print multiple pages together as one document.
  • Print actual content.
  • Align content correctly on page.
  • Print correct size documents.

The solution requires the HTML document to have some white space in the bottom and the style tag html{ overflow:hidden; } - to hide the scrollbars and to allow scrolling to be used for pagination - but I can accept this.

The ONLY remaining problem is that WPF does not render the parts of the webbrowser that are off screen.

This means that if I tilt my computer screen I can print correctly, but if I do not the document cuts off the lower part.

I tried rendering to a bitmap, but when I print the resulting image as my visual the pages are empty.

If you know how to force WPF to fully render or how to correctly render to bitmap, please help me.

Print window XAML: (printing WPF only works on UI thread, otherwise nothing is rendered...)

<Window x:Class="CardLoader2000.PrintWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PrintWindow" Height="1139" Width="820">
    <Grid x:Name="grid">
        <!--The alignment and size of the webbrowser is reflected in the print. If larger than document
        it will be cut. The width here corresponds to A4 paper width with a little margin-->
        <WebBrowser x:Name="webBrowser" Height="1089" Width="770" VerticalAlignment="Top" Margin="0,10,0,0"/>
    </Grid>
</Window>

Print window code-behind:

public partial class PrintWindow : Window
    {
        public PrintWindow(string path)
        {
            InitializeComponent();

            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);

            webBrowser.NavigateToStream(fs);

            ContentRendered += OnContentRendered;
        }

        private void OnContentRendered(object sender, EventArgs eventArgs)
        {
            PrintDialog pd = new PrintDialog
            {
                PrintTicket = new PrintTicket
                {
                    Duplexing = Duplexing.TwoSidedLongEdge,
                    OutputColor = OutputColor.Monochrome,
                    PageOrientation = PageOrientation.Portrait,
                    PageMediaSize = new PageMediaSize(794, 1122),
                    InputBin = InputBin.AutoSelect
                }
            };

            //Ok, final TODO: Page only renders what is on the PC screen...
            WebPaginator paginator = new WebPaginator(webBrowser, 1089, 1122, 794);

            pd.PrintDocument(paginator, "CustomerLetter");

            Close();
        }
    }

Custom paginator:

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;
            }
        }
    }

解决方案

You could use the standard IE's print feature (through the ExecWB method), like this:

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);
    }
}

这篇关于使用WPF在C#静音打印的HTML文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆