![](/img/trans.png)
[英]Displaying Print Preview of HTML Document without DocumentViewer
[英]“Fast” Displaying in a DocumentViewer
我正在構建一個WPF應用程序,其中需要顯示文檔預覽,例如使用DocumentViewer和DocumentPaginator可以實現的預覽。 但是,事實證明,將報表轉換為XPS並將其加載到DocumentViewer時,速度非常慢(因為我需要顯示的是普通報表)。
這使我開始思考,可能有某種方法可以開始顯示報表的前幾頁,而其余頁面正被“加載”到DocumentViewer中- 基本上是在創建頁面時加載/顯示它們 。
有人知道這樣的事情是否可能嗎? 而且,如果是這樣,您如何建議我開始嘗試使其工作? 我花了幾個小時在網上四處尋找解決方案,以更快地顯示報告,但還沒有提出任何建議。
為了完全公開,在這種情況下,我需要顯示的報告是用HTML創建的。 我知道我需要將其轉換為XPS才能使用DocumentViewer,但是我提出來是因為如果任何人都有快速的顯示HTML的方法,請隨時提出。 我不能使用WebBrowser控件,因為我必須使顯示處於“打印預覽”類型的模式。 一個決定如何“分頁” HTML站點的好的算法可能會導致我找到該問題的解決方案,然后我可以創建一個自定義控件來顯示它。 我將使用DocumentPaginator,但是輸出的文件是XPS,然后回到DocumentViewer問題。
同樣,任何幫助是極大的贊賞。 謝謝!
好吧,我想我有...
我再次找到了一個更好的URL來引用。 這個不是直接為我加載的,因此我從Google緩存中獲取了它: http ://webcache.googleusercontent.com/search?q=cache:LgceMCkJBrsJ: joshclose.net/%3Fp%3D247
定義每篇文章中所述的IViewObject接口:
[ComVisible(true), ComImport()]
[GuidAttribute("0000010d-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IViewObject
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Draw(
[MarshalAs(UnmanagedType.U4)] UInt32 dwDrawAspect,
int lindex,
IntPtr pvAspect,
[In] IntPtr ptd,
IntPtr hdcTargetDev,
IntPtr hdcDraw,
[MarshalAs(UnmanagedType.Struct)] ref Rectangle lprcBounds,
[MarshalAs(UnmanagedType.Struct)] ref Rectangle lprcWBounds,
IntPtr pfnContinue,
[MarshalAs(UnmanagedType.U4)] UInt32 dwContinue);
[PreserveSig]
int GetColorSet([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect,
int lindex, IntPtr pvAspect, [In] IntPtr ptd,
IntPtr hicTargetDev, [Out] IntPtr ppColorSet);
[PreserveSig]
int Freeze([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect,
int lindex, IntPtr pvAspect, [Out] IntPtr pdwFreeze);
[PreserveSig]
int Unfreeze([In, MarshalAs(UnmanagedType.U4)] int dwFreeze);
void SetAdvise([In, MarshalAs(UnmanagedType.U4)] int aspects,
[In, MarshalAs(UnmanagedType.U4)] int advf,
[In, MarshalAs(UnmanagedType.Interface)] IAdviseSink pAdvSink);
void GetAdvise([In, Out, MarshalAs(UnmanagedType.LPArray)] int[] paspects,
[In, Out, MarshalAs(UnmanagedType.LPArray)] int[] advf,
[In, Out, MarshalAs(UnmanagedType.LPArray)] IAdviseSink[] pAdvSink);
}
創建一個HtmlPaginator類,該類可以對瀏覽器的文檔進行截圖(如上所述),然后將其裁剪為頁面/框架:
class HtmlPaginator
{
public event EventHandler<PageImageEventArgs> PageReady;
protected virtual void OnPageReady(PageImageEventArgs e)
{
EventHandler<PageImageEventArgs> handler = this.PageReady;
if (handler != null)
handler(this, e);
}
public class PageImageEventArgs : EventArgs
{
public Image PageImage { get; set; }
public int PageNumber { get; set; }
}
public void GeneratePages(string doc)
{
Bitmap htmlImage = RenderHtmlToBitmap(doc);
int pageWidth = 800;
int pageHeight = 600;
int xLoc = 0;
int yLoc = 0;
int pages = 0;
do
{
int remainingHeightOrPageHeight = Math.Min(htmlImage.Height - yLoc, pageHeight);
int remainingWidthOrPageWidth = Math.Min(htmlImage.Width - xLoc, pageWidth);
Rectangle cropFrame = new Rectangle(xLoc, yLoc, remainingWidthOrPageWidth, remainingHeightOrPageHeight);
Bitmap page = htmlImage.Clone(cropFrame, htmlImage.PixelFormat);
pages++;
PageImageEventArgs args = new PageImageEventArgs { PageImage = page, PageNumber = pages };
OnPageReady(args);
yLoc += pageHeight;
if (yLoc > htmlImage.Height)
{
xLoc += pageWidth;
if (xLoc < htmlImage.Width)
{
yLoc = 0;
}
}
}
while (yLoc < htmlImage.Height && xLoc < htmlImage.Width);
}
private static Bitmap RenderHtmlToBitmap(string doc)
{
Bitmap htmlImage = null;
using (var webBrowser = new WebBrowser())
{
webBrowser.ScrollBarsEnabled = false;
webBrowser.ScriptErrorsSuppressed = true;
webBrowser.DocumentText = doc;
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
webBrowser.Width = webBrowser.Document.Body.ScrollRectangle.Width;
webBrowser.Height = webBrowser.Document.Body.ScrollRectangle.Height;
htmlImage = new Bitmap(webBrowser.Width, webBrowser.Height);
using (Graphics graphics = Graphics.FromImage(htmlImage))
{
var hdc = graphics.GetHdc();
var rect1 = new Rectangle(0, 0, webBrowser.Width, webBrowser.Height);
var rect2 = new Rectangle(0, 0, webBrowser.Width, webBrowser.Height);
var viewObject = (IViewObject)webBrowser.Document.DomDocument;
viewObject.Draw(1, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, hdc, ref rect1, ref rect2, IntPtr.Zero, 0);
graphics.ReleaseHdc(hdc);
}
}
return htmlImage;
}
}
這樣稱呼它:
WebBrowser browser = new WebBrowser();
browser.Navigate("http://www.stackoverflow.com");
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
HtmlPaginator pagr = new HtmlPaginator();
pagr.PageReady += new EventHandler<HtmlPaginator.PageImageEventArgs>(pagr_PageReady);
pagr.GeneratePages(browser.DocumentText);
為了測試它,我實現了一個帶有按鈕,圖片框和列表集合的基本表單。 我從HtmlPaginator准備好頁面后將它們添加到集合中,並使用按鈕將下一張圖像添加到圖片框。
幻數是您所需的寬度和高度。 我使用800x600,但您可能需要不同的尺寸。
缺點是您仍在等待WebBrowser呈現HTML,但我真的不知道替代解決方案如何減少時間-首先必須解釋和繪制HTML。 我猜想寫你自己的網絡瀏覽器。 :)
我確實嘗試過使用IViewObject.Draw來查看是否可以直接渲染頁面框架而不是具有裁剪循環,但這對我來說不起作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.