Search code examples
knockout.jsdotnetbrowser

How to wait for knockout page to finish loading before printing in DotNetBrowser?


I am trying to print using the DotNetBrowser using code like this:

    public void PrintUrl(string url)
    {
        using (var browser = BrowserFactory.Create())
        {
            browser.PrintHandler = this;
            _waitEvent = new ManualResetEvent(false);

            browser.FinishLoadingFrameEvent += (sender, e) => 
            {
                if (e.IsMainFrame)
                {
                    browser.Print();
                }
            };

            browser.LoadURL(url);
            _waitEvent.WaitOne();
        }
    }

    public PrintStatus OnPrint(PrintJob printJob)
    {
        printJob.PrintJobEvent += (sender, args) => _waitEvent.Set();
        return PrintStatus.CONTINUE;
    }

The page I am trying to print is rendered with Knockout. The HTML elements are bound to the Javascript Knockout model. The model is initialised when the Javascript is executed and the HTML updated.

I get only a blank page.

What I assume is happening is that the FinishLoadingFrameEvent of the main frame is triggered before the Javascript is executed --or-- the event is triggered after the Javascript has executed but before the bound HTML elements are updated.

I can get printing to work by adding the following code right before the print call:

        browser.FinishLoadingFrameEvent += (sender, e) => 
        {
            if (e.IsMainFrame)
            {
                // executing javascript seems to update the DOM
                browser.ExecuteJavaScriptAndReturnValue("window"); 
                browser.Print();
            }
        };

Calling ExecuteJavaScriptAndReturnValue seems to work but I don't know if that is reliable. Is there a sure fire way to get the DOM to update based on the underlying KO model?

The page itself contains a script block that calls ko.applyBindings() and if I execute that instead of "window" it also seems to work.

Is this reliable though? Feels like a hack.


Solution

  • It seems like the DOM model is being generated after the page is loaded. In this case DotNetBrowser reports that the page is loaded but content is not updated yet by the Knockout library.

    There are few options for this case.

    Option 1:

    Execute 'ko.ApplyBindings()' as you have mentioned. After the method execution the webpage content should be loaded and ready for printing.

    Option 2:

    Notify .NET side about the content is loaded using JS-.NET Bridge. In this case you need to inject .NET object into Javascript. That object should contain method that launches print. After DOM is loaded, Knockout should call this method.