【Win 10 应用开发】打印UI元素
Windows App支持将UI界面进行打印的功能,这与浏览器中的打印网页的用途相近,其好处就是“所见即所得”,直接把界面上呈现的内容打印下来,比重新创建打印图像方便得多。
要在通用App中实现打印,主要依靠以下几个类型:
PrintManager:位于Windows.Graphics.Printing命名空间,主要负责显示打印对话框,设置打印源等操作。在使用时,首先调用GetForCurrentView静态方法得到一个PrintManager实例;随后处理它的PrintTaskRequested,当要进行打印时就会发生该事件。
PrintTask:表示一个打印任务。在PrintManager对象的PrintTaskRequested事件处理中创建打印任务。
PrintDocument:这个类比较关键(位于Windows.UI.Xaml.Printing命名空间)。通过它可以将UI元素转换为待打印的文档逻辑。a、处理Paginate事件,以计算打印的分页,计算后可以调用PrintDocument.SetPreviewPageCount方法来设置预览页面的总数。b、处理GetPreviewPage事件,当请求预览单个页面时会发生该事件,在处理过程中,可以调用PrintDocument.SetPreviewPage方法来设置要预览的特定页面。c、当开始打印时,会发生AddPages事件,此时调用PrintDocument.AddPage方法向打印文档逻辑添加页面,当所有要打印的页面都添加完毕后,请调用AddPagesComplete方法通知系统可以提交打印了。
当你刚刚接触打印时,你会觉得它好像很复杂,其实,当你动手做过实验后,你就会发现,其实也没什么。我们作为新时代的开发者,应当有迎难而上的精神。
下面咱们来做个例子,把页面上的一个RichTextBlock控件中的内容打印出来。
页面上的XAML大致如下,老周直接贴出来,不作解释了,我相信你能看懂XAML,如果看不懂,那就算了。
<Border Padding="30" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<StackPanel Margin="0,15" Orientation="Horizontal">
<Button Content="开始打印" Click="OnClick"/>
</StackPanel>
<RichTextBlock Name="tb" Grid.Row="1" Width="300" >
<Paragraph FontSize="36" TextAlignment="Center" FontFamily="楷体">
床前明月光,
<LineBreak/>
疑是地上霜。
<LineBreak/>
舉頭望明月,
<LineBreak/>
低頭思故鄉。
</Paragraph>
<Paragraph TextAlignment="Center">
<InlineUIContainer>
<Image Height="200" Source="http://img155.poco.cn/mypoco/myphoto/20110305/15/20110305154657_366496406.gif"/>
</InlineUIContainer>
</Paragraph>
</RichTextBlock>
……
</Grid>
</Border>
咱们这例子要打印的内容,就是那个名为tb的家伙。
进入页面的代码文件,在页面类中声明以下字段:
PrintManager printmgr = PrintManager.GetForCurrentView();
PrintDocument printDic = null;
RotateTransform rottrf =null;
PrintTask task = null;
RotateTransform变量的作用是把tb进行旋转变换,这是为了处理打印页面的方向,如果页面是横向,我就把tb转90度。
处理PrintManager的PrintTaskRequested事件,创建打印任务,并设置打印源。
printmgr.PrintTaskRequested += Printmgr_PrintTaskRequested;
……
private void Printmgr_PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs args)
{
var def = args.Request.GetDeferral();
// 创建打印任务
task = args.Request.CreatePrintTask("打印测试", OnPrintTaskSourceRequrested);
task.Completed += Task_Completed;
def.Complete();
}
在调用CreatePrintTask方法创建打印任务时,有一个参数需要通过一个委托来设置打印源。所谓打印源,就是我们要打印的文档。
private async void OnPrintTaskSourceRequrested(PrintTaskSourceRequestedArgs args)
{
var def = args.GetDeferral();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
() =>
{
// 设置打印源
args.SetSource(printDic?.DocumentSource);
});
def.Complete();
}
我们这里要打印的其实就是PrintDocument对象,我们变量命名好像错了,叫printDoc合理一些,我打成了printDic。没事,大家知道就OK了。
下面代码处理按钮的单击事件:
private async void OnClick(object sender, RoutedEventArgs e)
{
if (printDic != null)
{
printDic.GetPreviewPage -= OnGetPreviewPage;
printDic.Paginate -= PrintDic_Paginate;
printDic.AddPages -= PrintDic_AddPages;
}
this.printDic = new PrintDocument();
printDic.GetPreviewPage += OnGetPreviewPage;
printDic.Paginate += PrintDic_Paginate;
printDic.AddPages += PrintDic_AddPages; // 显示打印对话框
bool b=await PrintManager.ShowPrintUIAsync();
}
在实例化PrintDocument后,要处理它的几个事件。
先处理AddPages事件,这个事件是在开始执行打印时才会发生,在事件处理中要向打印文档添加页面,每个页面的内容就是我们要打印的UI元素,为了简单,老周只打印一页。
private void PrintDic_AddPages(object sender, AddPagesEventArgs e)
{
// 添加要打印的页
printDic.AddPage(tb);
// 报告添加完成
printDic.AddPagesComplete();
}
处理Paginate事件,这个事件在打开打印对话框时发生,并且如果用户调整了打印对话框中的参数后也会发生(比如修改了页面方向),目的是重新计算页面的预览。
private void PrintDic_Paginate(object sender, PaginateEventArgs e)
{
PrintTaskOptions opt = task.Options;
// 根据页面的方向来调整打印内容的旋转方向
switch (opt.Orientation)
{
case PrintOrientation.Default:
rottrf.Angle = 0d;
break;
case PrintOrientation.Portrait:
rottrf.Angle = 0d;
break;
case PrintOrientation.Landscape:
rottrf.Angle = 90d;
break;
} // 设置预览页面的总页数
printDic.SetPreviewPageCount(, PreviewPageCountType.Final);
}
下面代码添加特定页面的预览。
private void OnGetPreviewPage(object sender, GetPreviewPageEventArgs e)
{
// 设置要预览的页面
printDic.SetPreviewPage(e.PageNumber, this.tb);
}
大家要注意,页面预览和实际打印是两回事,因此SetPreviewPage只是设置要预览的UI元素,而实际打印是要在AddPages事件中通过AddPage方法来添加页面。
当示例完成之时,大家可能又遇到问题了,我没有打印机,怎么办? 没事,老周很穷,也没有打印机,但不要忘记,系统里面有这些功能:

