簡體   English   中英

在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM