Transform xml with xslt, and Print

Hi!

I have used the WebBrowser component for printing a transformed xml using xslt, this works fine if preformed from a UI tread, it does not work if executed from a worker thread, the WebBrowser component are not built for that.

What can I replace the WebBrowser component with? I need something that can print a transformed xml document.

This works from a UI thread
        private void LoadAndPrintXml(string data, string styleSheet)
        {
            // Load the xslt used by IE to render the xml.
            var xTrans = new XslCompiledTransform();
            xTrans.Load(styleSheet);

            // Read the xml string data into an XML reader object.
            StringReader sr = new StringReader(data);
            XmlReader xReader = XmlReader.Create(sr);

            // Apply transform the XML data.
            var ms = new MemoryStream();
            xTrans.Transform(xReader, null, ms);

            // Reset the stream position.
            ms.Position = 0;

            // Load data.
            this.uxWebBrowser.DocumentStream = ms;

            // Print the transformed XML.
            this.uxWebBrowser.Print();
        }

Open in new window

ulf-jzlAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ulf-jzlAuthor Commented:
I found a solution on stackoverflow.

stackoverflow.com/questions/1995527/how-might-i-create-and-use-a-webbrowser-control-on-a-worker-thread/

Here is the slightly modified code to support printing.

 /// <summary>
/// Wrapper for the WebBrowser controller, enables navigate and print via worker threads.
/// </summary>
public class WebPagePump : IDisposable
{
    /// <summary>
    /// Delegate for web page completed.
    /// </summary>
    /// <param name="wb">The WebBrowser.</param>
    public delegate void CompletedCallback(WebBrowser wb);

    /// <summary>
    /// Notifies waiting thread that an event has occurred.
    /// </summary>
    private ManualResetEvent start;

    /// <summary>
    /// The web browser.
    /// </summary>
    private SyncHelper syncProvider;

    /// <summary>
    /// Occurs when [completed].
    /// </summary>
    public event CompletedCallback Completed;

    /// <summary>
    /// Initializes a new instance of the <see cref="WebPagePump"/> class.
    /// </summary>
    public WebPagePump()
    {
        // Start the thread, wait for it to initialize
        this.start = new ManualResetEvent(false);

        var t = new Thread(new ThreadStart(() => 
            { 
                StartPump(); 
            }));
        t.SetApartmentState(ApartmentState.STA);
        t.IsBackground = true;
        t.Start();

        // Blocks the thread, waiting for the set signal.
        this.start.WaitOne();
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        // Shutdown message loop and thread
        this.syncProvider.Terminate();
    }

    /// <summary>
    /// Navigates the URI.
    /// </summary>
    /// <param name="url">The URL.</param>
    public void NavigateUri(Uri url)
    {
        // Start navigating to a URL
        this.syncProvider.NavigateUri(url);
    }

    /// <summary>
    /// Navigates the document.
    /// </summary>
    /// <param name="xml">The XML.</param>
    public void NavigateDocument(string xml, string styleSheet)
    {
        this.syncProvider.NavigateDocument(xml, styleSheet);
    }

    /// <summary>
    /// Prints the web page.
    /// </summary>
    public void Print()
    {
        // Print document.
        this.syncProvider.Print();
    }

    /// <summary>
    /// Handles the Completed event of the SyncProvider.
    /// </summary>
    /// <param name="wb">The wb.</param>
    private void SyncProvider_Completed(WebBrowser wb)
    {
        // Navigation completed, raise event
        var handler = Completed;
        if (handler != null) { handler(wb); }
    }

    /// <summary>
    /// Starts the pump.
    /// </summary>
    private void StartPump()
    {
        // Start the message loop
        this.syncProvider = new SyncHelper(this.start);
        this.syncProvider.Completed += SyncProvider_Completed;
        Application.Run(syncProvider);
    }

    /// <summary>
    /// The "web browser".
    /// </summary>
    private class SyncHelper : Form
    {
        /// <summary>
        /// The browser.
        /// </summary>
        private WebBrowser browser = new WebBrowser();

        /// <summary>
        /// Notifies waiting thread that an event has occurred.
        /// </summary>
        private ManualResetEvent start;

        /// <summary>
        /// Occurs when [completed].
        /// </summary>
        public event CompletedCallback Completed;

        /// <summary>
        /// Initializes a new instance of the <see cref="SyncHelper"/> class.
        /// </summary>
        /// <param name="start">The start.</param>
        public SyncHelper(ManualResetEvent start)
        {
            this.browser.DocumentCompleted += Browser_DocumentCompleted;
            this.start = start;
        }

        /// <summary>
        /// Navigate URI.
        /// </summary>
        /// <param name="url">The URL.</param>
        public void NavigateUri(Uri url)
        {
            // Start navigating
            this.BeginInvoke(new Action(() => this.browser.Navigate(url)));
        }

        /// <summary>
        /// Navigate document.
        /// </summary>
        /// <param name="xml">The XML.</param>
        public void NavigateDocument(string xml, string styleSheet)
        {
            // Load the xslt used by IE to render the xml.
            var xTrans = new XslCompiledTransform();
            xTrans.Load(styleSheet);

            // Read the xml string data into an XML reader object.
            var sr = new StringReader(xml);
            var xReader = XmlReader.Create(sr);
               
            // Apply transform the XML data.
            var ms = new MemoryStream();
            xTrans.Transform(xReader, null, ms);

            // Reset the stream position.
            ms.Position = 0;

            this.BeginInvoke(new Action(() =>
                {
                    // Load data.
                    this.browser.DocumentStream = ms;
                }));
        }

        /// <summary>
        /// Print web page.
        /// </summary>
        public void Print()
        {
            this.BeginInvoke(new Action(() => 
                {
                    // Print document.
                    this.browser.Print();
                }));
        }

        /// <summary>
        /// Handles the DocumentCompleted event of the Browser control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="WebBrowserDocumentCompletedEventArgs"/> instance containing the event data.</param>
        private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            // Generated completed event
            Completed(this.browser);
        }

        /// <summary>
        /// Terminates this instance.
        /// </summary>
        public void Terminate()
        {
            // Shutdown form and message loop
            this.Invoke(new Action(() => this.Close()));
        }

        /// <summary>
        /// </summary>
        /// <param name="value">true to make the control visible; otherwise, false.</param>
        protected override void SetVisibleCore(bool value)
        {
            if (!IsHandleCreated)
            {
                // First-time init, create handle and wait for message pump to run
                this.CreateHandle();
                this.BeginInvoke(new Action(() => this.start.Set()));
            }

            // Keep form hidden
            value = false;
            base.SetVisibleCore(value);
        }
    }
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.