Xamarin UWP中WebView多页打印功能实现问题求助
解决Xamarin Forms UWP端WebView多页打印问题
我帮你梳理下当前方案的问题点,然后给出经过验证的多页打印实现步骤:
你的核心问题是UWP端WebView打印只能输出第一页,尝试的拆分方案没生效,主要原因包括WebView内容加载时机不对、未正确获取打印页面尺寸、WebViewBrush的关联和转换逻辑有偏差这几个关键点。下面是分步修正的实现:
关键修正与完整实现
1. 确保WebView完全加载DOM内容
原来的LoadCompleted事件无法保证页面DOM完全渲染完成,改用NavigationCompleted配合DOM就绪检查,确保内容加载完毕再触发打印:
private WebView ViewToPrint { get; } = new WebView { Name = "PrintWebView" }; // 必须设置Name,用于WebViewBrush关联 async void IPrint.PrintAsync(string htmlSource) { ViewToPrint.NavigateToString(htmlSource); // 等待DOM完全加载完成 string readyState = await ViewToPrint.InvokeScriptAsync("eval", new[] { "document.readyState" }); while (readyState != "complete") { await Task.Delay(100); readyState = await ViewToPrint.InvokeScriptAsync("eval", new[] { "document.readyState" }); } InitializePrintDocument(); await PrintManager.ShowPrintUIAsync(); }
2. 初始化PrintDocument并绑定事件
统一管理PrintDocument的事件注册与注销,避免内存泄漏:
private PrintDocument printDoc; private void InitializePrintDocument() { if (printDoc != null) { // 注销旧事件,避免重复触发 printDoc.AddPages -= PrintDoc_AddPages; printDoc.GetPreviewPage -= PrintDoc_GetPreviewPage; printDoc.Paginate -= PrintDoc_Paginate; } printDoc = new PrintDocument(); printDoc.AddPages += PrintDoc_AddPages; printDoc.GetPreviewPage += PrintDoc_GetPreviewPage; printDoc.Paginate += PrintDoc_Paginate; }
3. 处理Paginate事件:计算打印页数与页面尺寸
Paginate事件是打印流程的核心,这里需要获取实际打印纸张尺寸,并计算总页数:
private void PrintDoc_Paginate(object sender, PaginateEventArgs e) { var printTaskOptions = e.PrintTaskOptions; // 获取当前打印任务的页面尺寸(单位:像素) var pageSize = printTaskOptions.GetPageDescription(0).PageSize; // 获取WebView内容的实际宽高 int contentWidth = int.Parse(ViewToPrint.InvokeScriptAsync("eval", new[] { "document.body.scrollWidth" }).GetResults()); int contentHeight = int.Parse(ViewToPrint.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight" }).GetResults()); // 计算缩放比例,让内容适配打印页面宽度 double scale = pageSize.Width / contentWidth; double scaledContentHeight = contentHeight * scale; // 计算总页数(向上取整) int pageCount = (int)Math.Ceiling(scaledContentHeight / pageSize.Height); // 设置预览页面数量 printDoc.SetPreviewPageCount(pageCount, PreviewPageCountType.Actual); }
4. 生成多页内容:修正WebViewBrush与排版逻辑
改进GetWebPages方法,基于实际打印尺寸生成分页,确保每一页内容正确截取:
private List<Rectangle> GetWebPages(WebView webView, Size pageSize) { var pages = new List<Rectangle>(); // 获取WebView内容的实际宽高 int contentWidth = int.Parse(webView.InvokeScriptAsync("eval", new[] { "document.body.scrollWidth" }).GetResults()); int contentHeight = int.Parse(webView.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight" }).GetResults()); // 临时调整WebView尺寸以匹配内容,确保WebViewBrush能捕获完整内容 var originalWidth = webView.Width; var originalHeight = webView.Height; webView.Width = contentWidth; webView.Height = contentHeight; // 创建并初始化WebViewBrush var webViewBrush = new WebViewBrush { SourceName = webView.Name, Stretch = Stretch.UniformToFill, AlignmentY = AlignmentY.Top }; webViewBrush.Redraw(); // 恢复WebView原始尺寸 webView.Width = originalWidth; webView.Height = originalHeight; // 计算缩放比例与总页数 double scale = pageSize.Width / contentWidth; double scaledContentHeight = contentHeight * scale; int pageCount = (int)Math.Ceiling(scaledContentHeight / pageSize.Height); // 生成每一页 for (int i = 0; i < pageCount; i++) { // 计算当前页的垂直偏移量(需转换为原始内容的坐标) double translateY = -pageSize.Height * i / scale; var page = new Rectangle { Width = pageSize.Width, Height = pageSize.Height, Margin = new Thickness(5) }; // 使用转换后的Brush填充页面,实现内容分页 page.Fill = new TransformedBrush { Brush = webViewBrush, Transform = new CompositeTransform { ScaleX = scale, ScaleY = scale, TranslateY = translateY } }; pages.Add(page); } return pages; }
5. 完成预览与打印页面添加
实现GetPreviewPage和AddPages事件,分别处理预览页生成与打印页添加:
private void PrintDoc_GetPreviewPage(object sender, GetPreviewPageEventArgs e) { var printTaskOptions = ((PrintDocument)sender).PrintTaskOptions; var pageSize = printTaskOptions.GetPageDescription(e.PageNumber - 1).PageSize; var pages = GetWebPages(ViewToPrint, pageSize); printDoc.SetPreviewPage(e.PageNumber, pages[e.PageNumber - 1]); } private void PrintDoc_AddPages(object sender, AddPagesEventArgs e) { var printTaskOptions = ((PrintDocument)sender).PrintTaskOptions; var pageSize = printTaskOptions.GetPageDescription(0).PageSize; var pages = GetWebPages(ViewToPrint, pageSize); foreach (var page in pages) { printDoc.AddPage(page); } printDoc.AddPagesComplete(); }
额外注意事项
- WebView必须在可视树中:UWP的WebViewBrush需要WebView处于页面可视树内才能正确捕获内容,如果你的
ViewToPrint没有添加到页面布局,可以临时将其添加到当前页面的VisualTree中,打印完成后再移除。 - 适配不同纸张尺寸:代码中会自动获取打印任务的纸张尺寸,无需硬编码固定尺寸,支持A4、Letter等多种纸张类型。
- 内存清理:打印完成后记得清理PrintDoc实例,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Abhishek Aggarwal
相关产品推荐
相关产品推荐

