ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Windows-universal-samples 之 Printing 示例:UWP 应用打印支持完整实战指南

2026/9/25 2:27:17 拓冰建站 浏览量
Windows-universal-samples 之 Printing 示例:UWP 应用打印支持完整实战指南 示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载导读本文以 Windows-universal-samples 仓库中的 Printing 示例 为核心系统讲解 UWP 应用如何接入 Windows 打印体系从注册打印契约、驱动分页与预览到自定义标准打印选项、添加应用专属打印设置、按页码范围打印、打印与文档无关的备用内容照片以及禁用打印预览与按设备能力隐藏打印按钮。读完本文你将掌握基于PrintManager、PrintDocument与 XAMLRichTextBlockOverflow文本流式分页的完整打印实现路径并可直接对照仓库中的 C#/C 双语言源码落地到自己的应用。示例概览六大打印场景Printing 示例演示了 UWP 应用添加打印支持的六种能力分别对应仓库中的六个 Scenario 页面C# 版位于 Samples/Printing/csC 版位于 Samples/Printing/cpp场景文件演示能力场景 1基础打印Scenario1Basic.xaml(.cs/.cpp)通过应用 UX 添加打印支持注册打印契约并调用系统打印 UI场景 2标准选项定制Scenario2StandardOptons.xaml(.cs)/Scenario2StandardOptionsC自定义打印对话框中向用户展示的打印机设置项及其顺序、默认值场景 3自定义选项Scenario3CustomOptions.xaml(.cs/.cpp)使用PrintCustomItemListOptionDetails、PrintCustomToggleOptionDetails添加应用专属打印选项场景 4页码范围Scenario4PageRange.xaml(.cs/.cpp)使用自定义打印模板打印用户指定的页面范围含范围校验与错误提示场景 5打印照片Scenario5Photos.xaml(.cs/.cpp)打印不属于当前文档的备用内容6 张照片含尺寸/缩放/旋转控制场景 6禁用预览Scenario6DisablePreview.xaml(.cs/.cpp)通过PrintTask.IsPreviewEnabled false关闭打印预览原 README 还提到一个 JavaScript 版本的 Printing 示例已归档至 archived 目录说明该 API 曾面向 JS 开放如今示例以 C#/C 为主。系统要求与构建运行系统要求Windows 10 build 14393 及以上版本即支持 UWP 打印 API 的 Windows 10 周年更新及后续版本。构建下载整个 Samples 压缩包后务必解压全部内容示例依赖根目录的 SharedContent 共享依赖用 Visual Studio 打开对应语言子目录下的 .sln 解决方案文件C# 为 Printing.slnC 为 Printing.sln按CtrlShiftB或Build Build Solution编译。运行按F5或Debug Start Debugging调试运行按CtrlF5或Debug Start Without Debugging免调试运行。打印基础注册契约与三大事件所有场景共享同一个 PrintHelper.csC 版对应 PrintHelper.cpp它封装了 UWP 打印的核心流程是理解本示例的钥匙。注册与注销RegisterForPrinting()完成两件事创建PrintDocument并挂接其三大事件以及通过PrintManager.GetForCurrentView()获取当前视图的打印管理器并订阅PrintTaskRequestedpublic virtual void RegisterForPrinting() { printDocument new PrintDocument(); printDocumentSource printDocument.DocumentSource; printDocument.Paginate CreatePrintPreviewPages; printDocument.GetPreviewPage GetPrintPreviewPage; printDocument.AddPages AddPrintPages; PrintManager printMan PrintManager.GetForCurrentView(); printMan.PrintTaskRequested PrintTaskRequested; }对应的UnregisterForPrinting()逐一解除事件订阅并清空承载打印页的隐藏画布PrintCanvas。每个 Scenario 页面在OnNavigatedTo中注册、在OnNavigatedFrom中注销例如 Scenario1Basic.xaml.cs。打印契约的三种事件回调事件职责关键 APIPaginate分页根据打印机页面描述创建全部预览页并上报页数GetPageDescription(0)、SetPreviewPageCountGetPreviewPage按需提供某一页的UIElement用于预览SetPreviewPage(pageNumber, element)AddPages提交最终打印的全部页面AddPage(element)、AddPagesComplete()文本流式分页原理场景 14 采用 XAML 的文本流式分页方案第一页 PageToPrint.xaml 中的RichTextBlockTextContent通过OverflowContentTarget绑定到FirstLinkedContainer再链到ContinuationPageLinkedContainer。当文字超出首页容量时RichTextBlockOverflow.HasOverflowContent为 true代码便通过 ContinuationPage.xaml 生成续页把文本流到下一页lastRTBOOnPage AddOnePrintPreviewPage(null, pageDescription); while (lastRTBOOnPage.HasOverflowContent lastRTBOOnPage.Visibility Visibility.Visible) { lastRTBOOnPage AddOnePrintPreviewPage(lastRTBOOnPage, pageDescription); }分页时通过PrintTaskOptions.GetPageDescription(0)获取打印机纸张尺寸PageSize与可成像区域ImageableRect据此计算打印边距与内容区尺寸double marginWidth Math.Max(printPageDescription.PageSize.Width - printPageDescription.ImageableRect.Width, printPageDescription.PageSize.Width * ApplicationContentMarginLeft * 2); double marginHeight Math.Max(printPageDescription.PageSize.Height - printPageDescription.ImageableRect.Height, printPageDescription.PageSize.Height * ApplicationContentMarginTop * 2);默认边距系数为ApplicationContentMarginLeft 0.075内容占宽 85%、ApplicationContentMarginTop 0.03内容占高 94%若打印机ImageableRect比应用设定的边距更小则以打印机实际可成像区域为准取两者较大值。调用打印 UI 与失败反馈ShowPrintUIAsync()调用PrintManager.ShowPrintUIAsync()并捕获异常通过MainPage.Current.NotifyUser提示。PrintTaskRequested处理器中通过e.Request.CreatePrintTask(C# Printing SDK Sample, sourceRequested sourceRequested.SetSource(printDocumentSource))创建打印任务并提交文档源同时订阅printTask.Completed当args.Completion PrintTaskCompletion.Failed时在 UI 线程上提示Failed to print.。系统要求在PrintTaskRequestedEventArgs.Request.Deadline期限内完成该回调因此示例刻意让该回调只负责创建任务复杂的选项定制推迟到文档源请求阶段。场景 1最简打印入口Scenario1Basic.xaml.cs 是最简实现OnNavigatedTo中先通过PrintManager.IsSupported()检测设备是否支持打印——不支持则隐藏打印按钮InvokePrintingButton.Visibility Visibility.Collapsed并提示用户支持则注册打印。随后创建PageToPrint并调用PreparePrintContent将其加入隐藏的PrintCanvas强制走一遍布局InvalidateMeasure()UpdateLayout()以便链接容器正确分配内容。点击打印按钮后调用printHelper.ShowPrintUIAsync()弹出系统打印对话框。关键点即使设备不支持打印注册事件处理器也无害——Printing-related event handlers will never be called if printing is not supported。这套检测能力 → 隐藏按钮 → 照常注册的模式就是 README 所述Removing the Print button if the device does not support printing场景的实现。场景 2定制标准打印选项Scenario2StandardOptons.xaml.cs 通过派生StandardOptionsPrintHelper覆写PrintTaskRequested利用printTask.Options.DisplayedOptions控制打印对话框中展示的标准选项及其顺序追加顺序即 UI 显示顺序IListstring displayedOptions printTask.Options.DisplayedOptions; displayedOptions.Clear(); displayedOptions.Add(StandardPrintTaskOptions.Copies); displayedOptions.Add(StandardPrintTaskOptions.Orientation); displayedOptions.Add(StandardPrintTaskOptions.MediaSize); displayedOptions.Add(StandardPrintTaskOptions.Collation); displayedOptions.Add(StandardPrintTaskOptions.Duplex); // Preset the default value of the printer option printTask.Options.MediaSize PrintMediaSize.NorthAmericaLegal;这里涉及的StandardPrintTaskOptions常用项包括Copies份数、Orientation方向、MediaSize纸张、Collation逐份打印、Duplex双面、ColorMode颜色、CustomPageRanges自定义页码范围等。代码同时演示了如何预设默认值将默认纸张设为美式 Legal。场景 3添加应用专属打印选项Scenario3CustomOptions.xaml.cs 是自定义选项的完整范例使用命名空间Windows.Graphics.Printing.OptionDetails中的类型三种自定义选项控件列表选项PrintCustomItemListOptionDetailsCreateItemListOption(PageContent, Pictures)创建内容类型下拉Pictures and text / Pictures only / Text only并用AddItem(id, displayName)注册候选项最后把选项 ID 加入DisplayedOptions使其显示。开关选项PrintCustomToggleOptionDetailsCreateToggleOption(Header, Show header)创建布尔开关通过Description属性向用户解释功能含义Display a header on the first pageTrySetValue(showHeader)设置默认值。带图标与描述的列表选项margins.AddItem(WideMargins, Wide, Each margin is 20% of the paper size, await wideMarginsIconTask)——AddItem支持传入图标流IRandomAccessStreamWithContentType与描述文本。三个边距图标资源来自共享目录下的 wideMargins.svg、moderateMargins.svg、narrowMargins.svg。选项变更驱动预览刷新printDetailedOptions.OptionChanged printDetailedOptions_OptionChanged订阅选项变化事件当PageContent、Margins或Header变化时根据新值调整ApplicationContentMarginTop/Left宽 0.2 / 中 0.1 / 窄 0.05、showHeader与内容显示标志并通过printDocument.InvalidatePreview()使预览失效、触发重新分页。代码还展示了动态错误提示选择窄边距时设置marginsOption.WarningText Narrow margins may not be supported by some printers取消时清空。按选项重构打印内容覆写AddOnePrintPreviewPage在首页生成时根据ShowText/ShowImage标志切换网格列宽GridUnitType.Star、隐藏图片或文本、折叠头部从而让仅图片/仅文本/图文混合真正反映到打印版面覆写CreatePrintPreviewPages则先从PrintTaskOptionDetails.Options[PageContent].Value解析出用户选择转换为位标志枚举DisplayContentText1、Images2、TextAndImages3后再调用基类分页。整个PrintTaskRequested使用sourceRequestedArgs.GetDeferral()延迟完成确保在异步加载 SVG 图标流之后再SetSource与deferral.Complete()。场景 4按页码范围打印Scenario4PageRange.xaml.cs 演示自定义打印模板打印指定页范围启用范围选项将StandardPrintTaskOptions.CustomPageRanges加入DisplayedOptions并通过printTask.Options.PageRangeOptions开放三种范围输入能力printTask.Options.PageRangeOptions.AllowCurrentPage true; printTask.Options.PageRangeOptions.AllowAllPages true; printTask.Options.PageRangeOptions.AllowCustomSetOfPages true;范围过滤与边界处理覆写AddPrintPages读取e.PrintTaskOptions.CustomPageRangesIListPrintPageRange空列表 全部页面customPageRanges.Count 0时逐页AddPage。按范围过滤遍历每个PrintPageRange从FirstPageNumber到LastPageNumber逐页添加当前页是自定义页集合的特例系统会把Current page选择转换为包含当前页的CustomPageRanges对开放式区间如6-LastPageNumber取应用上次通过SetPreviewPageCount上报的页数。越界与重复用户输入文档中不存在的页码会被忽略pageRange.FirstPageNumber printPreviewPages.Count检查重复输入同一页如3-4;1;1会按次数重复打印。页码是 1 基而内部列表是 0 基因此取页时用printPreviewPages[i - 1]。范围校验与用户提示ValidatePageRangeOption在每次分页后及选项变化时被调用若所有范围都超出文档页数设置pageRangeOption.ErrorText Those pages are not present in the document若部分页码不存在则设置WarningText One of the ranges contains pages that are not present in the document。示例注释明确说明这类校验并非必需不做校验的应用只需静默忽略不存在的页码即可。场景 5打印备用内容照片Scenario5Photos.xaml.cs 展示如何打印不属于当前文档的内容——6 张照片ms-appx:///Assets/photo{n}.jpg并带来更精细的打印引擎实现。照片尺寸与缩放选项自定义选项photoSizeFull Page / 4×6 / 5×7 / 8×10 英寸与scalingShrink To Fit / Crop默认方向设为横向printTask.Options.Orientation PrintOrientation.Landscape。照片物理尺寸按 96 DPI 换算成像素如 4×6 英寸即4 * 96×6 * 96像素。版面计算与异步生成CreatePrintPreviewPages构造PageDescription页尺寸、边距、可视区、照片显示区、是否裁剪基于打印机ImageableRect计算居中打印区域若照片尺寸超出可视区如在小纸上选 8×10则显示ErrorText Photo doesn’t fit on the selected paper并改用 PreviewUnavailable.xaml 作为预览不可用占位页虚线边框 Preview unavailable 字样同时只上报 1 页预览。若版面参数未变化则跳过重建currentPageDescription.Equals优化。GetPrintPreviewPage与AddPrintPages采用异步按需生成页面由GeneratePageAsync在后台构造——读取位图、按纸张横竖方向旋转BitmapRotation.Clockwise90/270Degrees、按Stretch.None原尺寸或缩放居中排版。代码用一个requestCount请求票据解决异步竞态分页时Interlocked.Increment若异步生成完成前发生了新的分页票据过期则丢弃结果不调用SetPreviewPage。打印任务完成后还会ClearPageCollection并重置尺寸/缩放/版面描述为默认值避免影响下次打印。与文本流式方案的分工场景 14 的PreparePrintContent以首页 文本溢出续页为模型场景 5 不走该路径PhotoSize.SizeFullPage时照片铺满整页因此Scenario5Photos的OnNavigatedTo只注册打印、不调用PreparePrintContent——这正是 PrintHelper.cs 注释Scenario 5 uses a different approach的含义。场景 6禁用打印预览Scenario6DisablePreview.xaml.cs 的关键一行// Choose not to show the preview by setting the property on PrintTask printTask.IsPreviewEnabled false;设置后系统打印对话框不再展示预览。由于预览被禁用Paginate与GetPreviewPage事件不会被触发分页工作整体转移到AddPages事件中完成DisablePreviewPrintHelper.AddPrintPages同步执行与AddOnePrintPreviewPage等价的AddOnePrintPage逻辑同样基于RichTextBlockOverflow.HasOverflowContent循环生成续页收集到printPages列表后逐页AddPage并AddPagesComplete()。设备能力检测与打印按钮兜底六个场景页面统一采用如下能力检测 兜底模板README 所述Removing the Print button if the device does not support printing的具体实现if (PrintManager.IsSupported()) { MainPage.Current.NotifyUser(Print contract registered, use the Print button to print., NotifyType.StatusMessage); } else { InvokePrintingButton.Visibility Visibility.Collapsed; MainPage.Current.NotifyUser(Printing is not supported., NotifyType.ErrorMessage); }即使设备不支持打印也照常注册事件处理器这些处理器永远不会被调用从而保持代码路径统一、避免运行时分支。双语言实现对照示例同时提供 C# 与 Ccppcx两套完整实现文件结构一一对应C# 版在 Samples/Printing/csC 版在 Samples/Printing/cpp。两套代码共享同一组 XAML 视图页面PageToPrint、ContinuationPage、PreviewUnavailable核心PrintHelper类分别以 PrintHelper.cs 与 PrintHelper.cpp 实现API 调用模式完全对齐如PrintManager::GetForCurrentView()、PrintDocument::DocumentSource、Paginate/GetPreviewPage/AddPages事件委托。共享资源边距图标 SVG、示例图片 print_1.png统一放在 Samples/Printing/shared 目录通过项目文件Printing.csproj / Printing.vcxproj链接进两个工程。构建/运行方式与 README 描述一致直接打开各自语言的 .sln 即可。小结把打印能力落地到自己的 UWP 应用从本示例可以提炼出一套可复用的 UWP 打印接入模板注册创建PrintDocument订阅Paginate/GetPreviewPage/AddPages用PrintManager.GetForCurrentView()订阅PrintTaskRequested在导航进入/离开时注册/注销。内容准备将可打印页面加入隐藏的PrintCanvas强制布局长文本用RichTextBlock.OverflowContentTargetRichTextBlockOverflow链式续页利用HasOverflowContent循环生成全部页面。尺寸适配读取GetPageDescription(0)的PageSize与ImageableRect以Math.Max权衡打印机可成像区域与应用边距动态设置纸面与可打印区。选项定制通过DisplayedOptions增删标准选项并排序用CreateItemListOption/CreateToggleOption添加自定义选项订阅OptionChanged配合InvalidatePreview()让设置即时生效。特殊需求页码范围用PageRangeOptions.Allow*开启并校验CustomPageRanges备用内容打印可绕过文本流式方案、按需异步生成页面不需要预览时设置PrintTask.IsPreviewEnabled false不支持打印的设备上隐藏入口按钮。依赖关系方面示例依赖仓库根目录的 SharedContent 共享模板与资源构建前务必确保该目录随仓库一同解压。以上全部代码与资源均可直接在仓库中查阅对应文件作为自己实现打印功能的起点。赞分享示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载相关推荐UWP 应用数据存储实战Windows-universal-samples 之 ApplicationData 示例深度解析UWP 应用数据存储实战Windows universal samples 之 ApplicationData 示例深度解析 导读 本文以 Windows u示例工程Windows-universal-samples 之 Compression 示例UWP 数据压缩与解压实战Windows universal samples 之 Compression 示例UWP 数据压缩与解压实战 导读 本文围绕 Windows univers示例工程Windows-universal-samples 中的 ContactPicker 示例UWP 联系人选择器完整实战指南Windows universal samples 中的 ContactPicker 示例UWP 联系人选择器完整实战指南 本指南围绕 Windows uni示例工程上一篇从零开始使用recaptcha构建安全的Sinatra应用下一篇【亲测免费】 塔可商城新零售电商系统的开源之选创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考