是啊,有它们就行,搜索“设备与打印机”就能找到它们,所以在运行示例后,直接把内容打印为.pdf文档就可以了,打印完后,.pdf文件存到“文档”目录中。
现在运行应用程序,然后点击“开始打印”按钮。

然后会弹出打印对话框。

确认开始打印,点击“打印”按钮。打印完成后系统会以Toast通知来提醒你。下图所示是打印出来的.pdf文件。

好了,是不是有点高大上的感觉呢?
示例代码下载:http://files.cnblogs.com/files/tcjiaan/printSample.zip
【Win 10 应用开发】打印UI元素的更多相关文章
- 【Win 10 应用开发】UI Composition 札记(一):视图框架的实现
在开始今天的内容之前,老周先说一个问题,这个问题记得以前有人提过的. 设置 Windows.ApplicationModel.Core.CoreApplicationView.TitleBar.Ext ...
- 【Win 10 应用开发】UI Composition 札记(三):与 XAML 集成
除了 DirectX 游戏开发,我们一般很少单独使用 UI Composition ,因此,与 XAML 互动并集成是必然结果.这样能够把两者的优势混合使用,让UI布局能够更灵活. 说到与 XAML ...
- 【Win 10 应用开发】UI Composition 札记(二):基本构件
在上一篇中,老周用一个示例,演示了框架视图的创建过程,在本篇中,老周将给大伙伴们说一下 Composition 构建 UI 的一些“零件”. UI Composition 有一个核心类——对,就是 C ...
- 【Win 10 应用开发】UI Composition 札记(五):灯光
UI Composition 除了能够为 UI 元素建立三维空间外,还有相当重要的一个部件——灯光.宇宙万物的精彩缤纷,皆源于光明,光,使我们看到各种东西,除了黑洞之外的世界都是五彩斑谰的.故而,真要 ...
- 【Win 10 应用开发】UI Composition 札记(八):用 XamlLight 制作灯光效果
前面老周已介绍过灯光的使用,如果你忘了,请用九牛二虎之力猛点击这里去复习一下.本篇老周再介绍另一种添加灯光的方法,这种方法是专为 XAML 元素而设计的,可以很方便地为可视化元素添加灯光效果. 不知道 ...
- 【Win 10 应用开发】UI Composition 札记(四):绘制图形
使用 Win 2D 组件,就可以很轻松地绘制各种图形,哪怕你没有 D2D 相关基础,也不必写很复杂的 C++ 代码. 先来说说如何获取 Win 2D 组件.很简单,创建 UWP 应用项目后,你打开“解 ...
- 【Win 10 应用开发】UI Composition 札记(六):动画
动画在 XAML 中也有,而且基本上与 WPF 中的用法一样.不过,在 UWP 中,动画还有一种表现方式—— 通过 UI Composition 来创建. 基于 UI Composition 的动画, ...
- 【Win 10 应用开发】UI Composition 札记(七):基于表达式的动画
上一篇烂文中,老周给大伙伴们介绍过了几个比较好玩的动画.本篇咱们深化主题,说一说基于表达式的动画.这名字好理解,就是你可以用公式 / 等式来产生动画的目标值.比如,你想让某个可视化对象的高度减半,你的 ...
- 【Win 10 应用开发】启动远程设备上的应用
这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...
随机推荐
- React虚拟DOM浅析
在Web开发中,需要将数据的变化实时反映到UI上,这时就需要对DOM进行操作,但是复杂或频繁的DOM操作通常是性能瓶颈产生的原因,为此,React引入了虚拟DOM(Virtual DOM)的机制. 什 ...
- 由overflow-x:scroll产生的收获
我们都知道float:left属性会让元素向左浮动,如果用一个div将几个左浮动的li包起来,是不是div的宽度被li撑得很长很长呢,代码: <!DOCTYPE html> <htm ...
- Linux下Electron的Helloworld
什么是Electron Electron 框架的前身是 Atom Shell,可以让你写使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序.它是基于io.js 和 Chromi ...
- URL的截取问题
$(function (){ if (window.location.href.includes('?')) { if (window.location.href.split('?')[1].spli ...
- Java_类似java.lang.VerifyError: Expecting a stackmap frame at branch target 22 in method的解决方法
报异常的方法内使用了Java 7的新特性:自动资源释放,类似于try(){},即在try后面跟一括号,在括号里面对一些资源赋值,try里面的代码块执行完毕之后会自动释放try后面的括号中声明的资源. ...
- 从问题看本质:socket到底是什么?
一.问题的引入——socket的引入是为了解决不同计算机间进程间通信的问题 1.socket与进程的关系 1).socket与进程间的关系:socket 用来让一个进程和其他的进程互通信息(IPC ...
- ES6的promise对象应该这样用
ES6修补了一位Js修真者诸多的遗憾. 曾几何时,我这个小白从js非阻塞特性的坑中爬出来,当我经历了一些回调丑陋的写法和优化的尝试之后,我深深觉得js对于多线程阻塞式的开发语言而言,可能有着其太明显的 ...
- Xcode 调试技巧
一 NSLog调试 官方文档:Logs an error message to the Apple System Log facility. 即NSLog不是作为普通的debug log的,而是err ...
- perl 遍历对象数组
my $appsList ; eval { $appsList = $db->query( $sqlstr1 )->hashes->to_array; }; ### $appsLis ...
- Lisk沙箱漏洞分析及解决方案
背景 比特股的创始人Daniel Larimer质疑了lisk系统中的一系列问题,绝大多数都被lisk的创始人之一Max正面回应过了,具体可以看看这个http://ethereum.stackexch ...