在 Xamarin UWP 中打印具有多个页面的 WebView

Posted

技术标签:

【中文标题】在 Xamarin UWP 中打印具有多个页面的 WebView【英文标题】:Print WebView with multiple pages in Xamarin UWP 【发布时间】:2018-11-01 03:25:06 【问题描述】:

我正在尝试以 xamarin 形式打印网页。我正在使用DependencyService打印webview,我已经在android中成功实现了。

对于 Windows UWP, 我参考了这个链接:https://forums.xamarin.com/discussion/91163/problem-with-printing-webview-in-uwp-phone 这里使用的方法是只打印网页的第一页。

编辑: 我创建了一个接口IPrint,只提供函数的html源代码。

public interface IPrint

    void PrintAsync(string htmlSource);

在 PrintAsync 函数中(在 Windows UWP 项目中),

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

WebView 完全加载后,

    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();
    

要在 PrintDocument 中添加页面,

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

要实现多页打印, 我参考了这个链接:https://***.com/a/17222629/6366591

我将 AddPages 函数更改为以下内容,但它似乎对我不起作用。

    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();
    

您可以在此处找到 GetWebPages() 函数。

    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;
    

【问题讨论】:

您刚刚发布了一部分代码。很难找到问题所在。请提供minimal reproducible example。 我已经编辑了这个问题。希望它能更清楚地描述问题。 【参考方案1】:

@Jerry Nixon 的方法对我来说效果很好。由于他的代码示例大约在五年前发布在该线程上。对于当前的 UWP API,我只是做了一些改动(例如,webView.InvokeScriptAsync)。我还看到您在代码中调用了webView.InvokeScriptAsync 方法。那挺好的。但是你调用GetResults()方法,我不建议你调用GetResults()方法。因为调用 javascript 代码有时会花费你很多时间。您可能会收到异常 A method was called at an unexpected time

然后,我还注意到您的打印流程有点混乱。请阅读Print from your app了解标准化打印流程。

您可以查看官方代码示例Printing sample了解详细信息。

以下是您的代码 sn-p 的更新代码:

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;
    

我使用了Printing sample,并将上面更新的代码放入其中并进行了一些相关更改,然后我可以成功打印所有网页。

【讨论】:

你有那个样品吗?我正在尝试在 Xamarin UWP 中执行此操作,但我生成的文档仅是空白页(虽然是多个)。

以上是关于在 Xamarin UWP 中打印具有多个页面的 WebView的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin.Forms UWP 中的内存泄漏

在 Xamarin UWP 中打印账单

如何在 xamarin 表单 UWP 中使用 AppWindow 打开多个窗口?

UWP:有效负载包含两个或多个具有相同目标路径的文件

入口圆角 - Xamarin 形成 UWP

Xamarin Forms 在 UWP 上是不是存在内存泄漏?