0
votes

I am trying to print web page in xamarin forms. I am using DependencyService to print webview, which I have implemented in android successfully.

For Windows UWP, I referred to this link:
https://forums.xamarin.com/discussion/91163/problem-with-printing-webview-in-uwp-phone
The approach used in this is printing only the first page of the webpage.

Edit :
I created an interface IPrint providing only the html source to the function.

public interface IPrint
{
    void PrintAsync(string htmlSource);
}

In PrintAsync function (in Windows UWP project),

    async void IPrint.PrintAsync(string htmlSource)
    {
        ViewToPrint.NavigateToString(htmlSource);
        ViewToPrint.LoadCompleted += ViewToPrint_LoadCompleteAsync;
    }

When WebView is completely loaded,

    private async void ViewToPrint_LoadCompleteAsync(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
    {

        if (PrintDoc != null)
        {
            printDoc.AddPages -= PrintDoc_AddPages;
            printDoc.GetPreviewPage -= PrintDoc_GetPreviewPage;
            printDoc.Paginate -= PrintDoc_Paginate;
        }
        this.printDoc = new PrintDocument();
        try
        {
            printDoc.AddPages += PrintDoc_AddPages;
            printDoc.GetPreviewPage += PrintDoc_GetPreviewPage;
            printDoc.Paginate += PrintDoc_Paginate;

            bool showprint = await PrintManager.ShowPrintUIAsync();

        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
        PrintDoc = null;
        GC.Collect();
    }

To add pages in PrintDocument,

    private void PrintDoc_AddPages(object sender, AddPagesEventArgs e)
    {          
        printDoc.AddPage(ViewToPrint);
        printDoc.AddPagesComplete();
    }


To implement multiple pages printing, I referred this link : https://stackoverflow.com/a/17222629/6366591

I changed AddPages function to the following, but it doesn't seem to work for me.

    private void PrintDoc_AddPages(object sender, AddPagesEventArgs e)
    {     
        rectangleList = GetWebPages(ViewToPrint,  new Windows.Foundation.Size(100d, 150d));
        foreach (Windows.UI.Xaml.Shapes.Rectangle rectangle in rectangleList)
        {
            printDoc.AddPage(rectangle);
        }                                                                                     
        printDoc.AddPagesComplete();
    }

You can find GetWebPages() function here.

    List<Windows.UI.Xaml.Shapes.Rectangle> GetWebPages(Windows.UI.Xaml.Controls.WebView webView, Windows.Foundation.Size page)
    {
        // ask the content its width
        var _WidthString = webView.InvokeScriptAsync("eval",
            new[] { "document.body.scrollWidth.toString()" }).GetResults();
        int _ContentWidth;
        if (!int.TryParse(_WidthString, out _ContentWidth))
            throw new Exception(string.Format("failure/width:{0}", _WidthString));
        webView.Width = _ContentWidth;

        // ask the content its height
        var _HeightString = webView.InvokeScriptAsync("eval",
            new[] { "document.body.scrollHeight.toString()" }).GetResults();
        int _ContentHeight;
        if (!int.TryParse(_HeightString, out _ContentHeight))
            throw new Exception(string.Format("failure/height:{0}", _HeightString));
        webView.Height = _ContentHeight;

        // how many pages will there be?
        var _Scale = page.Width / _ContentWidth;
        var _ScaledHeight = (_ContentHeight * _Scale);
        var _PageCount = (double)_ScaledHeight / page.Height;
        _PageCount = _PageCount + ((_PageCount > (int)_PageCount) ? 1 : 0);

        // create the pages
        var _Pages = new List<Windows.UI.Xaml.Shapes.Rectangle>();
        for (int i = 0; i < (int)_PageCount; i++)
        {
            var _TranslateY = -page.Height * i;
            var _Page = new Windows.UI.Xaml.Shapes.Rectangle
            {
                Height = page.Height,
                Width = page.Width,
                Margin = new Windows.UI.Xaml.Thickness(5),
                Tag = new Windows.UI.Xaml.Media.TranslateTransform { Y = _TranslateY },
            };
            _Page.Loaded += (s, e) =>
            {
                var _Rectangle = s as Windows.UI.Xaml.Shapes.Rectangle;
                var _Brush = GetWebViewBrush(webView);
                _Brush.Stretch = Windows.UI.Xaml.Media.Stretch.UniformToFill;
                _Brush.AlignmentY = Windows.UI.Xaml.Media.AlignmentY.Top;
                _Brush.Transform = _Rectangle.Tag as Windows.UI.Xaml.Media.TranslateTransform;
                _Rectangle.Fill = _Brush;
            };
            _Pages.Add(_Page);
        }
        return _Pages;
    }

    WebViewBrush GetWebViewBrush(Windows.UI.Xaml.Controls.WebView webView)
    {
        // resize width to content
        var _OriginalWidth = webView.Width;
        var _WidthString = webView.InvokeScriptAsync("eval",
            new[] { "document.body.scrollWidth.toString()" }).GetResults();
        int _ContentWidth;
        if (!int.TryParse(_WidthString, out _ContentWidth))
            throw new Exception(string.Format("failure/width:{0}", _WidthString));
        webView.Width = _ContentWidth;

        // resize height to content
        var _OriginalHeight = webView.Height;
        var _HeightString = webView.InvokeScriptAsync("eval",
            new[] { "document.body.scrollHeight.toString()" }).GetResults();
        int _ContentHeight;
        if (!int.TryParse(_HeightString, out _ContentHeight))
            throw new Exception(string.Format("failure/height:{0}", _HeightString));
        webView.Height = _ContentHeight;

        // create brush
        var _OriginalVisibilty = webView.Visibility;
        webView.Visibility = Windows.UI.Xaml.Visibility.Visible;
        var _Brush = new WebViewBrush
        {
            SourceName = webView.Name,
            Stretch = Windows.UI.Xaml.Media.Stretch.Uniform
        };
        _Brush.Redraw();

        // reset, return
        webView.Width = _OriginalWidth;
        webView.Height = _OriginalHeight;
        webView.Visibility = _OriginalVisibilty;
        return _Brush;
    }
1
You just posted a part of your code. It's hard to locate where the issue is. Please provide a minimal reproducible example.Xie Steven
I have edited the question. Hope it describes the problem a bit more clearly.Abhishek Aggarwal

1 Answers

0
votes

@Jerry Nixon's method worked well on my side. Since his code sample was posted on that thread about five years ago. For current UWP APIs, I just done a little changes(e.g, webView.InvokeScriptAsync). I also saw that you call the webView.InvokeScriptAsync method in your code. That's good. But you call the GetResults() method, I did not suggest you call GetResults() method. Because invoking javascript code sometimes will take you a lot of time. You might get the exception A method was called at an unexpected time.

Then, I also noticed that your printing flow is a bit of a mess. Please read Print from your app to learn the standardized printing process.

You could check the official code sample Printing sample for details.

The following was the updated code of your code snippet:

async Task<List<Windows.UI.Xaml.Shapes.Rectangle>> GetWebPages(Windows.UI.Xaml.Controls.WebView webView, Windows.Foundation.Size page)
{
        // ask the content its width
        var _WidthString = await webView.InvokeScriptAsync("eval",
            new[] { "document.body.scrollWidth.toString()" });
        int _ContentWidth;
        if (!int.TryParse(_WidthString, out _ContentWidth))
            throw new Exception(string.Format("failure/width:{0}", _WidthString));
        webView.Width = _ContentWidth;

        // ask the content its height
        var _HeightString = await webView.InvokeScriptAsync("eval",
            new[] { "document.body.scrollHeight.toString()" });
        int _ContentHeight;
        if (!int.TryParse(_HeightString, out _ContentHeight))
            throw new Exception(string.Format("failure/height:{0}", _HeightString));
        webView.Height = _ContentHeight;

        // how many pages will there be?
        var _Scale = page.Width / _ContentWidth;
        var _ScaledHeight = (_ContentHeight * _Scale);
        var _PageCount = (double)_ScaledHeight / page.Height;
        _PageCount = _PageCount + ((_PageCount > (int)_PageCount) ? 1 : 0);

        // create the pages
        var _Pages = new List<Windows.UI.Xaml.Shapes.Rectangle>();
        for (int i = 0; i < (int)_PageCount; i++)
        {
            var _TranslateY = -page.Height * i;
            var _Page = new Windows.UI.Xaml.Shapes.Rectangle
            {
                Height = page.Height,
                Width = page.Width,
                Margin = new Windows.UI.Xaml.Thickness(5),
                Tag = new Windows.UI.Xaml.Media.TranslateTransform { Y = _TranslateY },
            };
            _Page.Loaded +=async (s, e) =>
            {
                var _Rectangle = s as Windows.UI.Xaml.Shapes.Rectangle;
                var _Brush = await GetWebViewBrush(webView);
                _Brush.Stretch = Windows.UI.Xaml.Media.Stretch.UniformToFill;
                _Brush.AlignmentY = Windows.UI.Xaml.Media.AlignmentY.Top;
                _Brush.Transform = _Rectangle.Tag as Windows.UI.Xaml.Media.TranslateTransform;
                _Rectangle.Fill = _Brush;
            };
            _Pages.Add(_Page);
        }
        return _Pages;
}

    async Task<WebViewBrush> GetWebViewBrush(Windows.UI.Xaml.Controls.WebView webView)
    {
        // resize width to content
        var _OriginalWidth = webView.Width;
        var _WidthString = await webView.InvokeScriptAsync("eval",
            new[] { "document.body.scrollWidth.toString()" });
        int _ContentWidth;
        if (!int.TryParse(_WidthString, out _ContentWidth))
            throw new Exception(string.Format("failure/width:{0}", _WidthString));
        webView.Width = _ContentWidth;

        // resize height to content
        var _OriginalHeight = webView.Height;
        var _HeightString = await webView.InvokeScriptAsync("eval",
            new[] { "document.body.scrollHeight.toString()" });
        int _ContentHeight;
        if (!int.TryParse(_HeightString, out _ContentHeight))
            throw new Exception(string.Format("failure/height:{0}", _HeightString));
        webView.Height = _ContentHeight;

        // create brush
        var _OriginalVisibilty = webView.Visibility;
        webView.Visibility = Windows.UI.Xaml.Visibility.Visible;
        var _Brush = new WebViewBrush
        {
            SourceName = webView.Name,
            Stretch = Windows.UI.Xaml.Media.Stretch.Uniform
        };
        _Brush.Redraw();

        // reset, return
        webView.Width = _OriginalWidth;
        webView.Height = _OriginalHeight;
        webView.Visibility = _OriginalVisibilty;
        return _Brush;
    }

I used the Printing sample and put my above updated code in it and do some relevant changes, then I could print all web pages successfully.